Live data from Hacker News

Java 8’s new Optional type doesn't solve anything

medium.com

131–140 of 197 posts

Re: Java 8’s new Optional type doesn't solve anything

#131

I've only used the Guava version of Optional, which appears to have a slightly different API than Java 8's. (You can tell there's a Java 8 committee, that's for sure.) The biggest problem I found in applying Optional is that Optional is very much a Haskell-y concept to me, and Java programmers and Haskell programmers don't really overlap much. Therefore, to me, Optional is just a functor like a list or a set. So doin…

It always bothered me that Java8 and Guava optionals don't just implement Iterable. There must be a good reason for this, and I'm guessing they're worried about confusion when you have an `Iterable>` but still, it'd be really nice to be able to just write

   for (T result : potentialResult ) {
      //...   
   }
I agree with you, that just seems so much more idiomatic than

    if (potentialResult.isPresent()) {
       T result = potentialResult.get();
    }
But maybe it comes from my mental model of Optional being a 0- or 1-length collection. It's at least definitely treated as a functor in that for pure functional operations, you have .map (or .transform for Guava).

Re: Java 8’s new Optional type doesn't solve anything

#132
post #80

Earlier quoted context omitted.

>Gonna have your function return an Err if an internal invariant is broken? Absolutely you should return an error. Whether the caller wants to panic or handle it or print unicorns should be left up to the caller, not your function. Functions should not be expected to tear down the thread in case of an error. Nothing that panics should belong anywhere in exported code

The idea is that Err is good if it's a recoverable error, but if it's not recoverable, you should panic!. Most errors are recoverable. panic! is an antipattern in a library. Or at least, provide both a panic-ing and a non-panic-ing variant.

The problem is that a function cannot know whether or not the caller can recover from a particular error, so there's no point in making that distinction in the first place.

Re: Java 8’s new Optional type doesn't solve anything

#133
post #116
post #45

Earlier quoted context omitted.

