-
Notifications
You must be signed in to change notification settings - Fork 4
Refinements
Starts with #
.
- Integer
-
int
: 64bit signed -
uint
: 64bit unsigned -
i32
: 32bit signed -
u32
: 32bit unsigned -
i8
: 8bit signed -
u8
: 8bit unsigned
-
- Float
-
float
: 64bit floating point -
f32
: 32bit floating point
-
- Boolean
bool
-
true
/false
- String
- utf8
- immutable
- Function
- Type (Left-hand side of
type
) - Module (Imported package with
import
)
For literal, 1 elem tuple is not allowed.
({elem0}, {elem1}, {elems}...)
- Named Elements
# Type Declaration
(
name0: int,
name1: bool,
)
# Literal
(name0: 42, name1: false)
- Unnamed Elements
# Type Declaration
(int, bool)
# Literal
(42, false)
- Mixed
named fields must follow unnamed field
# Type Declaration
(int, bool, name0: float)
# Literal
(42, false, name0: 3.14)
[elem]
Example:
# Type Declaration
[int]
# Literal
[1, 2, 3]
[] : [int]
# Access
[1, 2, 3][1] == 2
[key => val]
Example:
# Type Declaration
[bool => int]
# Literal
[true => 42, false => 21]
# Access
[true => 42, false => 21][true] == 42
enum (
Foo(int),
Bar(name0: bool),
Piyo,
)
type {name} = {type}
It defines a new type which is equivalent to rhs.
type Point = (
x: float,
y: float,
)
Point(x: 3.14, y: 2.7)
type Maybe = enum (
Just(?),
Nothing,
)
var m := Maybe::Just(42)
m = Maybe::Nothing # Inferred as Maybe(int)
func identifier(params) ret
body
end
It defines a constant variable identifier
whose type is function.
# Type of n and return type must be inferred
func product(n)
ret if n == 0 then 1 else n * product(n-1) end
end
# Type can be explicitly specified
func product(n: uint): uint
...
end
# 'var' keyword will pass parameter as mutable value with value semantics
func product(var n)
n = 10 # OK
end
Calling with positional or named arguments. If mixed, unnamed params must be followed by named ones.
func foo(a, b, c)
end
# Positional
foo(1, 2, 3)
# Named
foo(a: 1, b: 2, c: 3)
# Mixed
foo(1, 2, c: 3)
Initialize with :=
, modify with =
. They are immutable by default. They also can be mutable with var
(variable) keyword.
# Define immutable variable
n := 42
# Define mutable variable.
var m := 42
# Modify
m = -10
Structs, arrays and dicts are allocated to heap and managed by GC. They are used by reference. When complex type values are passed with value semantics, they will be deeply copied. They may be allocated to stack by escape analysis in the future.
- Sequence
{
statements...
}
Last expression is a value of sequence expression. If it's statement, the sequence can't be expression and can only be used as statement.
- Branch
if cond
val1
end
if cond
val1
else
val2
end
if cond then val1 else val2 end
if cond
val1
if cond2
val2
else
val3
end
If value of if
expression is omit, each if
clause can have different value type. In other words, if
can be statement.
When if
is used as expression, each clause must have the same type and the type value will be the value of the if
expression.
some_func(
if n > 0
42
else
21
end
)
- Pattern Match
case expr
of patt1
of patt2
else
end
- Loop
# 'while' loop
for cond
if some_cond
break
if other_cond
continue
end
end
# Infinite loop
for true
...
end
# Range 'for'
for elem in range
...
end
Loops must be a statement, not an expression.
In foo.dcs
+ func double(n)
ret n * 2
end
import foo as F
F.double(42)
Instead of UFCS, I'm considering apply operator because UFCS does not work well with modules because
import std
# How to use `std.to_float` or `std.to_int`in below UFCS?
42.to_float()
3.14.to_int()
# same as
std.to_float(42)
std.to_int(3.14)
# One idea: partial import
import std.{to_int, to_float}
# Well defined
42.to_float()
3.14.to_int()
With above partial import, we need to specify imported names twice.
Try to consider apply operator $
. $
is a binary operator where left hand side takes one expression or one tuple and right hand side takes a funciton.
import std
42 $ std.to_int
# Same as
std.to_int(42)
# Use with tuple
(3.0, 2.0) $ std.power # => 9.0
# Same as
std.power(3.0, 2.0)
# Chain
(3.0, 2.0) $ std.power $ std.sqrt $ std.to_int $ std.print_int
# Initialization?
42 $ std.to_int =: i
We can avoid ()
on single argument. (f(a)
v.s. a.f()
v.s. a $ f
)
- How this works with
do ... end
block?