Sugar for Option type?


#1

My rust code is littered with Option<Blah> and Some(myblah)'s and it feels noisy for something so common. Has there been any discussion about adding some sugar? E.g. Blah? and myblah (Jonathan Blow mentioned this a while ago IIRC but I didn’t see any serious discussion)

Cheers,

Phil


#2

I think that adding sugar for Option specifically would be a bad idea. Result is even more useful/used than Option, and Option can even be implemented in terms of Result, but not vice-versa.

But I have thought about this. After reading glaebhoerl’s RFC on exception handling, I realised that having separate bool, Option, and Result types is unnecessary, as Option<T> can be represented as Result<T, ()>, and bool can be represented as Result<(), ()>. Unfortunately, bool is fundamentally built-in to the language, and so it could not be replaced with a library type. So why not make Result a language type, and get some nice sugar at the same time?

I came up with two possible syntaxes:

  • Give bool two type parameters, each defaulting to (), and make true and false callable. This means that bool stays the same, Option<T> becomes bool<T>, Some(e) becomes true(e), None becomes false, Result<T, E> becomes bool<T, E>, Ok(e) becomes true(e), and Err(e) becomes false(e). The main problem with this is that true(e) instead of Some(e) seems strange.

  • Add a new built-in type, T?E which replaces Result<T, E>. Either of T or E can be omitted, defaulting to (), so Option<T> becomes T?, Result<(), E> becomes ?E, and bool becomes ?. A big problem with this is that it looks very cryptic: ? seems quite strange for a Boolean type. I’m also not sure how to represent values in this system: perhaps yes(e) and no(e), or maybe true(e) and false(e).

But this is just a silly pointless idea, really: such a drastic change to bool &c. would be too big a change at this stage. I don’t find the current syntax that verbose.


#3

There’s RFC PR #402 which might even lend itself to writing Option<T> as T | ()


#4

bool only has to be a lang item (so that e.g. ifelse can know about it), but not necessarily a built-in type. (Alternately Result could be a lang item.) We could do all of this:

type bool = Result<(), ()>;
const false: bool = Err(());
const true: bool = Ok(());

type Option<T> = Result<T, ()>;

For None we would need generic constants:

const None<T>: Option<T> = Err(());

which is not too bad (we will probably grow generic constants at some point). But for Some, we would need some kind of value-parameterized constants:

const Some<T>(x: T): Option<T> = Ok(x);

which seems like a much bigger lift. Compile-time evaluable (C++ constexpr) functions wouldn’t be enough, because it also has to work in patterns.

If we had all of that, one thing I’m not totally sure of is whether everything would work out smoothly with respect to trait impls for these types.

(As an aside, this functionality corresponds to (a subset of) GHC’s recent PatternSynonyms language extension.)


#5

A boolean value of false doesn’t necsesarily mean we get an Err.


#6

You’re quite right.

Result with Ok(a) and Err(b) is actually a special case of a more general boolean type, that is either Affirmative(a) or Negative(b), which itself is an interpretation of an Either<A, B> type.


#7

For the record I wasn’t concerning myself with names, only structure, and for the sake of demonstration I used the existing types because they exist. Interpretations are subjective.


#8

“Result is even more useful/used than Option…”

It hasn’t been my experience that Result is used more than Option. E.g. even in the rust repo with all its io library code:

/rust$ find src -name "*.rs" | xargs grep Option | wc -l
3052

/rust$ find src -name "*.rs" | xargs grep Result | wc -l
2402

Anyway my point was more about the syntax. if I’m writing code and a function returns Option<MyType>, I’m primarily interested in the 'MyType’ness of the type, and the 'Option’ness is secondary. The ‘MyType?’ sugar conveys this balance more accurately IMO

Cheers,

Phil