Advanced topics
Attributes
Attributes are given to module-level declarations to control how they are
treated by the compiler. Attributes appear in #[...]
before the declaration
and can be applied to module-level type, function, and constant declarations.
implicit
attribute
Refer to the implicits for information on #[implicit]
.
link
attribute
The link
attribute links a function against a function implemented in Erlang.
It accepts two parameters: an Erlang module name and an Erlang function name.
The linked function and the name of the function in Fuyu may be different. It
is a compile-time error if this function is not found.
#[link "lists" "last"]
last: List a -> a
The module name can be a path to a file. In this case, it must start with
either ./
or ../
.
#[link "./wrapper.erl" "last"]
last: List a -> a
public
attribute
The public
attribute makes a declaration available outside of the module.
Refer to visibility.
test
attribute
The test
attribute is given to functions that run test code. They will be
ignored in compilation except for when generating tests.
import std/assert
#[test]
test_equals: () -> ()
test_equals () = assert.eq 123 123
test_helper
attribute
The test_helper
attribute is given to functions, types, and constants that
are used only in tests.
import std/assert
import std/list
#[test_helper]
all_eq: &[Eq a] -> List a
all_eq xs = xs match
[x, y, *rs] ->
assert.eq x y
all_eq [y, ..rs]
_ -> ()
#[test]
test_all_eq: () -> ()
test_all_eq () = all_eq [123, 123, 123]
transparent
attribute
The transparent
attribute marks a type as transparent. Refer to
transparency.
Panic
A panic
is used when a non-recoverable error state is reached and the
chosen solution is to terminate the process.
checked_div: Float -> Float -> Float
checked_div x 0 = panic
checked_div x y = x / y
An optional message for the panic can be given by any expression that evaluates to a string.
checked_div: Float -> Float -> Float
checked_div x 0 = panic "Cannot divide by zero."
checked_div x y = x / y
Todo
A todo
is used to mark incomplete code with the intention to complete it
later. It will produce a compile-time warning and panic if evaluated.
greatest_common_divisor: Int -> Int -> Int
greatest_common_divisor a b = todo
Using todo
has another benefit for this function: it will only produce one
warning instead of three. When todo
appears in a function, warnings about
unused variables are not emitted, as it is assumed that they will be used once
the function is implemented.
An expression evaluating to a string can be used with todo
as the panic
message.
greatest_common_divisor: Int -> Int -> Int
greatest_common_divisor a b = todo "Implement using the Euclidean algorithm."
For functions that are not implemented and with no intent to do so, use
unimplemented
instead.
Unimplemented
An unimplemented
is used to mark incomplete code with no intention
to complete it later. It will produce a compile-time warning and panic if
evaluated. This is most commonly used in implicits and higher-order functions
for which it is known the function is never called.
The unimplemented
behaves exactly like todo
.
The difference is that unimplemented
is used when there is no intent to
implement the function, and todo
is used when there is.
When a function is not yet implemented but there is intent to do so, use
todo
.
Unreachable
An unreachable
expression is used to mark a branch of code that will never be
reached. If it happens to be evaluated, it will panic.
describe: Option Int -> String
describe (Some x) if x > 0 = "positive"
describe (Some x) if x == 0 = "zero"
describe (Some x) if x < 0 = "negative"
describe (Some _) = unreachable // Required for pattern exhaustion.
describe None = "nothing"
An expression evaluating to a string can optionally be added that is displayed as the panic message.
describe_as_square: Int -> String
describe_as_square n =
let x = when
n > 100 -> 100
n < 0 -> 0
else -> n
let s = math.sqrt x
when
x <= 3 -> "small square"
x <= 7 -> "medium square"
x <= 10 -> "large square"
else -> unreachable "The square root can never be greater than 10."