Functions with parameters may be defined as shown in the examples below.
fn(x, y) { x + y } fn x, y: x + y
Functions without parameters may be defined as shown in the examples below.
fn() { 123 } fn: 123
When using parentheses to define parameters (long form), curly braces are required to define the function body. The simple, or short form, without parentheses, requires a colon between parameters and the body of the function. With the short form, curly braces are not required if the body of the function is a single expression.
By default, function parameters are immutable.
To make a parameter mutable, precede the parameter name with a var token within the parameter list.
fn(x, y) { ... } # x and y immutable
fn(var x, y) { ... } # x mutable and y immutable
fn(var x, var y) { ... } # x and y mutable
Parameters could be of any type. To restrict a parameter type, use the type name after the parameter name.
fn(x string, y number) { ... } # x and y with explicit type
This checks the typed passed against the type declared.
Langur parameters fall into the following categories.
You can define optional parameters after positional parameters using the assignment syntax to define a default value for them.
val addto = fn(a, b=3) { a + b }
Optional arguments are always passed with the name (using assignment syntax), and positional arguments are never passed with the name.
addto(1)
addto(1, b=12)
Arguments using the name are not order-dependent (as long as they come after positional arguments), and any of them can be left out (except for required parameters by name).
An external name of a parameter by name can be preserved while changing the internal variable name, using the as keyword. An external name specified this way may also be the same as a keyword, since the context makes the meaning clear. The internal name is used within the function and the external name is used in the call.
val x = fn(a as c=123) { a } # a used internally x(c=9) # c used in call
This allows you to change a parameter name internally and not break an API in the process.
Parameters by name should not be confused with argument/parameter expansion, which only applies to positional arguments and parameters.
You can require a parameter that also must use the name (not positional). To do this, use the alias, but do not specify a default value. If you specify a default value, it is an optional parameter.
val x = fn(a as a) { a } # no default value for a; not optional and not positional x(a=9) # a required in call
You can use a ... operator on the last positional argument passed to a function, to expand a list argument into multiple arguments. This precedes any optional arguments passed.
val x = [[21, 7], [42, 14], [96, 21]] zip(x...) # result == [21, 42, 96, 7, 14, 21]
zip(mapX([7], [14, 21], by=fn x...: x)...) # result == [7, 7, 14, 21]
You can use the ... operator for parameter expansion. This allows a user-defined function to receive a variable number of arguments. The last arguments of the function will be placed into a single list. This also allows for setting limits for this expansion (with a default range of 0 to unlimited). -1 or nothing (such as [2..]) indicates unlimited for this purpose. See the following examples.
val a = fn(x...) { } # accepts 0 or more arguments val b = fn(x...[1..9]) { } # accepts 1 to 9 arguments val c = fn(x, y...[4]) { } # accepts 5 arguments val d = fn(x, y...[2 .. ]) { } # accepts 3 or more arguments val e = fn(x, y ...[2 .. 6]) { } # accepts 3 to 7 arguments
Argument/parameter expansion is considered to be positional and does not conflict with parameters by name. Parameters by name always follow positional parameters.
The possible parts of a parameter, in order, are as follows.
examples of parameter parts in order...
Using parameter expansion does not allow use of the other features at this time (mutable, alias, explicit type, or default value).
Using an explicit type does not allow a parameter to be mutable at this time.