Maybe an Enum
July 23, 2018
Last time we implemented an optional as a list that contained zero or one elements of a generic type.
This time we'll re-implement optional in a more standard way using enums and add some behavior beyond the map() and filterMap() methods we implemented last time.
This time we implement an optional using an enum with two cases none and some where the some case has an associated value keeping the wrapped value of the optional.
I know - what a horrible way to describe it. I'm assuming that optionals aren't new to you and that we're just playing with a possible implementation.
Last time we had simple inits for creating an instance that was nil or non-nil. We do that again along with computed properties for value and isNil and description.
I'm not happy with the fatal error being thrown in value.
We'll revisit that later.
For now, we can take this for a test drive using the echoEvenOrNil() method from last time.
The results are Opt(2) and nil as expected.
Let's continue with the output of echoEvenOrNil and see if the result is an optional wrapping a value that is divisible by 3.
This time we'll define filter() for Opt.
Now we can define a closure that returns true if an int is divisible by 3.
We can now filter the results of calling echoEvenOrNil and get only those numbers that are divisible by 6.
We get nil, nil, and Opt(12).
What about feeding the result of echoEvenOrNil into this function that halves ints?
The output of echoEvenOrNil is Opt<Int> and the input of halve is Int. We need map(). Here's how we implement map() for Opt. We can't use List as we did last time since this Opt doesn't build on List.
There are lots of ways to implement map(). Here's one.
We can use it the same as we did last time.
For our flatMap example I introduced a dictionary and a simple lookup function:
Here's how I'm implementing flatMap(). The key, as it always is for flatMap is that the function already returns the type that we want.
We use it the same as last time and get the same results.
I asked a dumb question on Twitter this morning and @nicklockwood, @jesseMeow, and @jl_hfl were so nice in response that I'm adding the following material to this post.
Let's implement the nil-coalescing operator for our optional.
This turns out to be a handy device that says, "unwrap this guy and use it if it's not nil - and if it is nil, use this default value instead."
Let's start with the method version of this:
We can use it like this.
This returns the default value -1 in the first case and 2 in the second.
We can overload the same symbol that Apple uses for the nil-coalescing operator: ??.
We use it like this:
Pretty cool - huh?
OK, next time we'll look for a type that lives somewhere between throwing an error and our optional type. It is known as the either type in many languages or the result type.