The Vale Programming Language
These features aren't implemented yet, and are still just under consideration. Until then, we have --region-override unsafe 0 and extern functions.

Memory safety always has run-time costs, no matter what language we're in. 1 In Vale, the primary run-time cost is in generation checks, when the code will check that a reference still points to a valid object.

There are a lot of ways to avoid generation checks:

  • The compiler completely skips generation checks into immutable regions, because it knows no objects in there have been destroyed. 2
  • The compiler uses a lot of static analysis to automatically skips a lot of generation checks even in non-immutable regions.
  • Hybrid-generational memory will do some checks ahead of time, and then keeps objects alive to the end of a scope so we don't have to generation check them again. 3
  • "Unsafe" features (more on this below).

Between those first three, generation checks are likely a negligible source of overhead, especially since they rarely cause CPU cache misses, and their branching is perfectly predicted.

But if you need that extra bit of performance, keep reading!

Beware!

Warning! There are risks to using any of the below features. If you access an object that's already been destroyed, you'll likely corrupt memory.

Corrupting memory doesn't just cause bugs, it also means your program becomes nondeterministic and cannot use deterministic replayability.

Also note that these features are completely ignored in any dependencies by default, for security reasons. You'll need to explicitly whitelist every single module that the compiler should allow unsafe operations and FFI for, using the --unsafe_whitelist flag like --unsafe_whitelist that_module

Check Override

The check override operator !! can be used to skip any run-time overhead.

  • myObject.aField might perform a generation check on myObject but myObject!!.aField won't.
  • myObject[someIndex] will assert someIndex < myObject.len() but myObject!![someIndex] won't.

Any function that uses !! must be annotated with the unsafe keyword.

Module Check Override

We'll be able to turn off all generation checks for a certain module with the --unsafe_force flag, like --unsafe_force my_module.

This will be useful to measure the overall memory-safety overhead for your program.

The Unsafe Block

The unsafe block will establish a new region in which we can do unsafe operations. Specifically, it will use the normal heap (malloc and free), and it will have a normal stack like C does.

The unsafe block uses the region borrow checker to keep these separate from the normal surrounding region.

In this example, safeShip is in the safe region, and notSafeShip is in the unsafe region.

vale
func main() {
safeShip = Spaceship(1337);
unsafe block {
notSafeShip = Spaceship(1448);
...
}

}

Similar to Separated FFI, whenever the unsafe region has a reference to a safe region's object, it will be scrambled. When we try to use it again, it will be unscrambled and checked. This way, bugs inside the unsafe region don't corrupt memory in the safe region.

Side Notes
(interesting tangential thoughts)
0

This will turn off all generation checks across the program. Use with care!

1

With garbage collection and reference counting the cost is obvious, and surprisingly, even borrow checking indirectly causes run-time overhead: it centralizes objects such that we need to perform bounds checks and hashing more often than other paradigms.

3

See Hybrid-Generational Memory for more on this.