Hacker News new | ask | show | jobs
by gnosek 2021 days ago
I agree with all your other points but

> > We can’t perform arithmetic on an Option<int> any more than we could on a List<int>.

> Why not? One sensible definition is (...)

It's not the only sensible definition. It would be equally sensible to implement it as:

    Some(x) + Some(y) => Some(x+y)
    Some(x) + None => Some(x)
    None + Some(y) => Some(y)
    None + None => None
3 comments

It really depends on what the meaning of None is. OP's definition makes perfect sense if it means "unknown". Yours make sense if it means "zero", but that's far less useful. If it means "missing" - which is what the article says they wanted - then any operation involving None should be an error (but Some can still be handled automatically).

It can be interesting to see what other languages do in this situation. For example, C# got nullable value types in version 2, and had to decide what to do with operators in a similar vein (including pre-existing overloaded operators in user code) - they called it "lifting":

https://docs.microsoft.com/en-us/dotnet/csharp/language-refe... https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...

You might notice that it almost, but not quite, has consistent semantics: null means "unknown", which is particularly obvious from Booleans: (true | null) is true, and (false & null) is false, but (true & null) and (false | null) are both null. However, comparison operators aren't consistent: you'd expect x == null to be null if it meant "unknown", but the language will always give you either true or false; and ditto for relative comparisons. This last one means that it's possible for (x == y), (x < y), and (x > y) to all be false.

What's interesting is that, in practice, it's rare to see reliance on any of this behavior in idiomatic C# code - "null" is usually used as "missing", not as "unknown", so all this magic is, at best, irrelevant, and at worst, actively harmful (because it defers a logic error).

> It really depends on what the meaning of None is.

Exactly. This will generally be application specific so we can't choose The One Right Definition for adding `Option<i32>`s.

> Yours make sense if it means "zero", but that's far less useful.

Not in my experience but I agree there are different situations. Personally, I'd default to `Option<i32>::None` meaning "no number there, so just skip it"[1] and prefer `Result<i32, E>::Err` to denote "there should be a number here but we don't have one", which would behave like a SQL NULL (propagate in all calculations).

1. What's the length of data in a header-only packet? I wouldn't say it's zero, especially when trying to fit a read() like API on top of a framed protocol (read() returning Ok(0) marks the end of file).

> > > We can’t perform arithmetic on an Option<int> any more than we could on a List<int>.

Is actually kind of a weird point to make. There are number of ways to add together List<int> including:

    listA.zip(listB).map(([a, b]) => a + b);
Similarly adding together two optionals could be done with:

    optionalA.zip(optionalB).map(([a, b]) => a + b);
Or if you would rather:

    optionalA
      .zip(optionalB)
      .map(([a, b]) => a + b)
      .or(optionalA)
      .or(optionalB)
> It's not the only sensible definition

Right, which is why I said it's just one sensible definition. :)

Although I guess there's at least two sensible definitions of arithmetic on List<int>, too.