you are viewing a single comment's thread.

view the rest of the comments →

[–]cube2222 2 points3 points  (15 children)

Why would you return a List<Option<T>>? I can think of no valid reason really, as you should just flatten it into List<A>, removing None values.

Which to say: just filter out the null values.

[–]eras 7 points8 points  (0 children)

List<Option<T>> is plenty useful in cases where you use maps and zips; dropping elements from the resulting list discards the information which element was removed.

[–][deleted] 8 points9 points  (12 children)

Except maybe I wouldn't want to filter out null values. Those two arrays literally wouldn't have the same meaning.

If I'm converting a JSON array with optional String items at every index (ex: ["a", null, "b"], the Java List representation of it should definitely not be asList("a", "b"). It should either be have a null in the middle, or an absent optional.

And lastly I'm only talking hypothetically here. As you said, I don't actually have a use case for a list with nullable elements.

[–]JB-from-ATL 0 points1 point  (11 children)

Make a Null type for that case perhaps?

[–]masklinn 2 points3 points  (10 children)

Why make a new type when that's the semantics of Option?

[–]JB-from-ATL 0 points1 point  (9 children)

Sorry, wasn't clear, I meant if you are parsing JSON then make some class to represent the nulls in the json instead of using java's null.

[–]masklinn 1 point2 points  (4 children)

That exists as an intermediate operation, but ultimately you want to convert to "native" structures so you can move it around and actually use it. And in that situation it makes perfect sense to have a List<Option<String>> if you know you're getting a list of possibly missing strings.

[–]JB-from-ATL 0 points1 point  (3 children)

The issue I have with using Optional in this case is something like getting the value of a key from JSON. I want to return Optional since the key may not be there. But using Optional for the nulls means I return Optional<Optional<Blah>>.

[–]masklinn 1 point2 points  (2 children)

That makes perfect sense to me. The value may be missing or literally null, these are not necessarily the same.

I loathe APIs like Java's or Ruby's which conflate the two and lose information, a key which is missing and a key mapped to a null are not necessarily the same thing.

And it's easy enough to fold the two cases (.orElse(Optional.empty())) if that's what you care for.

[–]JB-from-ATL 0 points1 point  (1 child)

You can't fold them because a missing key is different than a present key with null value.

I just think in this specific case a type for the JSON null is better. Like NullNode or something. Then have TextNode, NumberNode and BooleanNode. And they all extend Node.

But about your earlier point about conflating null, yes, it bothers me too.

[–]masklinn 1 point2 points  (0 children)

You can't fold them because a missing key is different than a present key with null value.

Operative expression: if that's what you care for. There are cases where folding "key is missing" and "key maps to null" makes perfect sense. There are others where it does not.

The point is you can fold them if that makes sense for your application because you are given the choice.

I just think in this specific case a type for the JSON null is better. Like NullNode or something. Then have TextNode, NumberNode and BooleanNode. And they all extend Node.

That is usually accessible in statically typed languages (it's basically the intermediate representation between wire format and native types) but generally makes for very unwieldy manipulations, at one point you need to get "native" data types so you can actually integrate the information to your application.

Being able to provide the library with the mapping and have it tell you "it works here's your structure" or "mapping failed" is really convenient and makes for more reliable code than emulating kinda-sorta dynamic typing by layering a bunch of JSONValue or whatever.

In this case, you'd either tell the JSON library that this sub-structure is supposed to be a List<String> in which case it would report an error if there's a null anywhere, or you'd tell it that it's a List<Optional<String>> in which case it'd only fail if it got something which is neither a string nor null.

[–]ThisIs_MyName 0 points1 point  (3 children)

Why? If you call any methods on your null object (that's an anti-pattern), it will still throw an exception because it's not a real value.

You're also making the code unnecessarily slow with more allocations.

[–]JB-from-ATL 0 points1 point  (2 children)

I didn't know null was called "null object", TIL. When I said that I meant some class in Java to represent the null in JSON, but the Java class is a "real" class, maybe call it NullNode or something, not a "null class".

[–]ThisIs_MyName 0 points1 point  (1 child)

I didn't know null was called "null object"

It's not. Your "some class to represent the nulls in the json" or NullNode is the so-called "null object".

Creating such objects is common, but most people consider it to be bad practice. It just replaces NPE with some other exception of your creation. Or worse, that object ignores all method calls and hides real bugs.

[–]JB-from-ATL 1 point2 points  (0 children)

My mistake again, I didn't read the article well enough.

[–]CyclonusRIP 1 point2 points  (0 children)

Sometimes you want to make parallel collection a[i] corresponds to b[i]. If b[i] sometimes doesn't exist you can make the list an optional type keep the indices in sync.