Open chharvey opened 3 years ago
The default default value of an optional parameter is null
.
When an optional parameter is specified, it was required to be given a default value.
function moveForward(steps: int ?= 1): void {
% ^ default value
return print.(steps);
}
moveForward.(); % prints "1"
moveForward.(2); % prints "2"
Now that requirement is relaxed. If not provided, the default value defaults to null
.
function moveForward(steps?: int): void {
% ^ new token
return print.(steps);
}
moveForward.(); % prints "null"
moveForward.(2); % prints "2"
The symbol for an optional parameter annotation is ?:
, as it is for tuples and records with optional entries.
type NumberPairT = [int, ?: float];
type NumberPairR = [a: int, b?: float];
This symbol is only for the implicit default. For optional parameters with explicit default values, the colon is still used.
function moveForward(steps: int ?= 1): void {
% ^ stays the same
return print.(steps);
}
Because the “default default value” is null
, the type of the optional parameter includes null
when read, but not written.
function moveForward(var steps?: int): void {
let steps_1: str = steps; %> TypeError % read type of `steps` is `int?`
let steps_2: str? = steps; % ok
set steps = null; %> TypeError % write type of `steps` is `int`
set steps = 3; % ok
return;
}
This is in line with uninitialized variables (#96).
let var greeting?: str;
let greet_1: str = greeting; %> TypeError % read type of `greeting` is `str?`
let greet_2: str? = greeting; % ok
set greeting = null; %> TypeError % write type of `greeting` is `str`
set greeting = "hello"; % ok
But unlike uninitialized variables, uninitialized parameters need not be declared with the var
keyword.
ParameterFunction<Optional>
- ::= (IDENTIFIER "=")? "var"? IDENTIFIER ":" Type . <Optional+>( "?=" Expression);
+ ::= (IDENTIFIER "=")? "var"? IDENTIFIER . <Optional->(":" Type) <Optional+>("?:" Type | ":" Type "?=" Expression);
SemanticParameterType[optional: Boolean]
::= SemanticVariable? SemanticType;
-SemanticParameter[unfixed: Boolean]
- ::= SemanticKey? SemanticVariable SemanticType SemanticExpression?;
+SemanticParameter[optional: false][unfixed: Boolean]
+ ::= SemanticKey? SemanticVariable SemanticType;
+SemanticParameter[optional: true][unfixed: Boolean]
+ ::= SemanticKey? SemanticVariable SemanticType SemanticExpression?;
-Decorate(ParameterFunction ::= IDENTIFIER ":" Type) -> SemanticParameter
+Decorate(ParameterFunction<-Optional> ::= IDENTIFIER ":" Type) -> SemanticParameter
- := (SemanticParameter[unfixed=false]
+ := (SemanticParameter[optional=false][unfixed=false]
(SemanticVariable[id=TokenWorth(IDENTIFIER)])
Decorate(Type)
);
-Decorate(ParameterFunction ::= "var" IDENTIFIER ":" Type) -> SemanticParameter
+Decorate(ParameterFunction<-Optional> ::= "var" IDENTIFIER ":" Type) -> SemanticParameter
- := (SemanticParameter[unfixed=true]
+ := (SemanticParameter[optional=false][unfixed=true]
(SemanticVariable[id=TokenWorth(IDENTIFIER)])
Decorate(Type)
);
-Decorate(ParameterFunction ::= IDENTIFIER__0 "=" IDENTIFIER__1 ":" Type) -> SemanticParameter
+Decorate(ParameterFunction<-Optional> ::= IDENTIFIER__0 "=" IDENTIFIER__1 ":" Type) -> SemanticParameter
- := (SemanticParameter[unfixed=false]
+ := (SemanticParameter[optional=false][unfixed=false]
(SemanticKey[id=TokenWorth(IDENTIFIER__0)])
(SemanticVariable[id=TokenWorth(IDENTIFIER__1)])
Decorate(Type)
);
-Decorate(ParameterFunction ::= IDENTIFIER__0 "=" "var" IDENTIFIER__1 ":" Type) -> SemanticParameter
+Decorate(ParameterFunction<-Optional> ::= IDENTIFIER__0 "=" "var" IDENTIFIER__1 ":" Type) -> SemanticParameter
- := (SemanticParameter[unfixed=true]
+ := (SemanticParameter[optional=false][unfixed=true]
(SemanticKey[id=TokenWorth(IDENTIFIER__0)])
(SemanticVariable[id=TokenWorth(IDENTIFIER__1)])
Decorate(Type)
);
+Decorate(ParameterFunction<+Optional> ::= IDENTIFIER "?:" Type) -> SemanticParameter
+ := (SemanticParameter[optional=true][unfixed=false]
+ (SemanticVariable[id=TokenWorth(IDENTIFIER)])
+ Decorate(Type)
+ (SemanticConstant[value=null])
+ );
Decorate(ParameterFunction<+Optional> ::= IDENTIFIER ":" Type "?=" Expression) -> SemanticParameter
- := (SemanticParameter[unfixed=false]
+ := (SemanticParameter[optional=true][unfixed=false]
(SemanticVariable[id=TokenWorth(IDENTIFIER)])
Decorate(Type)
Decorate(Expression)
);
+Decorate(ParameterFunction<+Optional> ::= "var" IDENTIFIER "?:" Type) -> SemanticParameter
+ := (SemanticParameter[optional=true][unfixed=true]
+ (SemanticVariable[id=TokenWorth(IDENTIFIER)])
+ Decorate(Type)
+ (SemanticConstant[value=null])
+ );
Decorate(ParameterFunction<+Optional> ::= "var" IDENTIFIER ":" Type "?=" Expression) -> SemanticParameter
- := (SemanticParameter[unfixed=true]
+ := (SemanticParameter[optional=true][unfixed=true]
(SemanticVariable[id=TokenWorth(IDENTIFIER)])
Decorate(Type)
Decorate(Expression)
);
+Decorate(ParameterFunction<+Optional> ::= IDENTIFIER__0 "=" IDENTIFIER__1 "?:" Type) -> SemanticParameter
+ := (SemanticParameter[optional=true][unfixed=false]
+ (SemanticKey[id=TokenWorth(IDENTIFIER__0)])
+ (SemanticVariable[id=TokenWorth(IDENTIFIER__1)])
+ Decorate(Type)
+ (SemanticConstant[value=null])
+ );
Decorate(ParameterFunction<+Optional> ::= IDENTIFIER__0 "=" IDENTIFIER__1 ":" Type "?=" Expression) -> SemanticParameter
- := (SemanticParameter[unfixed=false]
+ := (SemanticParameter[optional=true][unfixed=false]
(SemanticKey[id=TokenWorth(IDENTIFIER__0)])
(SemanticVariable[id=TokenWorth(IDENTIFIER__1)])
Decorate(Type)
Decorate(Expression)
);
+Decorate(ParameterFunction<+Optional> ::= IDENTIFIER__0 "=" "var" IDENTIFIER__1 "?:" Type) -> SemanticParameter
+ := (SemanticParameter[optional=true][unfixed=true]
+ (SemanticKey[id=TokenWorth(IDENTIFIER__0)])
+ (SemanticVariable[id=TokenWorth(IDENTIFIER__1)])
+ Decorate(Type)
+ (SemanticConstant[value=null])
+ );
Decorate(ParameterFunction<+Optional> ::= IDENTIFIER__0 "=" "var" IDENTIFIER__1 ":" Type "?=" Expression) -> SemanticParameter
- := (SemanticParameter[unfixed=true]
+ := (SemanticParameter[optional=true][unfixed=true]
(SemanticKey[id=TokenWorth(IDENTIFIER__0)])
(SemanticVariable[id=TokenWorth(IDENTIFIER__1)])
Decorate(Type)
Decorate(Expression)
);
Optional parameters allow arguments to be omitted from a function call.
Discussion
An optional parameter must have a default value, and when the argument for that optional parameter is omitted, the function is called as if the default value were provided.
The code
?= 1
is called an initializer and defines the default value of thesteps
parameter. It’s similar to the initializer of a variable declaration. WhenmoveForward
is called without that argument, the default value of1
is assumed.Notice the type signature’s new syntax:
(steps?: int) => void
. This means that the function may be called with 0 or 1 argument, and if it is called with 1 argument, that argument may be given a name ofsteps
, and it must be of typeint
. Function calls are not covered in this version.The syntax of optional type parameters carries over into unnamed parameters of a type signature.
The signature above indicates that a function of type
BinaryOperatorTypeUnnamed
has 1 required parameter and 1 optional parameter. Optional parameters’ default values are an implemenation detail, so they cannot be specified in type signatures. And since the parameters of this type signature are unnamed, an implementing function can only be called with positional arguments.All optional parameters must be declared after all required parameters; otherwise it’s a syntax error.
Specifying an initializer that mismatches the parameter type results in a TypeError.
Optional parameters may be unfixed (reassignable within the function):
Default Parameter Evaluation
Optional parameter initializers are evaluated when the function is called, not when it’s defined.
If an optional parameter initializer references a variable, it must be captured (as shown above), and it refers to the variable bound to the environment in which it’s initialized, not in which the function is called. And, if that variable is ever reassigned outside the function, the reassignment is not observed. However, mutations will still be observed.
Specification
Lexicon
Syntax
Semantics
Decorate
FunctionTypeOf