Use of optional is optional
After the article of last week "Optional in collections" today I can’t help but talking a bit more about the same beast. A bit more detail.
The class Optionial
originally introduced by Google Guava and later included in the Java 8 package is simply a wrapper that wraps an optional object. The wrapped object is optional in the sense that it is either there or there is no object in the wrapping, in which case it is empty. There is not too much magic there. The wrapping code, the class Optional
insist that the object wrapped is not null
. After all null
is null
and not an object. An object is never null
. Only a reference to an object can be null
.
These are nuances, fine details; but important fine details. After all, these fine details are those that required the introduction of Optional
. Average java coder does not see the importance of such tiny details. They think that Optional
is just as good as a variable to the wrapped object itself assuming that the variable can also be null
. At some level they are right. At their own level.
That level says that the good code works, can be understood and that is it. Most of enterprise legacy code that run banks, insurance companies, pace makers and weapons were made on this level. You can not do about it, just hope that you have the luck and a software bug will not select your house, bank account or body (in case of medical device) in a "bomb" explode there. What you can do is to understand the issue and do your part to slowly improve the situation. It will take a few generations unless we all are wiped out before that.
"Code working" and "possible to understand" are the very basic requirement for software. Some old times we said that if the software runs then it was ok and for the maintenance it was enough if there were two "person" who could understand the code: the coder who created it and God, who created the coder. Fortunately there are also levels higher. (I mean above the coder. Not above God.)
"Code working" and "easy (not so hard) to understand" are the next level. This is important in case you have to debug the code and need to identify the root cause of some malfunction. "Code working" and "easy to modify" are again new steps up the ladder. I had seen code that I could easily understand. The code was running. But the dependencies between the different modules were so complex like a macrame or a traditional Italian spagetti. Wherever I wanted to change something to fix a bug here, there were a few other places where the program started to fail. Easy to modify: that code was not.
The next level is "code working", "easy to modify" and "hard to create bad modifications". This means that the code provides style and internal data structures and APIs that the maintaining person will follow to some level and will create a working modified code that still works, easy to understand and to modify. This is the point where we get to the point of Optional
.
When a method returns Optional
is says that it may return something or just nothing. Optional<Integer>
may return an Integer
but it may just return an empty Optional
, which means: there was no Integer
that I could return. Why is it any better than returning an Integer
that may optionally be null
?
1.1. Optional method return value
The answer is that in case of returned Optional<Integer>
you can not
integer = methodReturningIntegerOrNull();
otherInteger = integer +1;
that causes NPE. Why you do that? Because you forget to check, and the JavaDoc mentions the possibility somewhere at the end of the description that is not visible in the mouse over window when you code. In case of Optional<Integer>
you are forced to
optionalInteger = methodReturningOptionalInteger();
if( optionalInteger.isPresent() ){
otherInteger = optionalInteger.get() +1;
}
Still there is a small chance that you will write:
optionalInteger = methodReturningOptionalInteger();
otherInteger = optionalInteger.get() +1;
but in that case you deserve what you get.
Optional
helps you to create more code and less documentation. It gives a semantic to pass on some optional value in a way that is harder to neglect than a nullable value. It says: I do not trust you handlingnull
properly, therefore I give you a wrapped object so you have to handle optionality explicitly.
If you consider that you can easily answer the questions
-
requiring
Optional<Something>
as a method argument -
having a
private
field optional.
are good ideas.
1.2. Optional method argument
There are pros and cons. When the argument says
countFrom(Optional<Date> from, Date to);
it is clear that the from
value may be missing and there should be some special default semantics when an absent value is passed. On the other hand the caller may pass null
to get the special behavior. It is less likely that the caller will pass null
just by mistake neglecting the optionality. Even if the argument is Optional
the argument actually passed can still be null
and I expect that the method throws NPE in this case. Last, but not least there is another danger introducing Optional
: the caller may pass an Optional
embracing an object that is not a Date
. Generics can be circumvented in Java easy and a sloppy coder may pass a wrong Optional
. It means that you have to implement assertions in your method:
-
argument is not null,
-
argument is of the proper type.
Also recall that Optional
, in case of a method return value says: I do not trust you handling null
properly, therefore I give you a wrapped object so you have to handle optionality explicitly. What would this message be when you create the API requiring Optional
as an argument? Please do not trust me! Give me only Optional
because even I do not trust myself to handle a null
value properly. Weird… On the other hand I trust that you will not pass null
or wrong type.
In my opinion: in this case using Optional
does not deliver more value than having proper documentation for the API and does not force the caller to behave better than it would anyway. On the other side you put extra code on your own shoulder.
Give
Optional
to code you trust, accept it from code that does not trust your code but do not request it! Trust yourself!
1.3. Private Optional Fields
When you declare a local, private field to be Optional
you will force the developer of the class itself to pay more attention to the optional feature of the field. The cost of this is the extra wrapper, the extra clutter in the code handling optional. On the other side there is no much gain, because you can get the same level of quality extending your unit tests checking all cases where null
value of the field is to be considered. Since all the code is in the hand of the current developer being responsible for the whole code there is no benefit of Optional
. It is again, like you not trusting yourself. That is a serious issue needing more and different treatment than what Optional
Java class can provide.
1.4. Optional in functional programming
You can use Optional
to program Java in functional programming style if you want, but Java is not a functional language and optional and lambda and the functional style methods alone will not make it to be. But that is a different topic for later.
Comments imported from Wordpress
Nicolai Parlog 2015-09-03 11:48:35
Nice, more discussions about 'Optional'. :-)
You might have read Stephen Colebourne’s post about 'Optional' and my reply. If so, you know that I disagree with your assessment regarding optional parameters and fields.
Specifically I think you should not assume that "me" writing a method or class and "me" modifying them are the same person. On the contrary, in a team with shared code ownership this is pretty unlikely. In such situations, 'Opional' helps immensely to communicate intent. (And way quicker and clearer than tests.)
I also fail to see "the extra clutter in the code handling optional". Coding for optionality is more succinct with 'Optional' than with regular references, see 'ifPresent' for example.
Finally and most importantly, you are missing one crucial aspect. If following your approach (no optional parameters, fields), null is still a legal value in some parts of the code. That means that if I encounter an NPE I am still forced to find out whether this value is even meant to exist. That’s wasting a lot of time.
If parameters and fields use 'Optional' as well, null is always a bug. Whenever I see null I already know something went wrong somewhere else and I can aggressively sprinkle null-tests anywhere because it can never be a legal value.
Peter Verhas 2015-09-03 12:55:10
I can absolutely accept your approach, arguments and conclusion. These issues are about the style and not carved in stone. Tastes can be different. If I were made to work in a group where the coding standard recommends, requires the approach you described I would not argue but follow the rules.
Mark 2015-09-03 21:33:23
While "pattern marching" could be a very researchy term that’d describe some obscure SW-technology phenomenon of codepatterns walking here and there but I need to admit, it’s just a typo of "pattern matching" which comes from the proximity of R and T on the keyboard :-(
Peter Verhas 2015-09-03 22:17:48
lol
Piotr Laskowski 2015-09-04 09:51:20
Please do not trust me! Give me only Optional because even I do not trust myself to handle a null value properly. Weird… <
I do not trust myself that after 3 months I will still remember details of given code. Optional is a doc in place, javadoc of public method is not. Especially when delegating work to private methods/helper classes. Not to mention the burden of keeping code and javadoc in sync.
tamasrev 2015-09-04 12:30:29
Using Optional as a private field… It could make sense when you have a monster class with thousands of lines. But wait! That’s below the 'possible to understand' level.
Still I find it a good idea: when you introduce an Optional into a huge legacy class, then the compiler will tell you when and how you need to check nulls.
And that’s it: leaning on the compiler is incredibly useful.
Mark 2015-09-03 21:26:58
Nice contemplation about Optional. It’s a good thing in my opinion that Java tries to solve , or at least give tools to cope with, "the dreadful NPE problem".
However, Optional without pattern marching is just a fancy word and an additional line of imports. Also it’s monadic properties are not exploitable (e.g. syntax-supported short-circuit of faulty operation).
TBH for me it seems Optional makes Java code only a slight more understandable while a lot more verbose. In Haskell, the Optional equivalent Maybe is a bliss: shortens code a lot while reduces "structure" (no more if-indentation hell), makes it way more comprehensible while helps you reason about your code.
In your argument,you distinguish between average and better coders. Average coders won’t start caring because of Optional. The more skilled, on the other hand, did already care: for them, it doesn’t matter whether they check for null or isPresent().
Comments
Please leave your comments using Disqus, or just press one of the happy faces. If for any reason you do not want to leave a comment here, you can still create a Github ticket.