Thanks to its VBScript heritage, Wasabi makes a distinction between functions and subroutines (Wikipedia, however, does not): functions return a value while subroutines do not. This ostensibly provides a distinction between functions you call for the value they return (functions) and ones you call for the side effects they cause (subroutine).
Functions are defined using the Function keyword and values are returned using the Return statement:
Function Fib(n)
If n < 2 Then
Return 1
End If
Return Fib(n - 1) + Fib(n - 2)
End Function
Warning
Inherited from VBScript, Wasabi allows you to set the return value of a Function by assigning to the function’s name and to exit early using the Exit Function statement:
Function Fib(n)
If n < 2 Then
Fib = 1
Exit Function
End If
Fib = Fib(n - 1) + Fib(n - 2)
End Function
These practices are deprecated. Use the Return instead.
Functions allow you to specify optional parameters using the Optional:
Function Indent(node, Optional depth = 0)
Dim indent = "".PadLeft(depth)
%><%= indent %><%= node %><%
For Each Dim child in node.Children()
Indent(child, depth + 1)
Next
End Function
Indent(tree)
Futhermore, parameters can be specified by name using the := syntax:
Indent(node := tree, depth := 10)
This is particularly useful for destinguishing literal parameters of the same type, but is also commonly used in conjunction with Optional parameters. Keep in mind that all positional parameters must come before named parameters.
While Wasabi’s type inferencer will infer the types of the majority of variables, you can provide type annotations to explicitly identify a functions return type and the types of it’s parameters:
Function Fib(n As Int32) As Int32
' Calculate Fib(n)
End Function
Generally, it is perfectly acceptable to not include type annotations on internal variables, but it is generally a good idea to provide type annotations on your external interfaces so that:
Subroutines are defined using the Sub keyword:
Sub Greetings(name, adjective)
%>Hello <%= name %>. It's a <%= adjective %> day!<%
End Sub
... and invoked like so:
Greetings "Aaron", "wonderful"
Notice that the arguments to the subroutine call are not surrounded in parenthesis. The grammar does allow for parens to be included for single argument calls, but this is simply an artifact of using parens to group expressions and not part of the grammar of subroutine calls. Early exit from a subroutine is accomplished using the Return statement, for example:
Sub Example(predicate)
If predicate Then
Return
End If
' Do stuff
End Sub
Note
Wasabi functions are not function objects, and do not capture their enclosing scope. In order to pass a function defined in a Function statement to a higher-order function you must wrap it in a simple Lambda.
Wasabi supports function objects; however, not all functions are objects, they must be created explicitly using the Lambda keyword. There are two forms of the Lambda expression a short form:
Dim predicate = Lambda (x) x > 0
... and a long form:
Function MakeAdder(x)
Return Lambda (y)
Return x + y
End Lambda
End Function
' Returns: 3
MakeAdder(1)(2)
Lambda objects do capture the objects they reference in their enclosing scope, making them closures.
The type of a function object is declared using the Function keyword:
Function Filter(predicate As Function(Variant, Returns Boolean), list As Variant())
...
End Function
The GetRef(name) built-in function returns a reference to a named function that can be passed around like a Lambda object.