Function Definition
In Cangjie, the func
keyword indicates the start of a function definition. func
is followed, by the function name, parameter list, an optional return value type, and the function body, in this order. Any valid identifier can be a function name. The parameter list is a comma (,) separated list enclosed in parentheses (). If the return value type is present, it is separated from the parameter list with a colon (:). The function body is enclosed in braces ({}).
The following is an example of function definition:
func add(a: Int64, b: Int64): Int64 {
return a + b
}
The preceding example defines a function named add
. The parameter list consists of the two parameters a
and b
of type Int64
. The return value type is also Int64
. The function body returns the result of adding together a
and b
.
Below is a further description of the parameter list, return value type, and function body in a function definition.
Parameter List
A function can have zero or more parameters, which are defined in the parameter list. Parameters in the parameter list are classified into non-named parameters and named parameters, based on whether their names need to be specified when the function is called.
A non-named parameter is defined by writing p: T
, where p
indicates the parameter name and T
indicates the parameter type. A colon (:) separates the parameter name and type. In the example above, the two parameters a
and b
of the add
function are non-named parameters.
A named parameter is defined by writing p!: T
. Unlike non-named parameters, an exclamation mark (!
) is added after p
(parameter name). The two non-named parameters of the add
function in the preceding example can be made named parameters as follows:
func add(a!: Int64, b!: Int64): Int64 {
return a + b
}
A named parameter may have a default value. For example, writing p!: T = e
sets the default value of p
to the value of the expression e
. In the following example, the default values of the two parameters of the add
function are both set to 1
:
func add(a!: Int64 = 1, b!: Int64 = 1): Int64 {
return a + b
}
Note:
Only named parameters may have default values.
A parameter list may contain both named and non-named parameters. Note that all non-named parameters must appear before named parameters. In the following example, the parameter list definition of the add
function is invalid:
func add(a!: Int64, b: Int64): Int64 { // Error, named parameter 'a' must be defined after non-named parameter 'b'
return a + b
}
The main difference between named and non-named parameters concerns the function call syntax. For more details, see Function Call.
Function parameters are immutable variables and therefore cannot be assigned to in the function body.
func add(a: Int64, b: Int64): Int64 {
a = a + b // Error
return a
}
The scope of a function parameter starts from its definition and ends with the function body.
func add(a: Int64, b: Int64): Int64 {
var a_ = a // OK
var b = b // Error, redefinition of declaration 'b'
return a
}
Return Value Type
The return value type of a function is the type of the value obtained from calling the function. An explicit return value type may be optionally specified in the function definition, and appears between the parameter list and function body. The compiler automatically determines the return value type if it is not specified in the function declaration.
When the return value type of a function is explicitly defined, the function body type or the type of e
in all return e
statements in the function body must be a subtype of the return value type. For details about how to determine the function body type, see Function Body. In the preceding example, the return value type of the add
function is explicitly defined as Int64
. If return a + b
in the function body is changed to return (a, b)
, an error is reported due to type mismatch.
// Error, the type of the expression after return does not match the return type of the function
func add(a: Int64, b: Int64): Int64 {
return (a, b)
}
If the return value type is not explicitly defined, the compiler will deduce it based on both the type and return
statements of the function body. In the following example, although the return value type of the add
function is omitted, the compiler can still deduce that the return value type is Int64
based on the statement return a + b
:
func add(a: Int64, b: Int64) {
return a + b
}
Note:
The return value types of functions cannot be deduced sometimes. If the return value type of a function fails to be deduced, the compiler reports an error.
If the return value type is defined as Unit, the compiler automatically inserts the expression return () where a value is possibly returned in the function body so that the return value type of the function is always Unit.
Function Body
A function body contains the operations to be performed when a function is called. It usually includes a number of variable definitions and expressions. It can also contain new function definitions (that is, nested functions). In the following example, the body of the add
function defines the r
variable of type Int64
(with an initial value of 0
), assigns the value of a + b
to r
, and then returns the value of r
:
func add(a: Int64, b: Int64) {
var r = 0
r = a + b
return r
}
A return
statement can appear anywhere in a function body to terminate the execution of the function and return a result. A return
statement can be in two forms: return
and return expr
(where expr
indicates an expression).
For the form return expr
, the type of expr
must be a subtype of the return value type specified in the function definition. In the following example, an error is reported because the type of 100
(Int64
) in return 100
differs from the return value type (String
) of the function foo
:
// Error, cannot convert an integer literal to type 'Struct-String'
func foo(): String {
return 100
}
When writing return
, which is equivalent to return ()
, the return value type of a function must be Unit
.
func add(a: Int64, b: Int64) {
var r = 0
r = a + b
return r
}
func foo(): Unit {
add(1, 2)
return
}
Note:
The type of a
return
statement as a whole isNothing
instead of an expression that follows it.
A variable defined in a function body is a local variable (such as the r
variable in the preceding example). Its scope starts from the definition and ends with the function body.
A local variable may have the same name as other variables that are defined outer scopes. In this case, using the shared name in the function body refers to the local variable, as shown in the example below.
let r = 0
func add(a: Int64, b: Int64) {
var r = 0
r = a + b
return r
}
In the add
function, the global variable r
of type Int64
is defined in the outer scope, and the local variable r
is defined in the function body. In the body of add
, the name r
refers to the local variable and not the global one.
As mentioned in Return Value Type, the function body also has a type. The function body type is the type of the last item in the function body. If the last item is an expression, the function body type is the expression type. If the last item is a variable definition or function declaration, or the function body is empty, the function body type is Unit
. The following is an example:
func add(a: Int64, b: Int64): Int64 {
a + b
}
In the preceding example, the last item in the function body is an expression of the Int64
type (a + b
). Therefore, the function body type is also Int64
, which matches the return value type in the function definition. In the following example, the last item in the function body is a call to the function print
. Therefore, the function body type is Unit
, which matches the return value type in the function definition.
func foo(): Unit {
let s = "Hello"
print(s)
}