
Java 8’s new Optional type doesn't solve anything - lelf
https://medium.com/@bgourlie/java-8-s-new-optional-type-is-worthless-448a00fa672d
======
jcrites
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 get() and risk an exception. So don't do that. I'm still
glad get() is present because there are times when the human knows the value
will always be present, but sometimes in a way that can't be encoded in the
type system. Alternatively, sometimes an absent value is an error and get() is
an acceptable way to check-and-throw.

I agree with the suggestion that static analysis can be useful, though many
users had that already with FindBugs or Fortify. If we're talking about
annotations based analysis, then it only goes so far. Optional and streams
provide useful new tools for documenting intentions from my perspective.
Another reason I enjoy the type is because it makes it a little more
reasonable to say that, at least in new code, all references are nonnull
references by default, since they'd be Optional otherwise.

~~~
jontro
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.

~~~
MereInterest
Wouldn't it be better to have a non-nullable type, akin to C++'s return by
value? That way, instead of forcing the programmer to think, you are removing
the problem that they would need to think about.

~~~
hibikir
In other languages that use Option types more natively, like Scala, anything
that isn't optional is assumed to just not be null: The compiler doesn't
guarantee it (it's not as if it can, we are dealing with a JVM here) but it
works in practice. I've not seen a NullPointerException in years.

Option has other advantages, like its compositional qualities (thanks to
Option being a monad). So imagine the following code

def foo(x:Option[String]) = x.filter(_.length<10).map(_ + "More data")

If the function returns None if it receives either None or a string longer
than 10 characters, and if we got Some("short "), foo will return Some("short
More data"). The alternatives without an option type, involve at least a
couple of branching statements, even if you have a non nullable type, to
convert from nullable to not nullable, while Option does it all for us.

~~~
the_af
> _I 've not seen a NullPointerException in years [in Scala]_

This sounds odd. Does your code never interface with Java libraries and
frameworks? I envy you! It's all too easy to forget to wrap a suspect value
from Java-land with an _Option(..)_. And cumbersome even if you do remember.

And then, there's the code written by Scala novices who just love using nulls.
Yes, yes, "code reviews", we all know they are always practiced all the time
:/

~~~
mark242
The Scala landscape is very, very quickly creating their own libraries for
similar popular Java libraries/frameworks. It is entirely possible to create
an application, web or otherwise, that uses no Java libraries at all (save for
the sbt dependency tree).

As for "Scala novices who just love using nulls", if you're seeing that, then
the coder in question missed day 1 of Scala training, which is always "if you
are writing the word null, you are doing something wrong" (right up there with
"if you are writing the word var, you are probably doing something wrong").

~~~
the_af
Maybe, but if true that's still in the future. The OP claimed they hadn't seen
a NPE "in years", which simply doesn't match my own experience.

As for novices: yes, novices tend to do that. They tend to miss, misremember
or fail to put into practice what they should have learned on day 1. I've also
seen senior devs who were not exactly newbies (in general) still using nulls
because they don't grok Scala; the famous "you can program Fortran in any
language". The _reality_ of software development is that you have to deal with
all these people.

------
ubertaco
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
null originated. Calling .get() on an empty optional _immediately_ throws a
NoSuchElementException, pointing you directly to the line where the optional
was empty where it shouldn't have been.

Consider this code:

    
    
        User user = getUser();
        // other stuff here
        // ...
        // ...
        String userSummary = formatUserSummary(user);
        // ...
        // ...
    

where

    
    
        public String formatUserSummary(User user){
            return "Franchise Location: " + 
                user.getFranchise().getLocation().getName() + 
                " Username: " + 
                user.getUsername();   
        }
    

An NPE occurs inside of formatUserSummary. Where did the null come from? Is
the user's Franchise null? Maybe the Franchise's Location? Or is it the User
that's null?

If you instead took an Optional<User>, _even if_ you just immediately
unwrapped it with .get(), you'd at least get an error that unambiguously told
you that it was the user that was missing.

~~~
ucho
> Where did the null come from?

A bit offtopic but SAP JVM puts that info in NPE error message[1], I don't
know why others implementations don't, maybe it is incurring too large
overhead?

[1] it is something like "Attempted to call getLocation() on Franchise object
returned from getFranchise() but it was null"

~~~
Ygor
Interesting, first time I heard SAP has a JVM implementation.

[https://scn.sap.com/people/desiree.matas/blog/2011/12/07/sap...](https://scn.sap.com/people/desiree.matas/blog/2011/12/07/sapjvm-
overview)

Here is a presentation with some interesting points, wonder if anyone has any
real-life experiences?

[https://www.youtube.com/watch?v=arryAs9lqfE](https://www.youtube.com/watch?v=arryAs9lqfE)

------
Kwastie
The author is missing the point. The fact that Optional can result in a
nullpointer doesn't mean you should use in the same manner as null-checks.

You _shouldn 't_ replace:

    
    
      if(x == null)
      {
        y = x.doSomething();
      }
    

with

    
    
      if(optionalX.isPresent())
      {
        y = x.doSomething();
      }
    

You should replace it with:

    
    
      y = Optional.ofNullable(x)
        .map(ClassX::doSomething)
        .orElse(null);

~~~
danieldk
_The author is missing the point._

Is he? The point is that in Java you are still able to treat x unsafely, while
languages with stronger typing do not. E.g. in Haskell, if a function returns
a _Maybe a_ , it will always be a _Just a_ or _Nothing_ value. Moreover, such
languages allow you to make non-exhaustive matching against all constructors a
compiler error.

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.)

~~~
krisdol
>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 does this when:

* the developer believes the Option/Result can never be None/Err (oh come on, just wait until you refactor your code a bit one day and miss a spot)

* the code is example code (I've had little luck finding "good" examples sprinkled about github)

* the developer is lazy (see above)

Allowing unsafe unwraps defeats a core purpose of rust, and the unwrap method
shouldn't even exist in the API.

~~~
markus2012
I completely agree. unwrap() is a huge mistake in Rust. There are brilliant
ideas implemented in Rust (primarily the borrow checker) but their advantages
seem to be wiped out by the kludge of unwrap.

~~~
Manishearth
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.

~~~
valarauca1
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 don't know a more eloquent method of handling these
operations.

~~~
Manishearth
I'm not angry.

> Really it should be replaced by TODO WRITE ERROR HANDLING in 90% of its
> cases.

That's what the Rust community reads it as, mostly.

I've seen it occur very infrequently in libraries (aside from
example/benchmark/test/mocking code, of course). When it does its usually for
really out of whack errors like poisoned mutexes, crashed threads, etc (mind
you, these are for unwrapping error values, not options, but it's almost the
same thing). Or for cases where it's known to be valid due to invariants that
can't be expressed in the normal way.

I did a quick grep of hyper, and the unwraps are almost all in "dev" code
(tests/benchmarks/etc). The cases where they aren't are where there was an
`is_some()` earlier (and due to some reasons it couldn't be restructured as a
match, perhaps just because of rightward drift), or the "invariants" thing --
i.e. it often calls `<some url>.serialize_path().unwrap()`, which is OK,
because hyper only ever deals with relative schemes (e.g.
`[http://`](http://`) and `[https://`](https://`), not `data:` or `mailto:` --
the latter two don't have paths), which is checked in the constructors, so
this should NEVER panic. I didn't go through all the code, but in the main
HTTP and HTTP2 code serialize_path was the only offender, which was one that
was justified.

I see it more often in applications. In the following cases:

\- Example applications in blog posts (because you want to explain something
else, not spend too much time on error handling)

\- Slightly less out of whack errors which are weird enough that they should
close the app

\- Normal errors which should close the app (e.g. "insufficient permissions"
for a command line util, or a port-opening error on a network app). unwrap()
prints out the error message so this is a very rudimentary form of error
handling anyway.

\- Laziness, or often with a TODO. Not too common.

So, it's mostly used in justifiable ways, and that's why it exists in the
stdlib. It doesn't "wipe out" anything that the borrow checker provides
(borrowchk and exhaustive match are two different things), and while it's a
kludge if used often there are legitimate reasons to use it; enough reasons to
have it in the stdlib.

> I really don't know a more eloquent method of handling these operations.
    
    
        .filter_map(|x| foo(x))
    
    

:)

(but yes, in general there are situations in which you _know_ an Option is
unwrappable, e.g. the serialize example above)

~~~
valarauca1
> filter_map(|x| foo(x))

Thanks :D

I've been really struggling to _get_ iterators in rust. I don't have a very
strong functional background :|

~~~
kibwen
Note that anytime you see a closure in any language that just takes a single
argument, calls a single function with that argument, and returns the value of
that function, then you can eliminate the closure entirely by just passing the
function instead.

So `filter_map(|x| foo(x))` can be written more simply as just
`filter_map(foo)`.

~~~
valarauca1
I know this but I can never get my code to compile when doing this. I always
seem to get huge type errors even when I know the code is correct.

    
    
         map(|x|foo(x)) //clean compile
         map(foo) //type error
    

The number of times I've had this happen has just lead to me giving up on
simply just passing the lambda as a variable instead of wrapping it in
another.

~~~
kibwen
Curious. Can you provide a full code example so that I can try to determine
what's causing that error?

~~~
Manishearth
Usually in these cases the culprit is autoderef/deref coercions.

~~~
kibwen
I don't see anything in `|x| foo(x)` that could be causing `x` to be deref'd.

~~~
Manishearth
A deref coercion can happen there

[https://github.com/Manishearth/rust-
clippy/issues/116](https://github.com/Manishearth/rust-clippy/issues/116)

------
aclissold
I've been using Swift for over a year now, which has had an Optional
implementation from day one. I see a lot of people defending Java's
implementation in this thread, can someone check my understanding? I did Java
in a past life but am not super familiar with Java 8.

In Swift, types are non-optional by default. You can never end up with a null,
the compiler makes it impossible. Optionals are out of the way until you need
them, and if you use them properly (i.e. avoid the .get() equivalent), it's
still impossible to crash from a null.

In Java 8, things can still contain null by default and you might not know
about it, right? You can express that something is Optional in your API, but
that's only marginally better than documentation, doesn't solve "unexpected
nulls" whatsoever, and makes this only halfway to a solution and therefore
broken entirely. Why not just use annotations?

Are my assumptions and understanding correct?

~~~
Lewton
I don't think anyone thinks that Optional as it is in Java right now is the
perfect solution. The article seems to be making the case that Optional isn't
an improvement of what came before, which is what people are having issues
with.

~~~
aclissold
Ah. Right! "doesn't solve anything" is definitely not the case:)

------
jrockway
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 doing Optional.asSet() and iterating over the result is, to me,
the correct way way of handling an optional value. If there's something in
there, the loop runs once. If there's not anything in there, the loop runs
zero times. This is exactly like "fmap" in Haskell:

    
    
      Prelude Data.Functor> fmap (+1) $ Just 42
      Just 43
      Prelude Data.Functor> fmap (+1) $ Nothing
      Nothing
    

(Except that Haskell automatically preserves the type safety, whereas you have
to re-wrap the value if you're using Java. Functional programming in Java
never works, and this where the Optional idea starts to go wrong.)

But I got "I don't really understand this" in code reviews every time I did
that; the Java way is to check if it's set, then do a type-unsafe unboxing.
Thus, like the article said, completely defeating the purpose of the Optional
type.

That said, it's pretty rare to need exactly 0 or 1 of something. If you're
doing a database query, you can probably make the API return a set of rows.
Then it's natural to loop over the results and nobody raises their eyebrows.

~~~
peeters
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<List<T>>` 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).

~~~
plonh
The Guava authors believed Iterable would be confusing without calling
.asSet() first.

------
pron
Brian Goetz's response: _" They didn't solve the problem I thought they should
have solved, so their solution is worthless." Thank you, internetz._[0]

In any case, that's not what Java's optional is there for[1]. Solving the
safety problem is the job of Java 8's pluggable type systems[2] that are both
more powerful than the static-analysis tools listed in the article _and_ had
Oracle's official support (in the form of JSR-308).

[0]:
[https://twitter.com/BrianGoetz/status/656860771196887040](https://twitter.com/BrianGoetz/status/656860771196887040)

[1]:
[http://stackoverflow.com/a/26328555/750563](http://stackoverflow.com/a/26328555/750563)

[2]: [http://types.cs.washington.edu/checker-
framework/current/che...](http://types.cs.washington.edu/checker-
framework/current/checker-framework-manual.html)

------
w23j
TL;DR You can call `Optional.get()` to deliberately circumvent the safety
mechanisms of Optional.

The author apparently concludes that since it does not solve ALL error cases
it does not solve ANY error cases...

~~~
Cthulhu_
The problem is that you don't get guarantees that something is not null; you
can still do Optional<T> myOptional = null. Second, you're not required to
handle the not-present case. Third, if you attempt to get the value of an
optional (using .get()) when it is not present, you get an (unchecked, so no
requirement to catch) exception - basically replacing NullPointerException
with NoSuchElementException.

The only value Optional has over regular values is that the developer has to
assume the value can be missing - but the same was true for nullable
properties.

~~~
jcrites
> Optional<T> myOptional = null

That hasn't been a problem for me in practice. It's pretty clear that a
reference to Optional should never be null. It can be statically or
dynamically checked with @Nonnull or a precondition.

> but the same was true for nullable properties.

It's inconvenient to have to treat everything as possibly null. It's a lot
nicer to create the convention, within one's codebase, that references are
always nonnull and only Optional are nullable.

~~~
gurkendoktor
> That hasn't been a problem for me in practice.

It has for me. Functions have multiple return points, some of them returning
"null". Lead developer insists we use Optional<> to clarify that these
functions can return null. People go over the function, replacing each
instance of "return null" with "return Optional.empty()", but forget some
instances. Now we have Optionals that are sometimes null.

~~~
RHSeeger
But that's a bug in the library (or code you're calling into), not a bug in
how you're using it. That's the main difference in my opinion.

Optional allows the code to say "I never intend to return null, only an
Optional that may be nothing". In theory, a library/module/whatever that's
been converted to use Optional should not have any calls that do return null.

In theory, its no different than a C API that can return a size or -1 for
failure. Sure, it could return -2 because the language allows it, but you
shouldn't need to check for that in your code that uses it.

------
matteotom
I don't program much Java, but how expensive are exceptions? Wouldn't it make
more sense to expect functions that could return null to instead throw a
checked exception if something goes wrong?

eg

    
    
         public dbResult doDatabaseThing(stuff) throws DatabaseException
      

So if you do

    
    
         result = doDatabaseThing(stuff)
      

the compiler will require you to do something about the DatabaseException.

It seems to me that the point of, for example, Option and Result in Rust is to
avoid the whole checked exception mess while still passing useful information
about things that go wrong. But, given the problems pointed out in this
article (lack of pattern matching and algebraic data types mostly), checked
exceptions might be a more correct way to do it in Java.

~~~
alkonaut
Yes. In this case the No-result means that the database query was successful,
but no record was found. A connection error etc. should almost certainly still
be thrown as an exception in Java.

Without exceptions you would have to return a value that could discriminate
between all 3 possible outcomes: nothing, error, result. In Rust this is the
`Result<T, E>` struct.

~~~
matteotom
It that case, wouldn't it be better to return something other that `null` for
no-result (an empty iterator? an empty list?)? That might be where Optional
comes in, but I'm still not sure why a new language feature is needed for
that.

~~~
alkonaut
Yes, the Optional<T> is a "0 or 1 result" type. It's little more than a list
with max length 1.

------
pjmlp
Optional is planned to become a value type in Java 10, so while the current
situation is less than perfect I don't consider it a big problem.

------
jkscm
Using get() is just bad style and so is returning null where you could return
Collections.emptyList().

Previous discussion on reddit:
[https://www.reddit.com/r/programming/comments/3pl7o0/java_8s...](https://www.reddit.com/r/programming/comments/3pl7o0/java_8s_new_optional_type_is_worthless/)

tl;dr: use map, orElseGet, orElse

~~~
vbezhenar
Why it's bad? If I'm sure that this optional contains value, I don't see why
it's bad. May be I checked this value presence few lines above.

~~~
serpix
If you are certain optional has a value, don't use optional.

Checking presence of value of an optional is an anti-pattern, the same as
doing != null checks.

You should treat Optional the same as a List type with size 1. You never check
if a list is size 1 before doing map or filter.

~~~
vbezhenar
I'm not always own code. Simple example:

    
    
        getCharsetOpt("UTF-8")
    

There is no way this code will return None in this particular case. So any
additional checks are unnecessary and make code less readable.

~~~
louthy
I don't know who said it, and this is probably a paraphrase:

"If it can't happen, it will".

If a function says the result is optional, then it's optional. It's not _not_
optional because you decided it can't ever fail.

------
_Codemonkeyism
Shameless self plug

"Comparing Optionals and Null in Swift, Scala, Ceylon and Kotlin"

[http://codemonkeyism.com/comparing-optionals-and-null-in-
swi...](http://codemonkeyism.com/comparing-optionals-and-null-in-swift-scala-
ceylon-and-kotlin/)

~~~
desdiv
FYI your Scala example doesn't work.

    
    
        Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45).
    
        scala> var h:Option[String] = "Hello".some
        <console>:7: error: value some is not a member of String
           var h:Option[String] = "Hello".some

~~~
andrioni
The author is using the scalaz syntax, you could substitute it for the
"vanilla" syntax:

    
    
        var h: Option[String] = Option("Hello")
    

or import scalaz (in case you have it in your classpath etc):

    
    
        import scalaz._, Scalaz._
        var h: Option[String] = "Hello".some

------
AndrewDucker
I think the main use of Optional is in a codebase which doesn't _ever_ allow
"null".

If every method call either returns an actual object then you can get rid of
null checks, and not bother doing any checks on method returns that don't
return an Optional.

~~~
electrum
That is exactly how we use Optional.

------
lukedegruchy
Optional (either JDK or Guava) is not perfect but is infinitely better than
hand-checking for null. Among other things, it expresses the intent of the API
writer that their method may or may not return an absent value and this is
expressed via the type system. This is in stark contrast to using null as a
primitive, which has no such transparency. For instance, there is no
difference in Java's type system between a method that intends to always
return a non-null String, and one that intends to return a null String under
certain circumstances. Thus it is impossible for the user of the API to
determine when to build conditional logic to check for null or when not to
bother.

In any case, the concept of null as a primitive is fundamentally broken. Due
to Java's backward compatibility requirements, it's too late to resolve this
in that language. However, newer languages don't need to make this mistake.
However, there are "interoperability" requirements for new languages
interfaces with legacy runtimes that tempt language designers to build escape
hatches. These escape hatches exist in Swift, Kotlin, Rust, etc even though
they're not recommended and their usage presents edge cases.

Ceylon and Haskell seem to be the only two languages to get this completely
right. Ceylon expresses optionality as the union between the present value
type and null, which is an actual type separate from Object. An optional
String is therefore a String|Null, or a String? Haskell accomplishes this with
the Maybe type.

All this to say that null should not be a primitive but should be banished to
its own corner of the type system with clear compile-time semantics for
dealing with the absence of values.

~~~
nv-vn
There are actually a lot of languages that do it in the same way as Ceylon
does. However, Haskell goes a step further than most other languages by
defining Maybe as a monad in the standard library.

------
mbfg
All of these problems seem trivial to me. The problem with Optional is that it
isn't baked into the API, nor can it ever be, so any use of Optional is after
the fact, applied only by the application, which means you need to wrap api
calls in Optionals manually, which is something that gets real old, real
quick.

------
vbezhenar
I don't understand what's wrong with get() method. Swift has built-in null-
safety and it has "!" operator. Kotlin has it. Even Haskell has fromJust
function which does exactly the same.

May be name "get()" is too short and innocent-looking.

~~~
danieldk
Partial functions such as _fromJust_ are generally frowned upon in the Haskell
community. There was a relatively recent proposal to deprecate and then remove
fromJust:

[https://mail.haskell.org/pipermail/libraries/2015-February/0...](https://mail.haskell.org/pipermail/libraries/2015-February/025010.html)

~~~
aljones
The equivalents are not celebrated in other languages.

------
danking00
I think in this thread when we talk about "pattern matching" (which _is_
awesome) were caught up with two notions: pattern based destructuring of input
and type enforced exhaustiveness checks. Java 8's Optional does give the
latter:

> maybeT.map(t -> ...).orElse(...)

The author does make a good point that 'get' is unsafe. I think it was a
necessary concession to team members who are learning how to program in this
manner.

------
gurkendoktor
We tried to use Optional<> instead of returning null. Accidentally returning
null from methods returning Optional<> is something that actually happens,
especially when migrating existing code. Of course you can solve that with
@Nonnull annotations, but then why use Optional in the first place?

The other problem is that the Optional<> interface is clunky. There is
ifPresent(), but no ifAbsent(). The stream syntax is incompatible with the
rest of the Java world, in the same way that List<T>#toArray has always been
ridiculous. And if you use ifPresent(), you have to live with the fact that
you cannot return from Java lambdas, and you cannot change any variables or
even use non-final variables. I want to scratch my eyes out when I see people
allocate one-element arrays on the heap just to work around Java's lambdas.

I don't see the value of Optional<T> if you already have @Nullable.

~~~
wcummings
>if you use ifPresent(), you have to live with the fact that you cannot return
from Java lambdas

That's what map/flatMap is for, ifPresent is really only useful for side-
effects.

------
GhotiFish

      public Optional<Long> badIdea() { return null; }
    

I think the fact that this compiles is all the argument necessary. What java
needed was a ThisWillDefinatelyExist<Object>. Not the opposite, but java just
can't do that.

------
EvenThisAcronym
Where did this myth that Option types are the "solution" to nullable
references come from? That's got it perfectly backwards. The solution to
nullable references is to remove them from the language; Option is just a
means for languages that have already done this to encode nullability into the
type of a value add necessary, as it should be. And people claiming that a
language needs pattern matching or it doesn't solve the problem?! It makes me
worry that those advocating these ideas are just part of the latest cargo cult
and don't really understand the underlying principles or why these are good
ideas in the first place.

------
jryan49
I thought Optional was mostly for the steam API, and not just general usage?

~~~
jryan49
Also, despite it not being "standard" @NotNull, and @Nullable have worked
really well for me so far. And I don't think Optional was meant to replace
them.

------
spiralpolitik
We've been using Optional<T> a lot in recent years (via Guava). It's useful,
and has certainly reduced the number of NPE we've had slip through as it
forces the developer to consider nullability up front. Looking forward to
migrating to the Java 8 version when we upgrade to that JDK.

One addition that would be useful would be some syntactical sugar to reduce
the verbosity of using Optional<T>. But otherwise I'm happy and if you combine
with @Nonnull and @Nullable annotations you get the best of both worlds.

------
bakhy
some have already commented here that author maybe complains too much (e.g.,
calling .get() on an Option<T> is a deliberate move, meaning that the
developer explicitly took on the risk of that exception. that's very different
than implicitly assuming that a regular ref is not null, using it and getting
bitten in the ass.). but this one really hurts:

"The last flaw with Java's implementation is a bit ironic — It's possible for
the optional reference itself to be null."

ouch.

~~~
Latty
This is another off-base point, in my opinion. Sure, it's possible for it to
be null, and that isn't great - but the vast majority of null problems come
from the user assuming the interface won't give you a null. Something
returning an Optional should never return null, so the ambiguity is resolved.
Sure, it still could as a bug, but that's actually a pretty rare case. I don't
see it being a real problem.

~~~
bakhy
that makes sense. i think an important question here is - what does "return
null" in a method which returns Optional<T> do? will it return a null
Optional<T>, or will it return a non-null Optional<T> which is empty?

sorry to rub it in, but Java needs value types. this whole issue, however
maybe irrelevant, does not exist in C#.

~~~
KfZ
It's a very simple question to answer: "return null" returns null.

~~~
bakhy
then this abstraction has sprung a serious leak. the article seems to be fully
right.

~~~
Latty
The point is that wherever that happens, it's an obvious flaw with the method
returning the null, and can also be caught by static analysis. It means that
in general, the problem is avoided.

Yes, it's not ideal, it's still a flaw that should be caught at compile-time,
but it's not a big real-world problem, as returning null by accident instead
of an option is a pretty rare bug.

The much more common bug (you didn't realize no return value was a case), the
Option is a good counter to.

No, it's not a perfect solution, but it's not useless either.

~~~
bakhy
i understand, and agree. i would personally, though, avoid adding it, and add
attributes for the same purpose instead. just as the article suggests... it
achieves the same without introducing a new class, thus also remaining
backwards compatible.

------
kailuowang
Implementing a monad like structure without a monadic for loop syntax sugar
tends to confuse people. It's hard to picture writing most operations as map
or flatmap.

------
greydius
I love Haskell, but the existence of a bottom type throws all run time
guarantees out the window.

    
    
        import Control.Monad
        ex1 = Just 1 :: Maybe Int
        ex2 = undefined :: Maybe Int
        inc = liftM (+1)
        main = do
          putStrLn . show $ inc ex1
          putStrLn . show $ inc ex2
    

Yes, you should never use `undefined`. Now replace `undefined` with `null` and
it becomes apparent that Maybe and Optional have exactly the same amount of
power.

~~~
codygman
> Yes, you should never use `undefined`. Now replace `undefined` with `null`
> and it becomes apparent that Maybe and Optional have exactly the same amount
> of power.

Null is encouraged and pervasive in Java, undefined is sometimes used as a
placeholder and could be forgotten. You can't say that Maybe and Optional have
the same amount of power because of this.

------
cetra3
It's not a get out of jail free card no, but it's value isn't in preventing
null pointers. The value of Optional is in providing intent.

You also get map, filter, flatMap, orElse, orElseGet, ifPresent. These are all
great ways of making your code more functional, and do more with less.

I don't think annotations are the answer either, as you can't always rely on
static analysis to prevent errors, a lot will still appear at runtime.

~~~
Retra
It does provide some type-level information, but if you're already writing
documentation, the benefits are marginal. Add to that the fact that it really
pollutes your interfaces, I would argue that it is almost always better to
just pass a null and force people to check it, or read the documented
guarantees.

Basically, just assume _every_ Java type is wrapped in Optional implicitly.
But by adding Optional (and using it in standard libraries) it's often a
matter dealing with code that interfaces between the two styles -- another
problem that didn't exist without Optional.

And even if you think Optional is worth the small gains, it's still a sad
mimic of the Option types implemented in other languages.

------
loren_kuhn
Would be handy if I could filter out all medium.com entries from the front
page for me. Never read anything mildly researched or balanced there...

------
mamcx
This remind me of a old say:

"What is worse than not given anything to somebody that need it? Give to him
something broken".

------
tux3
Static analysis is great, but excessive annotations are not fun.

In my (admittedly limited) experience, people omit them, forget to update
them, and then rely on the analyser to magically catch everything.

Sure, library solutions like Optional can always be misused, but there's no
silver bullet to negligence.

------
mariusmg
I really wished C# would support Nullable for reference types too. This + the
new traversal operator (?. ) would be a great combo to get rid of
NullReferenceExceptions.

To me Optional<T> without pattern matching seems crap.

------
toolslive
I have the same feeling about boost's optional. It's a bandage on a wooden
leg.

~~~
stinos
But is it really? Maybe I'm missing the point but it is a nice way to express
that a function may or may not calculate something, no? At least it seems way
better than returning bare pointers or pasing an argument by
reference+returning bool, or returning a unique_ptr, or ...

~~~
toolslive
If you come from ML or Haskell and start using boost or Java's option, you
actually feel ripped off.

Some people claim it's a sort of documentation denoting 'intent', but I don't
want documentation. I don't want options to infect the whole codebase, I just
want to pattern match once and extract the value, and never have to check
again for None or null.

The problem in Java is the type system has references. X static use_it(X x){
....}

really has a signature something like this: use_it : X ref -> X ref

no little library is going to fix that.

