Skip to content

Instantly share code, notes, and snippets.

@rsslldnphy
Last active December 18, 2015 23:39
Show Gist options
  • Save rsslldnphy/5862686 to your computer and use it in GitHub Desktop.
Save rsslldnphy/5862686 to your computer and use it in GitHub Desktop.
GAAAAAAVVVIIIIIIIIIIIINNNNNNN!!!!!!!
## Making Option[[]], Option[{}] and Option[""] return None
Looked at a certain way, it does make a kind of sense. I can see how you got the idea.
A None is itself a kind of empty collection, so why wouldn't an Option of an empty collection also be a None?
However, I think there are some important things we need to consider.
The first one is - why would you be creating an optional collection - what value would you be getting from doing so?
And what value would you be getting from empty collections being interpreted as None?
You might want to only do something if there are elements in the collection.
But iterating over an empty collection will achieve this anyway.
You could conceivably want to do just one thing if the collection has at least one elements,
and nothing or something else if it has none.
This is easily and more readably (I would argue) achieved just using a conditional - even though I hate conditionals.
However, if you really wanted to do it with Options, you could do something like this:
Option[my_collection_which_may_be_empty].reject(&:empty?)
or
Option[my_collection_which_may_be_empty].select(&:any?)
So there is nothing you can do with a None that you can't already do with an empty collection.
Kind of by definition, because a None *is* an empty collection.
What about the way it is - with a difference between a Some[empty_collection] and a None?
Does that bring any benefits?
One case I can think of is allowing you to distinguish between information you *don't know*,
and information you do know - but that happens to be empty.
So for example, suppose you have a Customer model, and there's a part of your system that works out
what vouchers a customer of that age, with that total spend etc etc is entitled to.
Calculating the vouchers is an expensive process so you only do it when you need to,
and you cache the result in a big Hash (keyed on age and total spend to the nearest £100,
because customers with the same combination get the same set of vouchers, so there's no need
to do the calculation multiple times).
You decide to represent the set of vouchers in the hash as an Option.
It's a Some if the vouchers have been calculated, it's a None if they haven't.
That way, when you look in the hash for the correct vouchers and you get a None,
you know you have to kick off the voucher calculation process.
But some sets of customers are not eligible for *any* vouchers.
You only know this, however, after you've done the calculation.
So you want to store this in the hash.
But if Option[[]] evaluates to None, the next time you look in the hash there's no way to tell
if you've done the calculation or not.
You just get None regardless of whether the calculation has been done and returned an empty collection,
or if the calculation has never been done.
But if there's a difference between a None and a Some[empty_collection], you can distinguish between
*not having a collection* and *having an empty collection*. Which is an important difference.
That's why I say there's a difference between an empty bucket and the absence of a bucket.
You can fill an empty bucket with sand - but you can't fill the absence of a bucket with anything.
They are fundamentally different things.
Another issue is that if you make Option[empty_collection] evaluate to None, you cannot get this distinction back.
There is no way to represent Some[[]] if you need it.
However, if Option[[]] => Some[[]], but you happen to *need* Option[empty_collection] to evaluate to a None,
you can simply use the select or reject shown above to turn it in to one.
So this way, both ways of using Options work. The other way, and one of them is impossible.
Having said all this, I'm really pleased that you're interested enough in Options to be submitting a pull request!
It's really nice and exciting to receive one.
It is in fact the first pull request I've had, too. So I'm genuinely sorry I disagree with it! Sorry Gav!
I do have a suggestion that you could look at though, if you're interested?
There's a very similar thing to Options that is also used in Scala and Haskell and that sort of language,
called an 'Either'. Have you come across it? Worth a google.
Anyway, I thought it might be nice if there was a companion gem to optional that implemented the Either type in Ruby.
Then we could think about creating a gem that brought a number of Ruby implementations of functional structures
together as a collection. Options, Eithers, maybe even some other crazy monads!
What do you reckon? Fancy having a go at it???
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment