Skip to content
Isaac Shelton edited this page Sep 8, 2023 · 8 revisions

Functions

Functions are blocks of code that take zero or more parameters and optionally return a value.

Declaration

There are multiple syntaxes for declaring functions, each varying in style preferences and specificity.

All function declarations are a combination of the following:

  • func keyword
  • function name
  • parameters (sometimes omitted)
  • return type (sometimes omitted)
  • block or expression

You can declare a function using any of the following syntax styles.

Standard Syntax

func myFunction {}
func myFunction ReturnType {}
func myFunction(arg_name ArgType, arg_name ArgType) {}
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType {}
func myFunction ReturnType = return_value
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 1

myFunction :: func {}
myFunction :: func ReturnType {}
myFunction :: func (arg_name ArgType, arg_name ArgType) {}
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType {}
myFunction :: func ReturnType = return_value
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 2

myFunction :: func {}
myFunction :: func : ReturnType {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType {}
myFunction :: func : ReturnType = return_value
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType = return_value

Parameters

Function parameters are always given as a list of argument names and argument types all surrounded by parentheses. When there are zero parameters, the parameter list can be omitted, or an empty parameter list () can be used.

Examples (Standard Syntax)
(name String)
(name String, age int)
(firstname, lastname String)
Examples (Alternative Syntax)
(name: String)
(name: String, age: int)
(firstname, lastname: String)

Compound Parameters

If multiple parameters in a row have the same argument type, then the shared argument type doesn't have to be specified multiple times.

For example

func setPosition(x float, y float, z float) void { /* ... */ }

can be abbreviated as

func setPosition(x, y, z float) void { /* ... */ }

or even

func setPosition(x, y, z float) { /* ... */ }

Default Values

Default values can be specified for each argument, and if the argument is missing when the function is called, then it will automatically be filled in with the default value.

func sum(a double = 0.0, b double = 0.0, c double = 0.0) double {
return a + b + c
}

Default values can be specified per argument or argument group, depending on syntax.

For example, the following applies to all a, b, and c

func sumB(a, b, c double = 0.0) double {
return a + b + c
}

But default values can also be specified per argument when using a shared argument type:

func sumC(a = 1.0, b = 2.0, c double = 3.0) double {
return a + b + c
}

Default argument values are evaluated in the context of the callee, and are unique to each call.

import basics
func getDefaultName() String {
print("Getting default name...")
return "Isaac"
}
func welcome(name String = getDefaultName()){
print("Welcome " + name)
}
func main {
welcome()
welcome()
}
Getting default name...
Welcome Isaac
Getting default name...
Welcome Isaac

POD Parameters

Arguments that are marked as POD (plain-old-data), are immune to __pass__ and __defer__ management procedures.

C-style Variadic Arguments

C-style variadic arguments can be used for a function, using ...

func myCStylePrintf(format *ubyte, ...) int { /* ... */ }

C-style variadic arguments do not support structure types, or other composite types. Unless compatibility with C is desired, it is recommended to use Adept-style variadic arguments instead.

Adept-style Variadic Arguments

Adept-style variadic arguments can be used for a function, using ... followed by a variable name to hold the variadic argument array.

import VariadicArray
func myPrintf(format String, ... arguments) int { /* ... */ }

For most cases, the type of the variadic argument list received, will be the standard library type VariadicArray.

Parameter Data-Flow Annotations

The keywords in, out, and inout can be used to help document the data flow of a function.

func sum(in a, b int, out result *int) {
*result = a + b
}

They only exist to help the programmer, and do NOT actually enforce data flows.

See data flow annotations for more information.

Return Type

The return type is specified after the parameter list. If there isn't any return type, then it can be omitted, or void can be used in its place.

Additionally, the return type of a function can be prefixed with the exhaustive keyword to make the return value no-discard. Return values that are no-discard cannot be ignored when calling the function. Forgetting to use the return value of a no-discard function is a compile-time error.

func getName() exhaustive String = "Not using this return value is a compile-time error"

Modifiers

The stdcall modifier can be used to tell the compiler that a function should use the stdcall calling convention.

stdcall func test(a int, b float) long {
/* ... */
}

The verbatim modifier can be used to disable auto-generation of certain management procedures. Generally it's used on __pass__ and __defer__ management definitions.

verbatim func __defer__(this *MyStruct) {
// 'verbatim' tells the compiler to not automatically call '__defer__' on children of 'this'
}
verbatim func __pass__(my_struct_value POD MyStruct) MyStruct {
// 'verbatim' tells the compiler to not automatically call '__pass__' on children of 'my_struct_value'
}

The implicit modifier can be used to promote the __as__ management procedure so the compiler will preform implicit conversions using it.

implicit func __as__(my_number MyNumber) double {
// 'implicit' makes it so that values of type 'MyNumber' can be converted to 'double' without explicitly using 'cast' or 'as'
}

Intrinsic Procedures

Some functions and methods have special intrinsic purposes.

See intrinsic procedures for more information

Foreign Functions

Functions defined in other programming languages can be declared using the foreign keyword.

foreign printf(*ubyte, ...) int

See foreign functions for more information.

Externally Visible Functions

Functions can be made externally visible by using the external keyword

external func sum(a, b int) int {
return a + b
}

See externally visible functions for more information.

Single Line Functions

When a function only performs a simple operation to return a value, it can be abbreviated by substituting the code block with an = sign followed by an expression that represents the return value

For example

func sum(a, b int) int {
return a + b
}

can be abbreviated as

func sum(a, b int) int = a + b

Polymorphic Functions

Polymorphic functions are functions that can operate on multiple types.

They are declared like normal functions, expect they use polymorphic types within their arguments and/or return type.

func difference(a, b $T) $T {
return a - b }

Function Aliases

Function aliases can be used to have multiple names refer to the same function definition

func alias println(String) => print

See function aliases for more information.

Multiple Possibilities

When multiple possible functions exist with the same name, then the rules for function resolution will be applied to determine which one is used.

See function calls for more information.

Virtual methods

Virtual methods are methods which are dispatched at runtime. They can be defined on classes. See classes for more information.

import basics
class Shape () {
constructor {}
virtual func getArea() float = 0.0
}
class Rectangle extends Shape (w, h float) {
constructor(w, h float){
this.w = w
this.h = h
}
override func getArea() float = this.w * this.h
}
func main {
shape *Shape = new Rectangle(5.0f, 10.0f)
defer delete shape
print(shape.getArea())
}

Disallowed functions

Functions may be marked with = delete after their return type to disallow using them.

func youCannotCallThisFunction(a, b int) int = delete
func youCannotCallThisFunctionAlso(a, b int) = delete
func youCannotCallThisFunctionEither(a, b int) int = delete { return a + b }

Trying to call a disallowed function is a compile-time error.

Disallowing functions is most useful for disabling assignment of certain types. For example,

func __assign__(this *UnassignableType, _other POD UnassignableType) = delete

Trying to assign a type regularly that has __assign__ disallowed is a compile-time error.

Constructors

Constructors can be created using the constructor keyword inside of composite types such as a classes or structs.

struct Rectangle (w, h float) {
constructor(w, h float) {
this.w = w
this.h = h
}
constructor(size float) {
this.__constructor__(size, size)
}
}
func main {
rectangle1 Rectangle(100, 50)
rectangle2 Rectangle = Rectangle(75, 50)
rectangle3 Rectangle
rectangle3.__constructor__(500)
rectangle4 *Rectangle = new Rectangle(640, 480)
defer delete rectangle4
}

Constructors automatically generate a function that has the same name as the target type, and which returns a constructed instance of that type.

Constructors also come with a companion __constructor__ method, which can be used to call a constructor on any value

Constructors can use the immediate construction syntax:

rectangle Rectangle(100, 50)
square *Rectangle = new Rectangle(400, 400)
defer {
square.__defer__()
delete square
}

Zero-initialization is still the default, constructors don't apply to naked definitions, e.g. my_value MyType is zero-initialized and not constructed.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Functions · AdeptLanguage/Adept Wiki · GitHub
Skip to content
Isaac Shelton edited this page Sep 8, 2023 · 8 revisions

Functions

Functions are blocks of code that take zero or more parameters and optionally return a value.

Declaration

There are multiple syntaxes for declaring functions, each varying in style preferences and specificity.

All function declarations are a combination of the following:

  • func keyword
  • function name
  • parameters (sometimes omitted)
  • return type (sometimes omitted)
  • block or expression

You can declare a function using any of the following syntax styles.

Standard Syntax

func myFunction {}
func myFunction ReturnType {}
func myFunction(arg_name ArgType, arg_name ArgType) {}
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType {}
func myFunction ReturnType = return_value
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 1

myFunction :: func {}
myFunction :: func ReturnType {}
myFunction :: func (arg_name ArgType, arg_name ArgType) {}
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType {}
myFunction :: func ReturnType = return_value
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 2

myFunction :: func {}
myFunction :: func : ReturnType {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType {}
myFunction :: func : ReturnType = return_value
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType = return_value

Parameters

Function parameters are always given as a list of argument names and argument types all surrounded by parentheses. When there are zero parameters, the parameter list can be omitted, or an empty parameter list () can be used.

Examples (Standard Syntax)
(name String)
(name String, age int)
(firstname, lastname String)
Examples (Alternative Syntax)
(name: String)
(name: String, age: int)
(firstname, lastname: String)

Compound Parameters

If multiple parameters in a row have the same argument type, then the shared argument type doesn't have to be specified multiple times.

For example

func setPosition(x float, y float, z float) void { /* ... */ }

can be abbreviated as

func setPosition(x, y, z float) void { /* ... */ }

or even

func setPosition(x, y, z float) { /* ... */ }

Default Values

Default values can be specified for each argument, and if the argument is missing when the function is called, then it will automatically be filled in with the default value.

func sum(a double = 0.0, b double = 0.0, c double = 0.0) double {
return a + b + c
}

Default values can be specified per argument or argument group, depending on syntax.

For example, the following applies to all a, b, and c

func sumB(a, b, c double = 0.0) double {
return a + b + c
}

But default values can also be specified per argument when using a shared argument type:

func sumC(a = 1.0, b = 2.0, c double = 3.0) double {
return a + b + c
}

Default argument values are evaluated in the context of the callee, and are unique to each call.

import basics
func getDefaultName() String {
print("Getting default name...")
return "Isaac"
}
func welcome(name String = getDefaultName()){
print("Welcome " + name)
}
func main {
welcome()
welcome()
}
Getting default name...
Welcome Isaac
Getting default name...
Welcome Isaac

POD Parameters

Arguments that are marked as POD (plain-old-data), are immune to __pass__ and __defer__ management procedures.

C-style Variadic Arguments

C-style variadic arguments can be used for a function, using ...

func myCStylePrintf(format *ubyte, ...) int { /* ... */ }

C-style variadic arguments do not support structure types, or other composite types. Unless compatibility with C is desired, it is recommended to use Adept-style variadic arguments instead.

Adept-style Variadic Arguments

Adept-style variadic arguments can be used for a function, using ... followed by a variable name to hold the variadic argument array.

import VariadicArray
func myPrintf(format String, ... arguments) int { /* ... */ }

For most cases, the type of the variadic argument list received, will be the standard library type VariadicArray.

Parameter Data-Flow Annotations

The keywords in, out, and inout can be used to help document the data flow of a function.

func sum(in a, b int, out result *int) {
*result = a + b
}

They only exist to help the programmer, and do NOT actually enforce data flows.

See data flow annotations for more information.

Return Type

The return type is specified after the parameter list. If there isn't any return type, then it can be omitted, or void can be used in its place.

Additionally, the return type of a function can be prefixed with the exhaustive keyword to make the return value no-discard. Return values that are no-discard cannot be ignored when calling the function. Forgetting to use the return value of a no-discard function is a compile-time error.

func getName() exhaustive String = "Not using this return value is a compile-time error"

Modifiers

The stdcall modifier can be used to tell the compiler that a function should use the stdcall calling convention.

stdcall func test(a int, b float) long {
/* ... */
}

The verbatim modifier can be used to disable auto-generation of certain management procedures. Generally it's used on __pass__ and __defer__ management definitions.

verbatim func __defer__(this *MyStruct) {
// 'verbatim' tells the compiler to not automatically call '__defer__' on children of 'this'
}
verbatim func __pass__(my_struct_value POD MyStruct) MyStruct {
// 'verbatim' tells the compiler to not automatically call '__pass__' on children of 'my_struct_value'
}

The implicit modifier can be used to promote the __as__ management procedure so the compiler will preform implicit conversions using it.

implicit func __as__(my_number MyNumber) double {
// 'implicit' makes it so that values of type 'MyNumber' can be converted to 'double' without explicitly using 'cast' or 'as'
}

Intrinsic Procedures

Some functions and methods have special intrinsic purposes.

See intrinsic procedures for more information

Foreign Functions

Functions defined in other programming languages can be declared using the foreign keyword.

foreign printf(*ubyte, ...) int

See foreign functions for more information.

Externally Visible Functions

Functions can be made externally visible by using the external keyword

external func sum(a, b int) int {
return a + b
}

See externally visible functions for more information.

Single Line Functions

When a function only performs a simple operation to return a value, it can be abbreviated by substituting the code block with an = sign followed by an expression that represents the return value

For example

func sum(a, b int) int {
return a + b
}

can be abbreviated as

func sum(a, b int) int = a + b

Polymorphic Functions

Polymorphic functions are functions that can operate on multiple types.

They are declared like normal functions, expect they use polymorphic types within their arguments and/or return type.

func difference(a, b $T) $T {
return a - b }

Function Aliases

Function aliases can be used to have multiple names refer to the same function definition

func alias println(String) => print

See function aliases for more information.

Multiple Possibilities

When multiple possible functions exist with the same name, then the rules for function resolution will be applied to determine which one is used.

See function calls for more information.

Virtual methods

Virtual methods are methods which are dispatched at runtime. They can be defined on classes. See classes for more information.

import basics
class Shape () {
constructor {}
virtual func getArea() float = 0.0
}
class Rectangle extends Shape (w, h float) {
constructor(w, h float){
this.w = w
this.h = h
}
override func getArea() float = this.w * this.h
}
func main {
shape *Shape = new Rectangle(5.0f, 10.0f)
defer delete shape
print(shape.getArea())
}

Disallowed functions

Functions may be marked with = delete after their return type to disallow using them.

func youCannotCallThisFunction(a, b int) int = delete
func youCannotCallThisFunctionAlso(a, b int) = delete
func youCannotCallThisFunctionEither(a, b int) int = delete { return a + b }

Trying to call a disallowed function is a compile-time error.

Disallowing functions is most useful for disabling assignment of certain types. For example,

func __assign__(this *UnassignableType, _other POD UnassignableType) = delete

Trying to assign a type regularly that has __assign__ disallowed is a compile-time error.

Constructors

Constructors can be created using the constructor keyword inside of composite types such as a classes or structs.

struct Rectangle (w, h float) {
constructor(w, h float) {
this.w = w
this.h = h
}
constructor(size float) {
this.__constructor__(size, size)
}
}
func main {
rectangle1 Rectangle(100, 50)
rectangle2 Rectangle = Rectangle(75, 50)
rectangle3 Rectangle
rectangle3.__constructor__(500)
rectangle4 *Rectangle = new Rectangle(640, 480)
defer delete rectangle4
}

Constructors automatically generate a function that has the same name as the target type, and which returns a constructed instance of that type.

Constructors also come with a companion __constructor__ method, which can be used to call a constructor on any value

Constructors can use the immediate construction syntax:

rectangle Rectangle(100, 50)
square *Rectangle = new Rectangle(400, 400)
defer {
square.__defer__()
delete square
}

Zero-initialization is still the default, constructors don't apply to naked definitions, e.g. my_value MyType is zero-initialized and not constructed.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Functions · AdeptLanguage/Adept Wiki · GitHub
Skip to content
Isaac Shelton edited this page Sep 8, 2023 · 8 revisions

Functions

Functions are blocks of code that take zero or more parameters and optionally return a value.

Declaration

There are multiple syntaxes for declaring functions, each varying in style preferences and specificity.

All function declarations are a combination of the following:

  • func keyword
  • function name
  • parameters (sometimes omitted)
  • return type (sometimes omitted)
  • block or expression

You can declare a function using any of the following syntax styles.

Standard Syntax

func myFunction {}
func myFunction ReturnType {}
func myFunction(arg_name ArgType, arg_name ArgType) {}
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType {}
func myFunction ReturnType = return_value
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 1

myFunction :: func {}
myFunction :: func ReturnType {}
myFunction :: func (arg_name ArgType, arg_name ArgType) {}
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType {}
myFunction :: func ReturnType = return_value
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 2

myFunction :: func {}
myFunction :: func : ReturnType {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType {}
myFunction :: func : ReturnType = return_value
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType = return_value

Parameters

Function parameters are always given as a list of argument names and argument types all surrounded by parentheses. When there are zero parameters, the parameter list can be omitted, or an empty parameter list () can be used.

Examples (Standard Syntax)
(name String)
(name String, age int)
(firstname, lastname String)
Examples (Alternative Syntax)
(name: String)
(name: String, age: int)
(firstname, lastname: String)

Compound Parameters

If multiple parameters in a row have the same argument type, then the shared argument type doesn't have to be specified multiple times.

For example

func setPosition(x float, y float, z float) void { /* ... */ }

can be abbreviated as

func setPosition(x, y, z float) void { /* ... */ }

or even

func setPosition(x, y, z float) { /* ... */ }

Default Values

Default values can be specified for each argument, and if the argument is missing when the function is called, then it will automatically be filled in with the default value.

func sum(a double = 0.0, b double = 0.0, c double = 0.0) double {
return a + b + c
}

Default values can be specified per argument or argument group, depending on syntax.

For example, the following applies to all a, b, and c

func sumB(a, b, c double = 0.0) double {
return a + b + c
}

But default values can also be specified per argument when using a shared argument type:

func sumC(a = 1.0, b = 2.0, c double = 3.0) double {
return a + b + c
}

Default argument values are evaluated in the context of the callee, and are unique to each call.

import basics
func getDefaultName() String {
print("Getting default name...")
return "Isaac"
}
func welcome(name String = getDefaultName()){
print("Welcome " + name)
}
func main {
welcome()
welcome()
}
Getting default name...
Welcome Isaac
Getting default name...
Welcome Isaac

POD Parameters

Arguments that are marked as POD (plain-old-data), are immune to __pass__ and __defer__ management procedures.

C-style Variadic Arguments

C-style variadic arguments can be used for a function, using ...

func myCStylePrintf(format *ubyte, ...) int { /* ... */ }

C-style variadic arguments do not support structure types, or other composite types. Unless compatibility with C is desired, it is recommended to use Adept-style variadic arguments instead.

Adept-style Variadic Arguments

Adept-style variadic arguments can be used for a function, using ... followed by a variable name to hold the variadic argument array.

import VariadicArray
func myPrintf(format String, ... arguments) int { /* ... */ }

For most cases, the type of the variadic argument list received, will be the standard library type VariadicArray.

Parameter Data-Flow Annotations

The keywords in, out, and inout can be used to help document the data flow of a function.

func sum(in a, b int, out result *int) {
*result = a + b
}

They only exist to help the programmer, and do NOT actually enforce data flows.

See data flow annotations for more information.

Return Type

The return type is specified after the parameter list. If there isn't any return type, then it can be omitted, or void can be used in its place.

Additionally, the return type of a function can be prefixed with the exhaustive keyword to make the return value no-discard. Return values that are no-discard cannot be ignored when calling the function. Forgetting to use the return value of a no-discard function is a compile-time error.

func getName() exhaustive String = "Not using this return value is a compile-time error"

Modifiers

The stdcall modifier can be used to tell the compiler that a function should use the stdcall calling convention.

stdcall func test(a int, b float) long {
/* ... */
}

The verbatim modifier can be used to disable auto-generation of certain management procedures. Generally it's used on __pass__ and __defer__ management definitions.

verbatim func __defer__(this *MyStruct) {
// 'verbatim' tells the compiler to not automatically call '__defer__' on children of 'this'
}
verbatim func __pass__(my_struct_value POD MyStruct) MyStruct {
// 'verbatim' tells the compiler to not automatically call '__pass__' on children of 'my_struct_value'
}

The implicit modifier can be used to promote the __as__ management procedure so the compiler will preform implicit conversions using it.

implicit func __as__(my_number MyNumber) double {
// 'implicit' makes it so that values of type 'MyNumber' can be converted to 'double' without explicitly using 'cast' or 'as'
}

Intrinsic Procedures

Some functions and methods have special intrinsic purposes.

See intrinsic procedures for more information

Foreign Functions

Functions defined in other programming languages can be declared using the foreign keyword.

foreign printf(*ubyte, ...) int

See foreign functions for more information.

Externally Visible Functions

Functions can be made externally visible by using the external keyword

external func sum(a, b int) int {
return a + b
}

See externally visible functions for more information.

Single Line Functions

When a function only performs a simple operation to return a value, it can be abbreviated by substituting the code block with an = sign followed by an expression that represents the return value

For example

func sum(a, b int) int {
return a + b
}

can be abbreviated as

func sum(a, b int) int = a + b

Polymorphic Functions

Polymorphic functions are functions that can operate on multiple types.

They are declared like normal functions, expect they use polymorphic types within their arguments and/or return type.

func difference(a, b $T) $T {
return a - b }

Function Aliases

Function aliases can be used to have multiple names refer to the same function definition

func alias println(String) => print

See function aliases for more information.

Multiple Possibilities

When multiple possible functions exist with the same name, then the rules for function resolution will be applied to determine which one is used.

See function calls for more information.

Virtual methods

Virtual methods are methods which are dispatched at runtime. They can be defined on classes. See classes for more information.

import basics
class Shape () {
constructor {}
virtual func getArea() float = 0.0
}
class Rectangle extends Shape (w, h float) {
constructor(w, h float){
this.w = w
this.h = h
}
override func getArea() float = this.w * this.h
}
func main {
shape *Shape = new Rectangle(5.0f, 10.0f)
defer delete shape
print(shape.getArea())
}

Disallowed functions

Functions may be marked with = delete after their return type to disallow using them.

func youCannotCallThisFunction(a, b int) int = delete
func youCannotCallThisFunctionAlso(a, b int) = delete
func youCannotCallThisFunctionEither(a, b int) int = delete { return a + b }

Trying to call a disallowed function is a compile-time error.

Disallowing functions is most useful for disabling assignment of certain types. For example,

func __assign__(this *UnassignableType, _other POD UnassignableType) = delete

Trying to assign a type regularly that has __assign__ disallowed is a compile-time error.

Constructors

Constructors can be created using the constructor keyword inside of composite types such as a classes or structs.

struct Rectangle (w, h float) {
constructor(w, h float) {
this.w = w
this.h = h
}
constructor(size float) {
this.__constructor__(size, size)
}
}
func main {
rectangle1 Rectangle(100, 50)
rectangle2 Rectangle = Rectangle(75, 50)
rectangle3 Rectangle
rectangle3.__constructor__(500)
rectangle4 *Rectangle = new Rectangle(640, 480)
defer delete rectangle4
}

Constructors automatically generate a function that has the same name as the target type, and which returns a constructed instance of that type.

Constructors also come with a companion __constructor__ method, which can be used to call a constructor on any value

Constructors can use the immediate construction syntax:

rectangle Rectangle(100, 50)
square *Rectangle = new Rectangle(400, 400)
defer {
square.__defer__()
delete square
}

Zero-initialization is still the default, constructors don't apply to naked definitions, e.g. my_value MyType is zero-initialized and not constructed.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Functions · AdeptLanguage/Adept Wiki · GitHub
Skip to content
Isaac Shelton edited this page Sep 8, 2023 · 8 revisions

Functions

Functions are blocks of code that take zero or more parameters and optionally return a value.

Declaration

There are multiple syntaxes for declaring functions, each varying in style preferences and specificity.

All function declarations are a combination of the following:

  • func keyword
  • function name
  • parameters (sometimes omitted)
  • return type (sometimes omitted)
  • block or expression

You can declare a function using any of the following syntax styles.

Standard Syntax

func myFunction {}
func myFunction ReturnType {}
func myFunction(arg_name ArgType, arg_name ArgType) {}
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType {}
func myFunction ReturnType = return_value
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 1

myFunction :: func {}
myFunction :: func ReturnType {}
myFunction :: func (arg_name ArgType, arg_name ArgType) {}
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType {}
myFunction :: func ReturnType = return_value
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 2

myFunction :: func {}
myFunction :: func : ReturnType {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType {}
myFunction :: func : ReturnType = return_value
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType = return_value

Parameters

Function parameters are always given as a list of argument names and argument types all surrounded by parentheses. When there are zero parameters, the parameter list can be omitted, or an empty parameter list () can be used.

Examples (Standard Syntax)
(name String)
(name String, age int)
(firstname, lastname String)
Examples (Alternative Syntax)
(name: String)
(name: String, age: int)
(firstname, lastname: String)

Compound Parameters

If multiple parameters in a row have the same argument type, then the shared argument type doesn't have to be specified multiple times.

For example

func setPosition(x float, y float, z float) void { /* ... */ }

can be abbreviated as

func setPosition(x, y, z float) void { /* ... */ }

or even

func setPosition(x, y, z float) { /* ... */ }

Default Values

Default values can be specified for each argument, and if the argument is missing when the function is called, then it will automatically be filled in with the default value.

func sum(a double = 0.0, b double = 0.0, c double = 0.0) double {
return a + b + c
}

Default values can be specified per argument or argument group, depending on syntax.

For example, the following applies to all a, b, and c

func sumB(a, b, c double = 0.0) double {
return a + b + c
}

But default values can also be specified per argument when using a shared argument type:

func sumC(a = 1.0, b = 2.0, c double = 3.0) double {
return a + b + c
}

Default argument values are evaluated in the context of the callee, and are unique to each call.

import basics
func getDefaultName() String {
print("Getting default name...")
return "Isaac"
}
func welcome(name String = getDefaultName()){
print("Welcome " + name)
}
func main {
welcome()
welcome()
}
Getting default name...
Welcome Isaac
Getting default name...
Welcome Isaac

POD Parameters

Arguments that are marked as POD (plain-old-data), are immune to __pass__ and __defer__ management procedures.

C-style Variadic Arguments

C-style variadic arguments can be used for a function, using ...

func myCStylePrintf(format *ubyte, ...) int { /* ... */ }

C-style variadic arguments do not support structure types, or other composite types. Unless compatibility with C is desired, it is recommended to use Adept-style variadic arguments instead.

Adept-style Variadic Arguments

Adept-style variadic arguments can be used for a function, using ... followed by a variable name to hold the variadic argument array.

import VariadicArray
func myPrintf(format String, ... arguments) int { /* ... */ }

For most cases, the type of the variadic argument list received, will be the standard library type VariadicArray.

Parameter Data-Flow Annotations

The keywords in, out, and inout can be used to help document the data flow of a function.

func sum(in a, b int, out result *int) {
*result = a + b
}

They only exist to help the programmer, and do NOT actually enforce data flows.

See data flow annotations for more information.

Return Type

The return type is specified after the parameter list. If there isn't any return type, then it can be omitted, or void can be used in its place.

Additionally, the return type of a function can be prefixed with the exhaustive keyword to make the return value no-discard. Return values that are no-discard cannot be ignored when calling the function. Forgetting to use the return value of a no-discard function is a compile-time error.

func getName() exhaustive String = "Not using this return value is a compile-time error"

Modifiers

The stdcall modifier can be used to tell the compiler that a function should use the stdcall calling convention.

stdcall func test(a int, b float) long {
/* ... */
}

The verbatim modifier can be used to disable auto-generation of certain management procedures. Generally it's used on __pass__ and __defer__ management definitions.

verbatim func __defer__(this *MyStruct) {
// 'verbatim' tells the compiler to not automatically call '__defer__' on children of 'this'
}
verbatim func __pass__(my_struct_value POD MyStruct) MyStruct {
// 'verbatim' tells the compiler to not automatically call '__pass__' on children of 'my_struct_value'
}

The implicit modifier can be used to promote the __as__ management procedure so the compiler will preform implicit conversions using it.

implicit func __as__(my_number MyNumber) double {
// 'implicit' makes it so that values of type 'MyNumber' can be converted to 'double' without explicitly using 'cast' or 'as'
}

Intrinsic Procedures

Some functions and methods have special intrinsic purposes.

See intrinsic procedures for more information

Foreign Functions

Functions defined in other programming languages can be declared using the foreign keyword.

foreign printf(*ubyte, ...) int

See foreign functions for more information.

Externally Visible Functions

Functions can be made externally visible by using the external keyword

external func sum(a, b int) int {
return a + b
}

See externally visible functions for more information.

Single Line Functions

When a function only performs a simple operation to return a value, it can be abbreviated by substituting the code block with an = sign followed by an expression that represents the return value

For example

func sum(a, b int) int {
return a + b
}

can be abbreviated as

func sum(a, b int) int = a + b

Polymorphic Functions

Polymorphic functions are functions that can operate on multiple types.

They are declared like normal functions, expect they use polymorphic types within their arguments and/or return type.

func difference(a, b $T) $T {
return a - b }

Function Aliases

Function aliases can be used to have multiple names refer to the same function definition

func alias println(String) => print

See function aliases for more information.

Multiple Possibilities

When multiple possible functions exist with the same name, then the rules for function resolution will be applied to determine which one is used.

See function calls for more information.

Virtual methods

Virtual methods are methods which are dispatched at runtime. They can be defined on classes. See classes for more information.

import basics
class Shape () {
constructor {}
virtual func getArea() float = 0.0
}
class Rectangle extends Shape (w, h float) {
constructor(w, h float){
this.w = w
this.h = h
}
override func getArea() float = this.w * this.h
}
func main {
shape *Shape = new Rectangle(5.0f, 10.0f)
defer delete shape
print(shape.getArea())
}

Disallowed functions

Functions may be marked with = delete after their return type to disallow using them.

func youCannotCallThisFunction(a, b int) int = delete
func youCannotCallThisFunctionAlso(a, b int) = delete
func youCannotCallThisFunctionEither(a, b int) int = delete { return a + b }

Trying to call a disallowed function is a compile-time error.

Disallowing functions is most useful for disabling assignment of certain types. For example,

func __assign__(this *UnassignableType, _other POD UnassignableType) = delete

Trying to assign a type regularly that has __assign__ disallowed is a compile-time error.

Constructors

Constructors can be created using the constructor keyword inside of composite types such as a classes or structs.

struct Rectangle (w, h float) {
constructor(w, h float) {
this.w = w
this.h = h
}
constructor(size float) {
this.__constructor__(size, size)
}
}
func main {
rectangle1 Rectangle(100, 50)
rectangle2 Rectangle = Rectangle(75, 50)
rectangle3 Rectangle
rectangle3.__constructor__(500)
rectangle4 *Rectangle = new Rectangle(640, 480)
defer delete rectangle4
}

Constructors automatically generate a function that has the same name as the target type, and which returns a constructed instance of that type.

Constructors also come with a companion __constructor__ method, which can be used to call a constructor on any value

Constructors can use the immediate construction syntax:

rectangle Rectangle(100, 50)
square *Rectangle = new Rectangle(400, 400)
defer {
square.__defer__()
delete square
}

Zero-initialization is still the default, constructors don't apply to naked definitions, e.g. my_value MyType is zero-initialized and not constructed.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Functions · AdeptLanguage/Adept Wiki · GitHub
Skip to content
Isaac Shelton edited this page Sep 8, 2023 · 8 revisions

Functions

Functions are blocks of code that take zero or more parameters and optionally return a value.

Declaration

There are multiple syntaxes for declaring functions, each varying in style preferences and specificity.

All function declarations are a combination of the following:

  • func keyword
  • function name
  • parameters (sometimes omitted)
  • return type (sometimes omitted)
  • block or expression

You can declare a function using any of the following syntax styles.

Standard Syntax

func myFunction {}
func myFunction ReturnType {}
func myFunction(arg_name ArgType, arg_name ArgType) {}
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType {}
func myFunction ReturnType = return_value
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 1

myFunction :: func {}
myFunction :: func ReturnType {}
myFunction :: func (arg_name ArgType, arg_name ArgType) {}
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType {}
myFunction :: func ReturnType = return_value
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 2

myFunction :: func {}
myFunction :: func : ReturnType {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType {}
myFunction :: func : ReturnType = return_value
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType = return_value

Parameters

Function parameters are always given as a list of argument names and argument types all surrounded by parentheses. When there are zero parameters, the parameter list can be omitted, or an empty parameter list () can be used.

Examples (Standard Syntax)
(name String)
(name String, age int)
(firstname, lastname String)
Examples (Alternative Syntax)
(name: String)
(name: String, age: int)
(firstname, lastname: String)

Compound Parameters

If multiple parameters in a row have the same argument type, then the shared argument type doesn't have to be specified multiple times.

For example

func setPosition(x float, y float, z float) void { /* ... */ }

can be abbreviated as

func setPosition(x, y, z float) void { /* ... */ }

or even

func setPosition(x, y, z float) { /* ... */ }

Default Values

Default values can be specified for each argument, and if the argument is missing when the function is called, then it will automatically be filled in with the default value.

func sum(a double = 0.0, b double = 0.0, c double = 0.0) double {
return a + b + c
}

Default values can be specified per argument or argument group, depending on syntax.

For example, the following applies to all a, b, and c

func sumB(a, b, c double = 0.0) double {
return a + b + c
}

But default values can also be specified per argument when using a shared argument type:

func sumC(a = 1.0, b = 2.0, c double = 3.0) double {
return a + b + c
}

Default argument values are evaluated in the context of the callee, and are unique to each call.

import basics
func getDefaultName() String {
print("Getting default name...")
return "Isaac"
}
func welcome(name String = getDefaultName()){
print("Welcome " + name)
}
func main {
welcome()
welcome()
}
Getting default name...
Welcome Isaac
Getting default name...
Welcome Isaac

POD Parameters

Arguments that are marked as POD (plain-old-data), are immune to __pass__ and __defer__ management procedures.

C-style Variadic Arguments

C-style variadic arguments can be used for a function, using ...

func myCStylePrintf(format *ubyte, ...) int { /* ... */ }

C-style variadic arguments do not support structure types, or other composite types. Unless compatibility with C is desired, it is recommended to use Adept-style variadic arguments instead.

Adept-style Variadic Arguments

Adept-style variadic arguments can be used for a function, using ... followed by a variable name to hold the variadic argument array.

import VariadicArray
func myPrintf(format String, ... arguments) int { /* ... */ }

For most cases, the type of the variadic argument list received, will be the standard library type VariadicArray.

Parameter Data-Flow Annotations

The keywords in, out, and inout can be used to help document the data flow of a function.

func sum(in a, b int, out result *int) {
*result = a + b
}

They only exist to help the programmer, and do NOT actually enforce data flows.

See data flow annotations for more information.

Return Type

The return type is specified after the parameter list. If there isn't any return type, then it can be omitted, or void can be used in its place.

Additionally, the return type of a function can be prefixed with the exhaustive keyword to make the return value no-discard. Return values that are no-discard cannot be ignored when calling the function. Forgetting to use the return value of a no-discard function is a compile-time error.

func getName() exhaustive String = "Not using this return value is a compile-time error"

Modifiers

The stdcall modifier can be used to tell the compiler that a function should use the stdcall calling convention.

stdcall func test(a int, b float) long {
/* ... */
}

The verbatim modifier can be used to disable auto-generation of certain management procedures. Generally it's used on __pass__ and __defer__ management definitions.

verbatim func __defer__(this *MyStruct) {
// 'verbatim' tells the compiler to not automatically call '__defer__' on children of 'this'
}
verbatim func __pass__(my_struct_value POD MyStruct) MyStruct {
// 'verbatim' tells the compiler to not automatically call '__pass__' on children of 'my_struct_value'
}

The implicit modifier can be used to promote the __as__ management procedure so the compiler will preform implicit conversions using it.

implicit func __as__(my_number MyNumber) double {
// 'implicit' makes it so that values of type 'MyNumber' can be converted to 'double' without explicitly using 'cast' or 'as'
}

Intrinsic Procedures

Some functions and methods have special intrinsic purposes.

See intrinsic procedures for more information

Foreign Functions

Functions defined in other programming languages can be declared using the foreign keyword.

foreign printf(*ubyte, ...) int

See foreign functions for more information.

Externally Visible Functions

Functions can be made externally visible by using the external keyword

external func sum(a, b int) int {
return a + b
}

See externally visible functions for more information.

Single Line Functions

When a function only performs a simple operation to return a value, it can be abbreviated by substituting the code block with an = sign followed by an expression that represents the return value

For example

func sum(a, b int) int {
return a + b
}

can be abbreviated as

func sum(a, b int) int = a + b

Polymorphic Functions

Polymorphic functions are functions that can operate on multiple types.

They are declared like normal functions, expect they use polymorphic types within their arguments and/or return type.

func difference(a, b $T) $T {
return a - b }

Function Aliases

Function aliases can be used to have multiple names refer to the same function definition

func alias println(String) => print

See function aliases for more information.

Multiple Possibilities

When multiple possible functions exist with the same name, then the rules for function resolution will be applied to determine which one is used.

See function calls for more information.

Virtual methods

Virtual methods are methods which are dispatched at runtime. They can be defined on classes. See classes for more information.

import basics
class Shape () {
constructor {}
virtual func getArea() float = 0.0
}
class Rectangle extends Shape (w, h float) {
constructor(w, h float){
this.w = w
this.h = h
}
override func getArea() float = this.w * this.h
}
func main {
shape *Shape = new Rectangle(5.0f, 10.0f)
defer delete shape
print(shape.getArea())
}

Disallowed functions

Functions may be marked with = delete after their return type to disallow using them.

func youCannotCallThisFunction(a, b int) int = delete
func youCannotCallThisFunctionAlso(a, b int) = delete
func youCannotCallThisFunctionEither(a, b int) int = delete { return a + b }

Trying to call a disallowed function is a compile-time error.

Disallowing functions is most useful for disabling assignment of certain types. For example,

func __assign__(this *UnassignableType, _other POD UnassignableType) = delete

Trying to assign a type regularly that has __assign__ disallowed is a compile-time error.

Constructors

Constructors can be created using the constructor keyword inside of composite types such as a classes or structs.

struct Rectangle (w, h float) {
constructor(w, h float) {
this.w = w
this.h = h
}
constructor(size float) {
this.__constructor__(size, size)
}
}
func main {
rectangle1 Rectangle(100, 50)
rectangle2 Rectangle = Rectangle(75, 50)
rectangle3 Rectangle
rectangle3.__constructor__(500)
rectangle4 *Rectangle = new Rectangle(640, 480)
defer delete rectangle4
}

Constructors automatically generate a function that has the same name as the target type, and which returns a constructed instance of that type.

Constructors also come with a companion __constructor__ method, which can be used to call a constructor on any value

Constructors can use the immediate construction syntax:

rectangle Rectangle(100, 50)
square *Rectangle = new Rectangle(400, 400)
defer {
square.__defer__()
delete square
}

Zero-initialization is still the default, constructors don't apply to naked definitions, e.g. my_value MyType is zero-initialized and not constructed.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Functions · AdeptLanguage/Adept Wiki · GitHub
Skip to content
Isaac Shelton edited this page Sep 8, 2023 · 8 revisions

Functions

Functions are blocks of code that take zero or more parameters and optionally return a value.

Declaration

There are multiple syntaxes for declaring functions, each varying in style preferences and specificity.

All function declarations are a combination of the following:

  • func keyword
  • function name
  • parameters (sometimes omitted)
  • return type (sometimes omitted)
  • block or expression

You can declare a function using any of the following syntax styles.

Standard Syntax

func myFunction {}
func myFunction ReturnType {}
func myFunction(arg_name ArgType, arg_name ArgType) {}
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType {}
func myFunction ReturnType = return_value
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 1

myFunction :: func {}
myFunction :: func ReturnType {}
myFunction :: func (arg_name ArgType, arg_name ArgType) {}
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType {}
myFunction :: func ReturnType = return_value
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 2

myFunction :: func {}
myFunction :: func : ReturnType {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType {}
myFunction :: func : ReturnType = return_value
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType = return_value

Parameters

Function parameters are always given as a list of argument names and argument types all surrounded by parentheses. When there are zero parameters, the parameter list can be omitted, or an empty parameter list () can be used.

Examples (Standard Syntax)
(name String)
(name String, age int)
(firstname, lastname String)
Examples (Alternative Syntax)
(name: String)
(name: String, age: int)
(firstname, lastname: String)

Compound Parameters

If multiple parameters in a row have the same argument type, then the shared argument type doesn't have to be specified multiple times.

For example

func setPosition(x float, y float, z float) void { /* ... */ }

can be abbreviated as

func setPosition(x, y, z float) void { /* ... */ }

or even

func setPosition(x, y, z float) { /* ... */ }

Default Values

Default values can be specified for each argument, and if the argument is missing when the function is called, then it will automatically be filled in with the default value.

func sum(a double = 0.0, b double = 0.0, c double = 0.0) double {
return a + b + c
}

Default values can be specified per argument or argument group, depending on syntax.

For example, the following applies to all a, b, and c

func sumB(a, b, c double = 0.0) double {
return a + b + c
}

But default values can also be specified per argument when using a shared argument type:

func sumC(a = 1.0, b = 2.0, c double = 3.0) double {
return a + b + c
}

Default argument values are evaluated in the context of the callee, and are unique to each call.

import basics
func getDefaultName() String {
print("Getting default name...")
return "Isaac"
}
func welcome(name String = getDefaultName()){
print("Welcome " + name)
}
func main {
welcome()
welcome()
}
Getting default name...
Welcome Isaac
Getting default name...
Welcome Isaac

POD Parameters

Arguments that are marked as POD (plain-old-data), are immune to __pass__ and __defer__ management procedures.

C-style Variadic Arguments

C-style variadic arguments can be used for a function, using ...

func myCStylePrintf(format *ubyte, ...) int { /* ... */ }

C-style variadic arguments do not support structure types, or other composite types. Unless compatibility with C is desired, it is recommended to use Adept-style variadic arguments instead.

Adept-style Variadic Arguments

Adept-style variadic arguments can be used for a function, using ... followed by a variable name to hold the variadic argument array.

import VariadicArray
func myPrintf(format String, ... arguments) int { /* ... */ }

For most cases, the type of the variadic argument list received, will be the standard library type VariadicArray.

Parameter Data-Flow Annotations

The keywords in, out, and inout can be used to help document the data flow of a function.

func sum(in a, b int, out result *int) {
*result = a + b
}

They only exist to help the programmer, and do NOT actually enforce data flows.

See data flow annotations for more information.

Return Type

The return type is specified after the parameter list. If there isn't any return type, then it can be omitted, or void can be used in its place.

Additionally, the return type of a function can be prefixed with the exhaustive keyword to make the return value no-discard. Return values that are no-discard cannot be ignored when calling the function. Forgetting to use the return value of a no-discard function is a compile-time error.

func getName() exhaustive String = "Not using this return value is a compile-time error"

Modifiers

The stdcall modifier can be used to tell the compiler that a function should use the stdcall calling convention.

stdcall func test(a int, b float) long {
/* ... */
}

The verbatim modifier can be used to disable auto-generation of certain management procedures. Generally it's used on __pass__ and __defer__ management definitions.

verbatim func __defer__(this *MyStruct) {
// 'verbatim' tells the compiler to not automatically call '__defer__' on children of 'this'
}
verbatim func __pass__(my_struct_value POD MyStruct) MyStruct {
// 'verbatim' tells the compiler to not automatically call '__pass__' on children of 'my_struct_value'
}

The implicit modifier can be used to promote the __as__ management procedure so the compiler will preform implicit conversions using it.

implicit func __as__(my_number MyNumber) double {
// 'implicit' makes it so that values of type 'MyNumber' can be converted to 'double' without explicitly using 'cast' or 'as'
}

Intrinsic Procedures

Some functions and methods have special intrinsic purposes.

See intrinsic procedures for more information

Foreign Functions

Functions defined in other programming languages can be declared using the foreign keyword.

foreign printf(*ubyte, ...) int

See foreign functions for more information.

Externally Visible Functions

Functions can be made externally visible by using the external keyword

external func sum(a, b int) int {
return a + b
}

See externally visible functions for more information.

Single Line Functions

When a function only performs a simple operation to return a value, it can be abbreviated by substituting the code block with an = sign followed by an expression that represents the return value

For example

func sum(a, b int) int {
return a + b
}

can be abbreviated as

func sum(a, b int) int = a + b

Polymorphic Functions

Polymorphic functions are functions that can operate on multiple types.

They are declared like normal functions, expect they use polymorphic types within their arguments and/or return type.

func difference(a, b $T) $T {
return a - b }

Function Aliases

Function aliases can be used to have multiple names refer to the same function definition

func alias println(String) => print

See function aliases for more information.

Multiple Possibilities

When multiple possible functions exist with the same name, then the rules for function resolution will be applied to determine which one is used.

See function calls for more information.

Virtual methods

Virtual methods are methods which are dispatched at runtime. They can be defined on classes. See classes for more information.

import basics
class Shape () {
constructor {}
virtual func getArea() float = 0.0
}
class Rectangle extends Shape (w, h float) {
constructor(w, h float){
this.w = w
this.h = h
}
override func getArea() float = this.w * this.h
}
func main {
shape *Shape = new Rectangle(5.0f, 10.0f)
defer delete shape
print(shape.getArea())
}

Disallowed functions

Functions may be marked with = delete after their return type to disallow using them.

func youCannotCallThisFunction(a, b int) int = delete
func youCannotCallThisFunctionAlso(a, b int) = delete
func youCannotCallThisFunctionEither(a, b int) int = delete { return a + b }

Trying to call a disallowed function is a compile-time error.

Disallowing functions is most useful for disabling assignment of certain types. For example,

func __assign__(this *UnassignableType, _other POD UnassignableType) = delete

Trying to assign a type regularly that has __assign__ disallowed is a compile-time error.

Constructors

Constructors can be created using the constructor keyword inside of composite types such as a classes or structs.

struct Rectangle (w, h float) {
constructor(w, h float) {
this.w = w
this.h = h
}
constructor(size float) {
this.__constructor__(size, size)
}
}
func main {
rectangle1 Rectangle(100, 50)
rectangle2 Rectangle = Rectangle(75, 50)
rectangle3 Rectangle
rectangle3.__constructor__(500)
rectangle4 *Rectangle = new Rectangle(640, 480)
defer delete rectangle4
}

Constructors automatically generate a function that has the same name as the target type, and which returns a constructed instance of that type.

Constructors also come with a companion __constructor__ method, which can be used to call a constructor on any value

Constructors can use the immediate construction syntax:

rectangle Rectangle(100, 50)
square *Rectangle = new Rectangle(400, 400)
defer {
square.__defer__()
delete square
}

Zero-initialization is still the default, constructors don't apply to naked definitions, e.g. my_value MyType is zero-initialized and not constructed.

Clone this wiki locally

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Functions · AdeptLanguage/Adept Wiki · GitHub
Skip to content
Isaac Shelton edited this page Sep 8, 2023 · 8 revisions

Functions

Functions are blocks of code that take zero or more parameters and optionally return a value.

Declaration

There are multiple syntaxes for declaring functions, each varying in style preferences and specificity.

All function declarations are a combination of the following:

  • func keyword
  • function name
  • parameters (sometimes omitted)
  • return type (sometimes omitted)
  • block or expression

You can declare a function using any of the following syntax styles.

Standard Syntax

func myFunction {}
func myFunction ReturnType {}
func myFunction(arg_name ArgType, arg_name ArgType) {}
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType {}
func myFunction ReturnType = return_value
func myFunction(arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 1

myFunction :: func {}
myFunction :: func ReturnType {}
myFunction :: func (arg_name ArgType, arg_name ArgType) {}
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType {}
myFunction :: func ReturnType = return_value
myFunction :: func (arg_name ArgType, arg_name ArgType) ReturnType = return_value

Alternative Syntax 2

myFunction :: func {}
myFunction :: func : ReturnType {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) {}
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType {}
myFunction :: func : ReturnType = return_value
myFunction :: func (arg_name : ArgType, arg_name : ArgType) : ReturnType = return_value

Parameters

Function parameters are always given as a list of argument names and argument types all surrounded by parentheses. When there are zero parameters, the parameter list can be omitted, or an empty parameter list () can be used.

Examples (Standard Syntax)
(name String)
(name String, age int)
(firstname, lastname String)
Examples (Alternative Syntax)
(name: String)
(name: String, age: int)
(firstname, lastname: String)

Compound Parameters

If multiple parameters in a row have the same argument type, then the shared argument type doesn't have to be specified multiple times.

For example

func setPosition(x float, y float, z float) void { /* ... */ }

can be abbreviated as

func setPosition(x, y, z float) void { /* ... */ }

or even

func setPosition(x, y, z float) { /* ... */ }

Default Values

Default values can be specified for each argument, and if the argument is missing when the function is called, then it will automatically be filled in with the default value.

func sum(a double = 0.0, b double = 0.0, c double = 0.0) double {
return a + b + c
}

Default values can be specified per argument or argument group, depending on syntax.

For example, the following applies to all a, b, and c

func sumB(a, b, c double = 0.0) double {
return a + b + c
}

But default values can also be specified per argument when using a shared argument type:

func sumC(a = 1.0, b = 2.0, c double = 3.0) double {
return a + b + c
}

Default argument values are evaluated in the context of the callee, and are unique to each call.

import basics
func getDefaultName() String {
print("Getting default name...")
return "Isaac"
}
func welcome(name String = getDefaultName()){
print("Welcome " + name)
}
func main {
welcome()
welcome()
}
Getting default name...
Welcome Isaac
Getting default name...
Welcome Isaac

POD Parameters

Arguments that are marked as POD (plain-old-data), are immune to __pass__ and __defer__ management procedures.

C-style Variadic Arguments

C-style variadic arguments can be used for a function, using ...

func myCStylePrintf(format *ubyte, ...) int { /* ... */ }

C-style variadic arguments do not support structure types, or other composite types. Unless compatibility with C is desired, it is recommended to use Adept-style variadic arguments instead.

Adept-style Variadic Arguments

Adept-style variadic arguments can be used for a function, using ... followed by a variable name to hold the variadic argument array.

import VariadicArray
func myPrintf(format String, ... arguments) int { /* ... */ }

For most cases, the type of the variadic argument list received, will be the standard library type VariadicArray.

Parameter Data-Flow Annotations

The keywords in, out, and inout can be used to help document the data flow of a function.

func sum(in a, b int, out result *int) {
*result = a + b
}

They only exist to help the programmer, and do NOT actually enforce data flows.

See data flow annotations for more information.

Return Type

The return type is specified after the parameter list. If there isn't any return type, then it can be omitted, or void can be used in its place.

Additionally, the return type of a function can be prefixed with the exhaustive keyword to make the return value no-discard. Return values that are no-discard cannot be ignored when calling the function. Forgetting to use the return value of a no-discard function is a compile-time error.

func getName() exhaustive String = "Not using this return value is a compile-time error"

Modifiers

The stdcall modifier can be used to tell the compiler that a function should use the stdcall calling convention.

stdcall func test(a int, b float) long {
/* ... */
}

The verbatim modifier can be used to disable auto-generation of certain management procedures. Generally it's used on __pass__ and __defer__ management definitions.

verbatim func __defer__(this *MyStruct) {
// 'verbatim' tells the compiler to not automatically call '__defer__' on children of 'this'
}
verbatim func __pass__(my_struct_value POD MyStruct) MyStruct {
// 'verbatim' tells the compiler to not automatically call '__pass__' on children of 'my_struct_value'
}

The implicit modifier can be used to promote the __as__ management procedure so the compiler will preform implicit conversions using it.

implicit func __as__(my_number MyNumber) double {
// 'implicit' makes it so that values of type 'MyNumber' can be converted to 'double' without explicitly using 'cast' or 'as'
}

Intrinsic Procedures

Some functions and methods have special intrinsic purposes.

See intrinsic procedures for more information

Foreign Functions

Functions defined in other programming languages can be declared using the foreign keyword.

foreign printf(*ubyte, ...) int

See foreign functions for more information.

Externally Visible Functions

Functions can be made externally visible by using the external keyword

external func sum(a, b int) int {
return a + b
}

See externally visible functions for more information.

Single Line Functions

When a function only performs a simple operation to return a value, it can be abbreviated by substituting the code block with an = sign followed by an expression that represents the return value

For example

func sum(a, b int) int {
return a + b
}

can be abbreviated as

func sum(a, b int) int = a + b

Polymorphic Functions

Polymorphic functions are functions that can operate on multiple types.

They are declared like normal functions, expect they use polymorphic types within their arguments and/or return type.

func difference(a, b $T) $T {
return a - b }

Function Aliases

Function aliases can be used to have multiple names refer to the same function definition

func alias println(String) => print

See function aliases for more information.

Multiple Possibilities

When multiple possible functions exist with the same name, then the rules for function resolution will be applied to determine which one is used.

See function calls for more information.

Virtual methods

Virtual methods are methods which are dispatched at runtime. They can be defined on classes. See classes for more information.

import basics
class Shape () {
constructor {}
virtual func getArea() float = 0.0
}
class Rectangle extends Shape (w, h float) {
constructor(w, h float){
this.w = w
this.h = h
}
override func getArea() float = this.w * this.h
}
func main {
shape *Shape = new Rectangle(5.0f, 10.0f)
defer delete shape
print(shape.getArea())
}

Disallowed functions

Functions may be marked with = delete after their return type to disallow using them.

func youCannotCallThisFunction(a, b int) int = delete
func youCannotCallThisFunctionAlso(a, b int) = delete
func youCannotCallThisFunctionEither(a, b int) int = delete { return a + b }

Trying to call a disallowed function is a compile-time error.

Disallowing functions is most useful for disabling assignment of certain types. For example,

func __assign__(this *UnassignableType, _other POD UnassignableType) = delete

Trying to assign a type regularly that has __assign__ disallowed is a compile-time error.

Constructors

Constructors can be created using the constructor keyword inside of composite types such as a classes or structs.

struct Rectangle (w, h float) {
constructor(w, h float) {
this.w = w
this.h = h
}
constructor(size float) {
this.__constructor__(size, size)
}
}
func main {
rectangle1 Rectangle(100, 50)
rectangle2 Rectangle = Rectangle(75, 50)
rectangle3 Rectangle
rectangle3.__constructor__(500)
rectangle4 *Rectangle = new Rectangle(640, 480)
defer delete rectangle4
}

Constructors automatically generate a function that has the same name as the target type, and which returns a constructed instance of that type.

Constructors also come with a companion __constructor__ method, which can be used to call a constructor on any value

Constructors can use the immediate construction syntax:

rectangle Rectangle(100, 50)
square *Rectangle = new Rectangle(400, 400)
defer {
square.__defer__()
delete square
}

Zero-initialization is still the default, constructors don't apply to naked definitions, e.g. my_value MyType is zero-initialized and not constructed.

Clone this wiki locally