LanguagesArchitecture

Vale was created to be the first fast, safe, and easy programming language.

Generally, languages today have one or two, but not all three.

This article will dive into the details and compare these languages' designs!

Easy Safe Fast
C++ No No Yes
Javascript Yes Yes No
Rust No Mostly Yes
Vale Yes Yes Yes

This article is meant to explain our vision for Vale, so will reference a lot of the final designs. We'll make it clear when we're talking about the current implementation versus what we have planned.

We hope to have all of these completed and benchmarked by late 2023. We're grateful for your interest and support as we create all this!

Side Notes
(interesting tangential thoughts)

Comparing with Love

We picked these three languages because they're our favorites in some way:

  • C++ has the feeling of raw power and freedom!
  • Javascript is like a soft autumn breeze, easy and refreshing. 0
  • Programming in Rust feels like an addictive puzzle game! 1

This post is not meant to criticize, just an honest comparison. Also note that these are only opinions, and not objective truths!

0

(I hope this isn't quoted on PCJ!)

1

It's fun to push the borrow checker's boundaries, especially when traits and closures are involved!

Easy

Vale aims to be safe and fast while also remaining easy.

To get a sense of what easy means:

  • Javascript is very easy. It only takes a few days to learn enough to make a medium-sized program in Javascript. It recently became even easier with the class keyword, to avoid the (usually) unintuitive prototypal inheritance.
  • C++ is very difficult. If one sticks to the more modern features and avoids multiple inheritance, it might only take a few months to become comfortable enough with C++ to be able to write a medium-sized program. However, to write a safe program in C++ is nearly impossible. One can get very close, with good use of smart pointers, valgrind, asan, etc, but it's still difficult to avoid undefined behavior.
  • Rust is also very difficult. It's as complex as C++, and throws it all at the programmer at once. Unless you're brilliant (or come from certain backgrounds which fit well with Rust's restrictions), it's going to take you many months to learn what patterns the borrow checker likes, what kinds of tricks to use to work around it, and when to give up and re-architect your program. Eventually, you internalize these things, at which point it has "clicked".

Vale is 100% safe, which removes most of C++'s difficulties.

Vale's "region borrow checker" doesn't impose the mutability-xor-aliasability restriction on every object, which is the source of Rust's difficulties.

Vale also has some innovations to make parallelism and concurrency easier:

  • Its planned "deterministic replayability" would help us reproduce race conditions and other bugs. Heisenbugs could be a thing of the past!
  • Its planned Seamless, Fearless, and Structured Concurrency would allow us to add structured concurrency without needing to refactor any existing code or data.

Vale does make a few concessions here:

  • It's centered around single ownership (moreso than C++ and Rust), in a way that isn't complicated by the orthogonal complexity burdens of C++ (difficult syntax and compiler errors) or Rust (the borrow checker).
  • Vale is statically typed, which isn't as easy as a dynamically typed language like Javascript (in the short term, at least).
  • Vale would have more advanced features, such as allocators and the region borrow checker. However, you can write entire programs without ever needing to know these, they're just for optimization. 2

In the end, Vale is almost as easy as Javascript, and much easier than Rust and C++.

2

This principle is called "gradual complexity." Other languages that do this well are C#, Swift, and Go.

Safe

Vale is 100% memory-safe and data-race-safe, like Javascript, and safer than Rust and C++.

  • C++ is completely unsafe. By default, the code you write will risk a lot of memory unsafety. There are ways to mitigate it (the aforementioned smart pointers, valgrind, asan), but it takes a lot of discipline.
  • Javascript is entirely sandboxed, and never shares memory with unsafe code. 3 You can largely trust Javascript code that someone else wrote. We do it all the time, with our browsers.
  • Rust is somewhere between. It's safe by default, except:
    • It has unsafe code which allow unsafe operations.
    • It allows bugs in unsafe code (and FFI 4) to trigger memory unsafety in safe Rust code.
    • A Rust program will bring a lot of unsafe code in via dependencies.

Vale plans to have a memory-safe unsafe block, as odd as that sounds; it will use the region borrow checker to keep the safe region's data separate from the unsafe region's data, and allowing safe communication between them.

Vale's "check override" operator !! is disabled by default, and can be enabled on a per-module basis.

3

Specifically, Javascript can use FFI into other languages with webassembly, but it doesn't share memory with them, it only sends immutable values back and forth.

4

This stands for Foreign Function Interface, and refers to how Rust can call into C code.

Fast

Note: Generational References are complete and stable, but the rest of this section is talking about Vale's final design. We hope to have all of these completed and benchmarked by mid-2023. We're grateful for your interest and support as we create all this!

Vale aims to be as fast as Rust and C++ in the average case, and much faster than Javascript.

  • Javascript uses dynamic typing and garbage collection, which both cause some overhead.
  • Rust is very fast. The borrow checker indirectly incurs only a little run-time overhead, often negligible. 5
  • C++ is the fastest; it lets you do anything you want, with zero overhead.

It is of course impossible to match C++'s speed in theory. However, for the majority of programs, Vale could approach it, and sometimes even surpass it.

Basically, we start with Generational References, and then remove the vast majority of the generation checks by using:

  • Object permissions such as iso and uni to inform the type system that these objects have no aliases, to skip all generation checks for those objects.
  • Hybrid-Generational Memory, which combines multiple generation checks into one ahead of time.
  • The Region Borrow Checker to temporarily turn any pre-existing data immutable, to skip generation checks when accessing them.

By our estimation, a surprisingly high percentage of functions drop to zero memory-safety overhead when we use these three techniques together as in this snippet, and we estimate the remaining generation checks are only about as common as the extra bounds checking that Rust does compared to other languages.

Additionally, Vale aims to make fast patterns much more accessible than C++ does, by:

  • Enabling memory-safe allocators and make them easy to use.
  • Making concurrency and parallelism easier than ever before, with Seamless Concurrency.

If we can make it easier to use these performance techniques, then people will use them more, and their programs will be faster in practice.

In summary, while no language can be faster than C++'s speed in theory, the average Vale program might be much faster in practice.

On top of all that, if there's still a generation check in critical code and someone needs an extra sliver of speed, they can use the check override operator to elide that check in release mode.

Intended Use Cases

Vale, C++, Rust, and JS have different strengths which makes them excel in different use cases.

Compared to Vale:

  • Javascript is very simple: dynamically typed and garbage collected. This could make it better than Vale for scripting and prototyping.
  • Rust imposes a lot of extra complexity on the programmer, but makes memory handling more explicit. This is better for things like embedded development or other overly-memory-constrained environments.
  • C++'s strength is in the absolute freedom it gives the programmer and its access to low-level memory tricks, which is vital in e.g. AAA games.

Vale's combination of speed, safety, and ease are universally useful, but it will particularly shine for:

  • Servers, because its 100% safety helps handle the untrusted input from the user, and its Seamless, Fearless, and Structured Concurrency makes concurrency easier than ever before.
  • Games, because it's extremely fast, with memory safety to prevent odd bugs, while still being easy and flexible enough to allow quick iterating and innovating.
  • Web/Android/iOS apps, because Vale's Higher RAII is an invaluable tool for complex systems with a lot of state.

We hope you enjoyed this article, and as always, feel free to tweet us, leave any comments in the r/vale subreddit, or swing by our discord server!

5

The borrow checker influences our programs to put more objects into centralized Vecs and HashMaps, which incur more bounds checking and hashing costs than other languages would in the same situation.