Better ergonomics for dealing with options

We are missing operators to deal with Option<T> values. We currently have only two things you can do with it:

  • match on it
  • apply the ? operator

You can’t even call any methods on it.

I think we are missing at least the following operators.

Null coalescing operator

Many languages have an operator that looks like ?? which returns the left hand side if it’s Some and the right hand side otherwise.

let x = None;
let y = x ?? 3;

What’s nifty about most implementations is that the right-hand side can be either T or Option<T>, which makes it a substitute for both unwrap_or and or in Rust and it allows it to be chained. Even better still, it’s also a substitute for unwrap_or_else and or_else because it’s lazily evaluated.

The main problem with having this operator in Roto is that we’ve already picked a meaning for ? and there are cases where it is slightly ambiguous:

let x = foo()??; # double `?` or a syntax error?

A solution is to use another syntax. Maybe orelse like Zig? Or maybe or? or just else.

Non-null Assertion Operator (also known as unwrap)

There should be a way to unwrap an Option<T> if you know that is safe. Swift and TypeScript use a postfix ! for this and Kotlin uses !!.

Try block

I’d like to have a try block to scope how far the ? operator returns:

let z = try {
   let x = foo()?;
   bar(x)
};

Other operators

Here are some more options that I don’t feel like we need. But if I’m wrong feel free to leave a comment.

Safe navigation operator

This is essentially a map operator for field access and method calls. Example:

x?.y

We can’t adopt this directly because ? has the Rust meaning of “return on None”.
.? would technically be unambiguous, but in practice too close to ?..

I generally dislike this operator because it tends to appear a lot in chains. For example:

foo?.bar?.baz?.quux

I’d then rather have:

try { foo?.bar.baz.quux }