>tl;dr: Haskell, Rust, et al. put the burden on the compiler. Java puts the burden to ensure safety on the programmer. (As can be witnessed in your snippet.) Actually, (much to my disappointment as I'm just learning rust) you can just take an Option or Result and .unwrap() and the compiler won't complain at you for not checking it. For such a "safe" strongly-typed language, I'm surprised that so much new rust code do…

>Actually, (much to my disappointment as I'm just learning rust) you can just take an Option or Result and .unwrap() and the compiler won't complain at you unwrap() is a convenience method that still uses exhaustive pattern matching and will panic if no value is present. The developer is making a conscious decision to panic in a not-present scenario, and on a case-by-case basis. The compiler is still doing it's job.…

The distinction is there but the runtime behavior is not remarkably different. This feels more like a philosophical argument with no real purpose, to be honest.

Re: Java 8’s new Optional type doesn't solve anything

#134

Earlier quoted context omitted.

> you can just take an Option or Result and .unwrap() and the compiler won't complain at you for not checking it. Explicit vs implicit. In Rust/Haskell you are forced to do _something_ about the nullability. If you use unwrap/expect/fromJust you are explicitly acknowledging that you want it to panic if it fails. On the other hand, in Java, you can get an NPE where you didn't expect it because nulls move around easily…

> If you use unwrap/expect/fromJust you are explicitly acknowledging that you want it to panic if it fails. If you use Optional.get() without Optional.isPresent(), how is that any different? It's not as nice as pattern decomposition, but it's still fundamentally the same, and on top of that, transform functions are provided so that most of the time you can do null-safe operations.

The difference is that Optional itself can be null, and in Java everything can be null.

Re: Java 8’s new Optional type doesn't solve anything

#135
post #19
post #5

The lack of pattern matching doesn't make it useless. The existence of Optional reminds the programmer to check whether the value is present, and the type system does enforce this; you can't accidentally treat an Optional as a reference of the same type. The type system does help us remember to handle things; it is a reminder enforced by the type system that's easy to examine during code review. Yes, you can write ge…

Exactly, it forces the programmer to think about whether something can be null or not and actually had a behavioural change in my java coding.

Every reference in Java can be null. You should be thinking about it all the time.

It's the Java language that forces you to think about nulls, not Optional.

Re: Java 8’s new Optional type doesn't solve anything

#136

Earlier quoted context omitted.

Care to explain why? Whatever unwrap provides can be done with a match+panic. Which is more explicit, but that's just splitting hairs -- unwrap is pretty explicit anyway.

I understand the anger but at the same time I don't. Overall unwrap() isn't good. Really it should be replaced by TODO WRITE ERROR HANDLING in 90% of its cases. That being said there are still good uses for it. The main _safe_ use for unwrap() I find is when dealing with an iterator of Results/Options (which seems to happen a lot). The pattern: .filter( |x| x.is_some() ) .map( |x| x.unwrap() ) Is safe, and I really d…

In Swift you can solve this with a filterNone() method with an explicit type signature of [T?] -> [T], I assume that could also be implemented in Rust?

Re: Java 8’s new Optional type doesn't solve anything

#137
post #5

The lack of pattern matching doesn't make it useless. The existence of Optional reminds the programmer to check whether the value is present, and the type system does enforce this; you can't accidentally treat an Optional as a reference of the same type. The type system does help us remember to handle things; it is a reminder enforced by the type system that's easy to examine during code review. Yes, you can write ge…

Java 8 Optional is useful (although the API could be better). If only FindBugs would warn about calling get() without checking isPresent() first. There's an open FindBugs ticket for this: http://sourceforge.net/p/findbugs/feature-requests/302/

That is the old bug tracker. An issue was submitted on the official tracker and immediately closed. See https://github.com/findbugsproject/findbugs/issues/56 for explanation.

Re: Java 8’s new Optional type doesn't solve anything

#138

Earlier quoted context omitted.

> If you use unwrap/expect/fromJust you are explicitly acknowledging that you want it to panic if it fails. If you use Optional.get() without Optional.isPresent(), how is that any different? It's not as nice as pattern decomposition, but it's still fundamentally the same, and on top of that, transform functions are provided so that most of the time you can do null-safe operations.

The difference is that Optional itself can be null, and in Java everything can be null.

It can be, and it's annoying, but that's still a step forward. It's trivial for a good static checker to treat all Optional references as if they were annotated with your favorite @Nonnull annotation.

Re: Java 8’s new Optional type doesn't solve anything

#139
post #89

Earlier quoted context omitted.

>Yes, you can write get() and risk an exception. So don't do that. Yes, you can dereference a null pointer and risk an exception. So don't do that. See where this is going? The problem with Java's optional is that it is by all appearances (in name and high-level description), a general purpose optional, albeit with a ton of gotchas that will result in people saying "Just don't do that." Java's optional is not a gener…

>>Yes, you can write get() and risk an exception. So don't do that. >Yes, you can dereference a null pointer and risk an exception. So don't do that. Except these aren't at all the same. With a reference, you have no good way of telling whether your reference IS nullable. With Optional, it's ALWAYS optional. Therefore it is trivial to a) train developer habits to always check before fetch, and b) enforce an isPresent…

>Except these aren't at all the same. With a reference, you have no good way of telling whether your reference IS nullable.

As the article mentions, we have annotations to do just that.

>Therefore it is trivial to a) train developer habits to always check before fetch, and b) enforce an isPresent check with static checks.

Again, if we're using static analysis to verify the correct use of Optional, why are we using optional at all? Why wouldn't we use static checks to verify null references can't be dereferenced, instead of hypothetical yet-to-be-implemented static checks that may not be implemented anyway? See https://github.com/findbugsproject/findbugs/issues/56

Re: Java 8’s new Optional type doesn't solve anything

#140
post #77

Adding my voice to the din of people noting how far afield of the point the author is: You should almost never call .get(), except in cases where the code path does not allow an empty optional. Even so, calling .get() on an empty optional is better than handing nulls around. A null may -- by chance, really -- make it several lines down the code, so that the stack trace points you much later in the code than where the…

Nulls can be particularly pernicious in Java because of auto-unboxing. E.g., imagine you got a NPE from this: String summary = getUserSummary( user.getId() ); ...you'd think "user" must be null, right? But it's quite possible that user.id is a Long, the current value is null, and getUserSummary() requires a long primitive argument. This compiles just fine, and at runtime the Long object will be auto-unboxed to a prim…

I had a fun one with this once. It looked something like this, using your `user.getId` method:

    int userId = p ? 0 : user.getId();
We spent a few hours staring at this trying to figure out why there was a `NullPointerException` on a line dealing with `int` values. Eventually realized that `thing` was really an `Integer`, causing the entire trinary to be an `Integer`, which was then being unboxed to an `int`.
Post reply on HN