Expressions
The expressions are listed in order of precedence so you know where to add parenthesis.
#
LiteralThese are all valid literals: 42
, true
, false
, "aaa"
.
These are not: 3.14
, 'c'
.
#
ThisThe syntax is simple: this
. It can be only used inside a method.
#
VariableYou can refer to a local variable or function parameter just by typing its name. For example, you can have:
or
#
Class FunctionYou can refer to a module function by ModuleName.functionName
.
For example, you can write:
#
TupleYou can construct a tuple by surrounding a list of comma separated expressions with []
.
- This is a tuple:
[1, 2]
; - This is also a tuple:
["foo", "bar", true, 42]
; - This is a tuple that is not fully evaluated:
[3 + 4, true && false]
; - Tuples can live inside another tuple:
[["hi", "how"], ["are", "you"]]
;
#
VariantA variant constructor is like a function, but it must start with an uppercase letter: Some(42)
.
#
Field AccessYou can access a field simply by using the dot syntax: expr.name
. Note that you can only access
the field within the class. You always need to use this syntax to access the field. i.e. this.name
and field
refer to different things.
#
Method AccessYou can access a method by using the .
syntax: expr.map
.
#
Unary Expressions- Negation:
-42
,-(-42)
- Not:
!true
,!(!(false))
#
Panic ExpressionYou can think of panic as a special function that has a generified type: <T>() -> T
. It's purpose
is to throw an unchecked exception with a specified message. For example, you can write:
When you do something illegal (e.g. division by zero), the interpreter may decide to panic.
#
Built-in Function CallThere are three built-in functions:
stringToInt: (string) -> int
. It will panic if the given string cannot be converted to int.intToString: (int) -> string
println: (string) -> unit
You can directly call them in samlang code.
#
Function CallYou can call a function as you would expect: functionName(arg1, arg2)
.
However, you don't need to have a function name: a lambda can also be used: ((x) -> x)(3)
.
Currying is not supported.
#
Binary ExpressionsHere are the supported ones:
a * b
,a / b
,a % b
,a + b
,a - b
:a
andb
must beint
, and the result isint
;a < b
,a <= b
,a > b
,a >= b
:a
andb
must beint
, and the result isbool
;a == b
,a != b
:a
andb
must have the same type, and the result isbool.
;a && b
,a || b
:a
andb
must bebool
, and the result isbool
;a::b
(string concatenation ofa
andb
):a
andb
must bestring
, and the result isstring
.
#
If-Else ExpressionsIn samlang, we don't have ternary expression, because if-else blocks are expressions.
You can write: if a == b then c else d
. c
and d
must have the same type and the result has the
same type as c
and d
.
#
Match Expressions (Pattern Matching!)Suppose you have a variant type like class Option<T>(None(unit), Some(T)) {}
. You can match on it
like:
Pattern matching must be exhaustive. For example, the following code will have a compile-time error:
#
LambdaYou can easily define an anonymous function as a lambda. Here is the simpliest one: () -> 0
. Here
is a more complex one: identity function (x) -> x
. Note that the argument must always be
surrounded by parenthesis.
You can optionally type-annotate some parameters: (x: int, y) -> x + y
.
#
Statement Block ExpressionYou can define new local variables by using the val statement within a block of statements:
The above example shows various usages of val statement. You can choose to type-annotate the pattern (variable, tuple, object, or wildcard), destruct on tuples or object, and ignore the output by using wildcard (supported in tuple pattern and wildcard pattern). Note that the semicolon is optional.
Statement blocks can be nested:
You may write function a(): unit = { val _ = 3; unit }
. There is a syntactic sugar for this
use-case: function a(): unit = { val _ = 3; }
. Therefore, you can also create a unit
value by
{}
.