nlkl / Optional

A robust option type for C#

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Should .Map return None if mapping returns null?

JudahGabriel opened this issue · comments

I was surprised by this behavior:

var obj = new { ThisIsNull = (string)null };
var result = Option.Some(obj)
       .Map(o => o.ThisIsNull)
       .ValueOr("hello");

Expected: "hello"
Actual: null

Isn't this unintuitive behavior? Looking at Java 8's Optional and Rust's std::Option, the result of .Map is None if the mapping produces null.

I realize we can get this functionality with .Map(...).NotNull(), however, the existing behavior remains unintuitive. Thoughts?

Hi,

This is actually by design. You can find some more details here: #14

The argument basically boils down to optionals behaving consistently (e.g. under refactorings), and the unfavorable "value/complexity ratio" of introducing a special case for nulls.

It is true that Java disallows null inside an Optional. Rust, however, doesn't really have the concept of null, so it cannot be directly compared. A more direct comparison would be with Scala and F#, which both allows nulls inside an Option.

/Nils

Your documentation and your reasoning are quite clear-headed! I figured it was a deliberate design choice.

Let me see if I understand your reasoning for this decision:

  1. Filtering nulls in the library will introduce complexity into the library itself.
  2. Consistency; inverted operations would no longer return the same result. val.Some().Map(mapping) != mapping(val).Some().
  3. Doesn't solve all cases of null: users can still make null happen given .Chaining.Null.Value.

If I understand you right, I'm still in favor of filtering nulls. To respond to the above:

  1. True! But we users don't care about your complexity. We care about making our code simpler. :-) The library filtering out nulls makes our code simpler.
  2. The consistency argument doesn't matter to me. I've never thought, "Gee, I wonder if changing the order of operation here will affect the output" - rather, my intuitive expectation is that yes, the output may change if the order changes. This is a non-issue to me.
  3. Just because we can't fix the world doesn't mean we can't make it a little better. :-) As a user, I would not expect .Chaining.Null.Values to work. But I would expect .Map(o => o.NullVal) to be None.

Overriding these is the surprising behavior of allowing nulls into an Option, and "lying" that .HasValue is true. That's unintuitive as a user, particularly for a library intended to deal with the problem of null values.

That's my feedback. This is a great library, and I'll still use it regardless. 👍

Closing this one for now. Feel free to re-open or open a new issue, if something pops up.