ObservableValue.map special-cases the null value

Michael Strauß michaelstrau2 at gmail.com
Thu May 18 17:05:16 UTC 2023


Hi John,

the `isPresent()` and `isEmtpy()` methods don't feel entirely natural
to me. I think the problem is that Optional has slightly different
semantics compared to ObservableValue. An Optional either has a value,
or it doesn't. The "it doesn't have a value" state doesn't feel
exactly equivalent to "having the null value", since no Optional API
will ever expose the null value. In contrast, ObservableValue will
happily expose the null value.

While the map(...).orElse(...) combination is sufficient for some
scenarios, it doesn't allow to disambiguate the case where map()
returns `null` from the case where map() was elided because the input
argument was `null`. That's where mapNullable() would be materially
different. But I acknowledge that this is an edge case.


On Wed, May 17, 2023 at 3:08 AM John Hendrikx <john.hendrikx at gmail.com> wrote:
>
> Hi Michael,
>
> As you're only trying to map to true/false, it is a bit ugly to do this
> I suppose:
>
>        nullableValue.map(x -> true).orElse(false);
>
> I've encountered situations like these before, where you only want to
> know about the presence of a value, and don't care what the value is.
> If there are sufficient use cases, we could consider adding a method for
> this.  Instead of `mapNullable` though I was thinking more along the
> lines of `isPresent` and `isEmpty`:
>
>        ObservableValue<Boolean> isPresent();  // true if not null
>
>        ObservableValue<Boolean> isEmpty();  // true if null
>
> So far I didn't think it would be warranted to add such methods, but
> they're trivial to add.
>
> On 17/05/2023 00:25, Michael Strauß wrote:
> > I'm trying to map an ObservableValue such that `null` is mapped to
> > `false` and any other value is mapped to `true`. The following line of
> > code should do the trick:
> > ObservableValue<Boolean> mappedValue = nullableValue.map(x -> x != null);
> >
> > It turns out that this doesn't work, since `map` doesn't pass `null`
> > to the mapping function. Instead of calling the mapping function, it
> > always returns `null`. This is not technically a bug, as `map` is
> > specified to have this behavior. It is a bit unfortunate, though;
> > `null` is a perfectly valid value in many cases and its special
> > treatment comes off as a bit of a surprise.
>
> The alternative is worse I think, as JavaFX properties can easily be
> `null`, you'd have to add null checks to your map/flatMaps. Especially a
> construct like this:
>
>        node.sceneProperty()
>            .flatMap(Scene::windowProperty)
>            .flatMap(Window::showingProperty)
>            .orElse(false);
>
> ... would be really annoying to write if you had to deal with the
> nulls.  The functionality is closely related to what Optional offers,
> and that one doesn't pass `null` to its map/flatMap methods either, nor
> will it ever add a `mapNullable` :-)
>
> > I'm wondering whether we need a `mapNullable` operator that does what
> > I intuitively expecting `map` to do, which is just unconditionally
> > passing the value to the mapping function.
>
> Maybe, I think however that you'd only need this for the very special
> case where you are intending to ignore the actual value being passed to
> a map/flatMap, and only want to check it for null.  `isPresent` /
> `isEmpty` would be nicer for this.  For all other cases, where you are
> actually doing some kind of mapping, I think a map/orElse combo works great.
>
> --John
>


More information about the openjfx-dev mailing list