Optional Types and Leaf: Removing automatic dereference

Optional values are one of the fundamental extrinsic types in Leaf, as are shared values. Originally optional values were used just like regular values, dereferenced automatically. I was always uncertain of that. It made the code simple but it didn’t hold up to a promise of safe code. It was essentially a null pointer error in disguise. I’ve since removed the automatic dereferencing.

Quick syntax introduction

Optional values can be created using the ? operator. Unlike the traditional cond ? true_val : false_val ternary operator, Leaf splits this up into two fundamental operators.

var a : integer = 5
var b = cond() ? a

The above creates an optional integer value, either it is 5 or unset.

var c = b | 10

The | is a default operator. The above expression will be the value of b if set, or 10 if not set. Together these look like the traditional ternary operator:

var d = cond() ? 5 | 10

If cond() is true then d == 5 otherwise d == 10. By splitting up the syntax we get the more generic ? and | operators. These help integrate optional types fully into the language.

Type declaration

The syntax for declaring an optional in Leaf is simply add optional to the type:

var a : integer optional
var b : pine optional

It can also be added to an inferred type, for example in the case of a parametric function that can take any optional argument:

defn leaf = ( a : optional ) -> { ... }


Originally I had the language automatically derefernce optionals. In the below function the optional arguments could be used directly.

defn leaf = ( a : integer, b : optional integer ) -> {
    return a + b

The same could be done for fields in a class or tuple.

typedef point : [
    x : integer
    y : integer

var p : optional point

The above would raise an error since p has no value (the default of any optional type is to not have a value).

As convenient as this was, it started to feel like it was just hiding errors. I decided this automatic dereferencing should be removed.

Using the | operator

The | can be used to avoid any explicit dereferncing.

defn leaf = ( a : integer, b : optional integer ) -> {
    return a + (b | 5)

The expression b | 5 will use the value of b if available, or 5 if it is not set. This is the desired way to work with optionals. The compiler doesn’t let you ignore the fact that b may not be defined, thus no error is now possible.

The future ?. operator

It’s not quite complete when dealing with fields however:

var p : optional point
str.print( p.x | 5 )

This will still raise an error as p.x cannot be resolved. Without a terse way to deal with this we’d end up with syntax bloat on optionals. I am going to add an optional operator ?. to deal with this:

std.print( p?.x | 5 )

p?.x evaluates to the value of x if p has a value, otherwise it evalutes to an optional unset value. This will work in a chain as well:

std.print( a?.b?.c?.d | 5 )

Explicit dereference

There are some situations where an explicit dereferencing of the optional are required. For that I added the unopt operator.

has(p) then std.print( unopt(p).x )

unopt(p) raises an error if p is not set, that’s why I check if with has(p) first. I’m not entirely certain of the name unopt yet, and it might still be changed. I just wanted to start with an unambiguous name.

2 replies »

  1. Can you nest optional values? Like option of option of option … of int? You mentioned “shared values” but I cannot find relevant post, so did you write about it already? If yes, I would be grateful for the link :-).

    • There is no way to apply the same extrinsic modifier twice to an intrinsic type, so no double `optional`. You can however create a tuple with an optional and have the whole tuple as optional: `[ x : optional int ] optional`.

      I don’t think I wrote about `shared` here yet. I’ll try to write something soon.

Leave a Reply to macias Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s