Basic types

Type annotations

Types come after the name of the thing they are the type of.
Function return types and parameter types are required. Local variable types are optional.

main void() log foo 1 foo string(n nat) s string = "{n}" s

Above, main is void, foo is string, n is nat, and s is string.

Anonymous type annotations

An anonymous type annotation that attaches to an expression instead of to a name.
expr::type specifies the type of an expression.
In a function call like to::int 1.5, the type is the return type of the function.
You can also write :: type at the start of an indented block to type the block.

main void() n = 1::nat m = to::int 1.5 log # This applies to the expression below it, not to 'log' :: string "{n} {m}"

Expected types

When Keen type-checks an expression, it may have an expected type.

  • A function body's expected type is the function's return type.
  • A function argument's expected type is the function's declared argument type.
    (Overloading complicates this; this will be explained in Overloading.)
  • A local's expected type is the declared type (if any).
  • Any expression with an anonymous type annotation has that as an expected type.
  • Certain expressions have an expected type; for example, in a sequence expression, any subexpression but the last must be void.

The below example uses () which can take on many types. This will be fully explained in "new" functions.

main void() () # is void # '()' is a bool _ bool = () # '()' is a nat _ = foo () foo string(_ nat) () # is a string

Many expressions do not need an expected type.
For example, the call to foo does not need an expected type, since there is only one foo and it returns a string.

Literal expressions

Literal expressions have favorite types that they will use automatically if there is no expected type.

A number literal prefers to be a nat, but a negative number will be an int and a number with a decimal point (even if .0) will be a float.

A string literal prefers to be a string.

main void() n = 1 # nat i = -1 # int f = 1.1 # float s = "hello" # string log n, i, f, s

If there is an expected type, a literal expression will use that instead of its default type.
(More on expected types in Overloading.)

main void() f float = 1 s symbol = "hello" j json = 4 log f, s, j

The possible number literal types are:

The possible string literal types are:

For char8 or char32, the string literal must contain a single character.
String literals can even be a user-defined type; see String literals.

Implicit conversion of numbers

Number types implicitly convert to larger number types of the same kind.
Keen will not implicitly convert between nats, ints, and floats, just within each category.

main void() n8 nat8 = 1 n nat = n8 i8 int8 = n.to i int = i8 f32 float32 = i.to f float = f32 log f