Option isn't the same as the null object pattern, because null objects get used as if they were real objects whereas code dealing with Options looks different. It has to contain some form of check or lifting of a function.
Option is the wrong type if you think you might ever ask 'why is it None?'. Before I realised that I had my own version in Java that stored a stack trace at the point of creating a None. On Jun 3, 2012 11:44 PM, "Cédric Beust ♔" <[email protected]> wrote: > I just listened to the latest podcast and I'm a bit surprised by the > explanation that Dick gave about Scala's Option type, so I thought I'd make > a few comments (and congratulations to Tor and Carl for pressing Dick to > clarify some of the things he said). > > First of all, Option's effect is 100% runtime, not static. It's nothing > like @Nonnull or @Nullable. Dick, can you explain why you said that Option > added static checking? > > If you want to get an intuition for Option, it's described in details in > the GOF book (1994!) under the name "Null Object Design Pattern" (here is > the wikipedia entry <http://en.wikipedia.org/wiki/Null_Object_pattern>, > although it doesn't mention the GOF book so maybe I'm misremembering). > > The idea behind Option is for the program to continue working even if a > method is invoked on a "null" (called "None" in Scala and "Nothing" in > Haskell) object. Obviously, null checks are still present but since they > are hidden inside the Option object, code that operates on these objects > can be oblivious to them. In other words, if f is an Option of any type, > f.foo() will never crash. Either it will actually call foo if there is an > object inside the Option or it will do nothing if there is no object. > > Here are some of the problems with this approach. > > Let's say that you have an HTTP request object and you want to see if a > GET parameter is present. Since this parameter could not be there, it's > reasonable to use an Option[String]: > > class HttpRequest { > def getParameter(val name: String) : Option[String] { ... > > > Now that you have this parameter wrapped in an option, you want to pass it > to another method. Either that method takes a String or an Option[String]: > > 1) def process(val param: String) { ... } > 2) def process(val param: Option[String]) { ... } > > In the first case, you have two choices: 1a) either you extract that > string from the option or, if that process() method belongs to you and you > can change it, 1b) you can modify its signature to accept an Option[String] > instead of a String (and obviously, you need to change its implementation > as well). > > The 1a) case is basically checking against null, like Java. You will do > something like: > > Option[String] p = req.getParameter("foo") > p match { > case Some(s) : process(s) > case None: _ > } > > You have gained nothing (I touched on this particular scenario in this > blog > post<http://beust.com/weblog/2010/07/28/why-scalas-option-and-haskells-maybe-types-wont-save-you-from-null/> > ). > > If 1b) is an option (no pun intended) to you, you go ahead and modify your > process() method to accept an Option, and your modified code will probably > have some matching code as shown above. And if you don't do it at this > level, you will, eventually, have to extract that value from the Option. > > Scenario 2) is the best of both worlds: you have two methods that > communicate with each other in terms of Option, and this buys you some nice > properties (composability). > > As you can see from this short description, the benefit of Option is > directly proportional to how many of your API's support Options. This is > often referred to as the "Midas effect", something that used to plague the > C++ world with the `const` keyword. The direct consequence is that you end > up reading API docs with method signatures that contain a lot of Options in > them. > > The problem with this rosy scenario is that you can't ignore the Java > world, and as soon as you try to interoperate with it, you will be dealing > with raw (non Option) values). So the scenario 1) above is, sadly, common. > > Another dark side of Options is that they tend to sweep errors under the > rug. You definitely see a lot less NPE's when you use options, because what > is happening is that your code is happily working on nonexistent objects > (by doing nothing) instead of blowing up. That's fine if your logic is > expected to sometimes return nonexistent objects but there are times when > you are dealing with Options that should never contain None. The correct > thing to do here would be to leave the Option world, extract the underlying > object and keep passing this, but then you are back to the interop problems > described above between raw objects and boxed ones. > > Debugging applications that have misbehaving Option objects is quite > challenging because the symptoms are subtle. You put a break point into > your code, look into the Option and realize that it's a None while you > would expect a Some. And now, you have to figure out what part of your code > returned a None instead of a Some, and Option doesn't have enough > contextual data to give you this information (some third party libraries > attempt to fix that by providing improved Options, e.g. scalaz's > Validation). > > This is why I think of Options as having a tendency to "sweep errors under > the rug". > > From a practical standpoint, I think that the "Elvis" approach which I > first saw in Groovy and which is also available in Fantom and Kotlin is the > best of both worlds. It doesn't offer the nice monadic properties that > Option gives you, but it comes at a much cheaper price and less boiler > plate. > > Finally, Option is still an interesting beast to study since it's a > gateway drug to monads. You probably guessed it by now but Option is a > monad, and understanding some of the properties that it exhibits (e.g. you > can chain several options) is a good first step toward getting a good > understanding of the appeal of monads, and from then on, functors and > applicatives are just a short block away. > > Dick, would love to get more details on what you were explaining during > that podcast! > > -- > Cédric > > > -- > You received this message because you are subscribed to the Google Groups > "Java Posse" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/javaposse?hl=en. > -- You received this message because you are subscribed to the Google Groups "Java Posse" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/javaposse?hl=en.
