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

Name bindings

Basics

Name bindings are made of three distinct components. The name, the type and the value that is assigned to the name.

Declaration of variables happens using the : and = symbols:

x: i32 = 3;

The : symbol is used to denote the type of a variable, and the = symbol is used to assign a value to it. The type can be omitted, in which case it is inferred:

x := "Terence Tao"; // `x: str` inferred
x: str = "Terence Tao"; // same thing
x: i32 = "Terence Tao"; // Compile error: `str` is not assignable to `i32`.

Declaration and assignment can happen separately:

x: i32:
print(x); // Compile error: `x` might be uninitialised at this point!
x = 3; 
print(x); // Ok

A variable declaration is an expression like any other, and returns the value of the variable. This means that you can write something like:

while (bytes_read := read_file(&buffer)) != 0 {
  print("Read some bytes!");
}

Hash is statically typed, which means that variables cannot change types:

x := "Ha!";
x = Some("Baaa"); // Compile error: `Option<str>` is not assignable to `str`.

Mutability

By default, all bindings in Hash are constant. In order to declare a mutable variable, use the mut keyword in front of a name binding.

(mut a, mut b) := (1, 2);
mut test := get_test();

modify_test(&mut test);
a += 2;
b += 3;

Visibility

Visibility modifiers can be added to declarations inside modules or traits. By default, all declarations in a module scope or impl block are private, while all declarations in a trait block are public. To declare that a member is private, use priv, while to declare that a member is public, use pub.

// Visible from outside:
pub foo := 3;

// Not visible from outside:
bar := 4;


Foo := trait {
    // Visible from outside
    foo: (Self) -> str;

    // Not visible from outside
    priv bar: (Self) -> str;
};

Grammar

The grammar for name bindings (and partial name bindings/reassignments) is as follows:

pattern = pattern_binding | ...(other patterns)
pattern_binding = ( "pub" | "priv" )? "mut"? identifier

name_binding =
  | ( pattern ":=" expr )  // Declaration and assignment, infer type
  | ( pattern ( ":" type )? "=" expr  ) // Assignment
  | ( pattern ( ":" type )  ) // Declaration