Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Built-in Values

Every Whim value has a runtime type. A declaration can state which values it accepts. Whim checks that rule when the program reaches the boundary.

Scalar values

Whim has seven scalar value kinds.

TypeValues
nullnull
booltrue and false
intsigned 64-bit integers
uintunsigned 64-bit integers, from 0 through 18,446,744,073,709,551,615
floatdouble-precision floating-point numbers
stringbyte strings
freshopaque identities created by fresh!()

Integers and floats stay distinct:

assert!(1 is int);
assert!(1u is uint);
assert!(1.0 is float);
assert!(1u != 1);
assert!(1 != 1.0);

Strings hold bytes, not a promise of valid UTF-8. The source file is UTF-8, but a string may contain any byte through escapes, file reads, sockets, or binary decoding.

fresh!() creates an identity distinct from every identity this VM has already created. Copying it preserves that identity:

$a = fresh!();
$b = fresh!();
$copy = $a;
assert!($a is fresh);
assert!($a != $b);
assert!($a == $copy);
$names = dict[$a => 'first', $b => 'second'];
assert!($names[$copy] == 'first');

Fresh values support == and !=, type checks, and dictionary keys. They have no order, arithmetic, bit operations, or implicit string or bool conversion. Even copies reject order comparisons such as $a <= $copy and $a <=> $copy. They cannot index a vec, tuple, or string.

$a as uint gives an unsigned integer for explicit use with APIs that need one. Equal identities give equal integers, and distinct identities give distinct integers during that VM lifetime. The integer has no promised value across runs and gives no ordering contract. Casting an integer back to fresh fails, including an integer obtained from a fresh value. Casting a fresh value to fresh preserves it.

If the VM exhausts its identity space, fresh!() throws OverflowError; further calls also fail. Separate VMs may reuse representations. Fresh values are not persistent IDs, distributed IDs, or secrets.

Whim\Refine\Scalar and Whim\Refine\ArrayKey include fresh. Whim\Refine\Numeric does not. JSON and BSON reject fresh values and keys; cast explicitly to a supported type when encoding a diagnostic representation. Such an encoding cannot restore the identity.

Arrays

Whim has three array forms:

TypeMeaning
(A, B)an immutable, fixed-size tuple
vec<T>a mutable list with uint keys from zero
dict<K, V>a mutable, ordered key-value map

array<K, V> accepts a tuple, vec, or dict whose keys and values fit K and V.

$pair = ('Ada', 36);
$names = vec['Ada', 'Grace'];
$scores = dict['Ada' => 10, 'Grace' => 12];

assert!($pair is (string, int));
assert!($names is vec<string>);
assert!($scores is dict<string, int>);

The collections chapter covers their syntax and update rules.

Objects and callables

object accepts any class instance. A class or interface name accepts objects of that class or its subtypes.

An object shape, such as #{ name: string, ... }, checks public instance properties and their current values. Omit ... to require exactly the listed public properties.

fn(A, B): R accepts a callable with two parameters and result R:

function apply(fn(int): int $operation, int $value): int {
  return $operation($value);
}

$double = fn(int $value): int => $value * 2;
assert!(apply($double, 21) == 42);

classname<T> accepts a class name whose instances satisfy T.

Wide and empty types

mixed accepts every value. !never also means every value.

never accepts no value. A function with return type never cannot return. It must throw, exit, or keep running.

void is valid only as a function or method return. Such a callable returns no value. You cannot use void for a parameter or property.

Literal types

A scalar value may also act as a type:

function choose('yes'|'no' $answer): bool {
  return $answer == 'yes';
}

assert!(choose('yes'));

true, 42, 42u, and 'yes' each describe one value. Literal types make unions, ranges, enum cases, and constants precise.

String length types

Put an integer or integer range after string to limit its byte length:

TypeAccepted strings
string[0]empty strings
string[5]strings with five bytes
string[1..]strings with at least one byte
string[1..=64]strings with one through 64 bytes

The range uses the same bounds as an integer range. Its lower bound is inclusive. .. excludes the upper bound, while ..= includes it.

Whim treats string[0] as '', string[1..] as string&!'', and string[0..] as string.

String lengths count bytes. For example, the UTF-8 form of é has two bytes:

assert!('é' is string[2]);

String length types work in aliases, parameters, properties, generic bounds, casts, and patterns.

Conditions

Conditions must be bool. Whim has no truthy or falsy conversion:

$name = 'Ada';
if ($name) {
  write_line!($name);
}

Write the test you mean:

$name = 'Ada';
if ($name != '') {
  write_line!($name);
}

This rule also applies to while, do ... while, &&, ||, &&=, and ||=.