Rune types

Types in Rune are identified uniquely by their item. An item path is a scope-separated identifier, like std::f64. This particular item identifies a type.

These items can be used to perform basic type checking using the is and is not operations, like this:

assert!(() is Tuple, "tuples should be tuples");
assert!((1, 2) is Tuple, "tuples should be tuples");
assert!(true is bool, "bools should be bools");
assert!('a' is char, "chars should be chars");
assert!(b'a' is u64, "bytes should be unsigned integers");
assert!(42 is i64, "integers should be integers");
assert!(42.1 is f64, "floats should be floats");
assert!("hello" is String, "strings should be strings");
assert!("x" is not char, "strings are not chars");
assert!(#{"hello": "world"} is Object, "objects should be objects");
assert!(["hello", "world"] is Vec, "vectors should be vectors");
$> cargo run -- run scripts/book/types/types.rn

Conversely, the type check would fail if you're providing a value which is not of that type.

assert!(["hello", "world"] is String, "vectors should be strings");
$> cargo run -- run scripts/book/types/bad_type_check.rn
== ! (panicked `assertion failed: vectors should be strings` (at 12)) (133.3µs)
error: virtual machine error
  ┌─ scripts/book/types/bad_type_check.rn:2:5
  │
2 │     assert!(["hello", "world"] is String, "vectors should be strings");
  │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ panicked `assertion failed: vectors should be strings`

This gives us insight at runtime which type is which, and allows Rune scripts to make decisions depending on what type a value has.

fn dynamic_type(n) {
    if n is String {
        "n is a String"
    } else if n is Vec {
        "n is a vector"
    } else {
        "n is unknown"
    }
}

println!("{}", dynamic_type("Hello"));
println!("{}", dynamic_type([1, 2, 3, 4]));
println!("{}", dynamic_type(42));
$> cargo run -- run scripts/book/types/type_check.rn
n is a String
n is a vector
n is unknown

A tighter way to accomplish this would be by using pattern matching, a mechanism especially suited for many conditional branches. Especially when the branches are different types or variants in an enum.

fn dynamic_type(n) {
    match n {
        n if n is String => "n is a String",
        n if n is Vec => "n is a vector",
        _ => "n is unknown",
    }
}

println!("{}", dynamic_type("Hello"));
println!("{}", dynamic_type([1, 2, 3, 4]));
println!("{}", dynamic_type(42));
$> cargo run -- run scripts/book/types/type_check_patterns.rn
n is a String
n is a vector
n is unknown