Values, types and functions
Constants, functions and checks
# Constants, functions and checks.
const SECONDS_PER_MINUTE: i64 = 60
fn to_seconds(minutes: i64) -> i64 = minutes * SECONDS_PER_MINUTE
fn area(width: i64, height: i64) -> i64
let a = width * height
return a
check to_seconds(3) == 180
check area(4, 5) == 20
constnames a value that never changes. Its type is written after:.fn to_seconds(minutes: i64) -> i64 = ...is a function with one parameter of typei64(a 64-bit signed integer) that returns ani64. When the body is a single expression, write it after=.- A longer body goes in an indented block.
letnames a value inside the block.returngives the result. checkis a test. The checker evaluates it while checking the program, and the program is accepted only if every check is true.
Names at the top level of a file can be used before they are declared, so the order of declarations does not matter.
Integer types
RCE has the integer types i8, i16, i32, i64 (signed), u8, u16,
u32, u64 (unsigned) and usize (used for lengths and positions). Each
one stands for exactly the whole numbers in its range: a u8 is a number
from 0 to 255.
# Every integer type has a fixed range. Mixing types needs an explicit `as`.
fn small_sum(a: u8, b: u8) -> u8 = a + b
fn widen(a: u8, b: i64) -> i64 = (a as i64) + b
check small_sum(100, 27) == 127
check widen(200, 1000) == 1200
check (250 as u8).wrapping_add(10) == 4
check (250 as u8).saturating_add(10) == 255
check (250 as u8).checked_add(10).isnone()
A number written in the program is an i64 unless the place it is used
needs a different integer type. In small_sum(100, 27) the parameters are
u8, so 100 and 27 are u8.
Different integer types never mix silently. To add a u8 to an i64, turn
it into an i64 with as first, as widen does.
When a result does not fit
What is 200 + 100 as a u8? The true answer, 300, is not a u8. Many
languages quietly wrap it around to 44. RCE does not guess. The addition
traps: it stops with an error. Because the check below needs that addition,
the program is refused:
fn small_sum(a: u8, b: u8) -> u8 = a + b
check small_sum(200, 100) == 44
rce check says:
$ rce check overflow.rce
REFUSED overflow.rce: line 3: W-INT-1 check: trap: overflow: 300 is outside u8
exit status: 1
W-INT-1 is the name of the rule in the specification: every check and
example must hold. When you want wrapping or clamping, ask for it by name,
as sizes.rce does: wrapping_add wraps around, saturating_add stops at
the largest value, and checked_add gives an option that is empty when
the result does not fit. (Options come back in chapter 7.)
Mixing types without as is refused too, by the type rule W-TY-1:
fn add(a: u8, b: i64) -> i64 = a + b
$ rce check mixed_types.rce
REFUSED mixed_types.rce: line 1: W-TY-1 `+` on u8 and i64: no implicit conversion; line 1: W-TY-1 expected i64, found u8
exit status: 1
Other basic types
bool:trueandfalse, combined withand,or,not.f64andf32: floating-point numbers. A literal such as2.5is anf64. The specification fixes how every operation rounds, so the same float code gives the same bits on every target.text: a string of Unicode text, such as"hello". Chapter 8 covers it.(): the unit type, the result of a function that returns nothing.
What you learned
- Functions, constants and
checktests. - Integer types have exact ranges, and going outside a range traps.
- Conversions between types are always written with
as.