

Sending null to /dev/null - vladev
http://bolddream.com/2009/06/12/sending-null-to-devnull/

======
pmjordan
Okay, I realise this is probably a naïve question, but it hasn't been answered
by any of the anti-null articles.

Usually, null as a return value has some kind of special meaning, like
indicating a failure or other edge case. Making null go away doesn't mean that
case can't happen, you just need to handle it differently. The example in the
article

    
    
      String com = tld("example").getOrElse("unknown");
    

is one of those lovely academic examples which is completely out of touch with
reality. Unless you're doing nothing but displaying it to the user, the string
"unknown" is just as bad as the null object in almost every way, and worse in
others: there's a reasonable chance that "unknown" will one day be a valid
TLD.

So the proposed solution with the Option<> generic type really is just a
reminder to the programmer. There's no technical advantage. You might even see
a decrease in performance if the compiler can't optimise it away.

Except we already have a reminder mechanism: checked exceptions. Remember
those? Remember how popular they are?

C# actually has this concept of nullable types. It doesn't apply to class
types which are always nullable, but structs (with mostly value semantics as
opposed to identity semantics) can be either nullable or not - just like
C/C++'s passing by value I suppose. Except they're so unwieldy to use due to
the _OMG IT MIGHT BE NULL_ paranoia (you can't do anything as ridiculous as
_access a member_ without unboxing... which will throw a NullPointerException
if null - score!), you may as well redefine your struct as a class and use
that. (which breaks cases where you didn't want it nullable. score 2!)

I won't even treat C++ references (&) as a realistic attempt at a non-nullable
type system because safety and C++ don't go together anyway. [1] I've not used
scala, so if someone has a good, realistic example of code where scala's non-
null system works well, I'd love to see it.

I guess I have to add that I actually _liked_ static typing for a long time
(I've done my stereotypical 10000 hours of C++), until I noticed I was just
slowing myself down and my code in dynamic languages wasn't any worse, just
quicker/easier to modify. Is this a sign of programming maturity? Is static
typing the "training wheel" mechanism for beginning programmers? I'm starting
to think so.

    
    
      [1] void bar(Foo& f); Foo* p = 0; bar(*p);

~~~
vladev
I agree, the example with the tld part wasn't the best - maybe an url schema
(http part) would have been much better.

"So the proposed solution with the Option<> generic type really is just a
reminder to the programmer." - exactly. But a good program is a program that
works, so we need to achieve that first. :)

~~~
pmjordan
_But a good program is a program that works, so we need to achieve that first.
:)_

The thing is, static typing addresses this on the microscopic scale, where
it's not difficult to make code work anyway - except maybe for novices, hence
my "training wheels" analogy. I don't see any evidence that it helps
correctness on a more macroscopic scale. In fact, it makes code more verbose,
which makes it trickier to take in all at once.

EDIT: rather than just hating on static typing, I propose this:

How about making our languages more expressive? I don't think exceptions
(try/catch/finally) are anywhere close to a global optimum for error/edge-case
handling. Maybe there's no silver bullet, but I'm pretty confident we can do
better than current exception handling. I hear Common Lisp 'conditions' are
resumable, which sounds nice, but again only useful if you can reasonably
substitute a value of some kind, a bit like the TLD example. What mechanism
should we have if we really want our program to do something else in
exceptional cases?

~~~
limmeau
Regarding "It makes code more verbose": while "new
JSome<LongSuperclassName>(myValue)" is certainly more verbose than necessary,
I still think that the one bit of information "this method returns Foos" vs
"this method returns Foos or nothing" is worth documenting. And in a
statically typed language, the type system is an obvious place for such
documentation.

~~~
pmjordan
Sure, if you're already going to go to the trouble of having type annotations
for everything, adding an extra '?' (like in C#) isn't going to break the
camel's back. It's the unboxing and wrangling with the returned value that
make it more verbose.

As far as I can tell the only statically typed languages that stand any chance
in terms of terseness are those with sophisticated type inference. In that
case, "can return null" or not makes a lot of sense for auto-generated
documentation or making it an error to compare the return value to null.

~~~
limmeau
There is bound to be some wrangling with the returned value if the case of
"something was returned" needs different treatment from "nothing was returned"
in the program's design.

However, I agree that

    
    
          match perform_foo() with
              | Some x -> do_something_with x 
              | None -> do_without
    

looks a lot less messy than

    
    
          JOption<Bar> baropt = performFoo();
          if(baropt.isNonempty()) {
             Bar bar = baropt.getValue();
             doSomethingWith(bar);
          }
          else {
             doWithout();
          }
    

There's just something deeply unsatisfying with a statically typed language
that requires so much legalese and boilerplate as Java while still permitting
surprising runtime errors in virtually every executable line of the program.
Abandoning static types is one approach to the dilemma, trying to plug hole by
hole is another.

------
limmeau
I agree with the author that having an option datatype makes the intention
"this method returns some Foo or nothing" clear.

However, the suggested encoding of an option type in Java blends poorly with
subtyping because a JOption<MySubtype> is not a subtype of
JOption<MySupertype>. For a quick optional-return scenario, it may work, but
as a substitute for nulls in optional parameters, you'd have to remember the
precise type of every parameter and create non-empty JOption instances in a
rather verbose way.

As an alternative, you could use a tool like Findbugs and its @Nullable
annotation.

~~~
vladev
In Scala's type system that can be expresses as well - it's called type
variance. I believe C#4.0 might be getting this.

~~~
limmeau
In C#4.0, apparently you can declare JOption as

    
    
       interface NOption<out T> { ... }
    

such that NOption<Mysub> is a subtype of NOption<Mysuper>. Still messy to
read, though, and C# has ?-types anyway.

------
chanux
Null is an element of any given set. So it's natural enough. Maybe the way we
human use it in implementations is wrong. But after all Null is defined by
human anyway.

"...And you, as a consumer of that method, need to check every time if the
return value is Null. If you don’t – you (usually) get a Null pointer
exception and your program crashes."

Can't this be handled by the language itself, by default?

~~~
ovi256
I propose eliminating Null/None all together. Simply do not allow a pointer to
be initialized to none, but require it to point to an object. The object
should not be collected as long as the pointer is valid.

Just throw exceptions if you need to, and handle those. Semantically,
exceptions and special null values are the same - they let you know something
went wrong. However, I think that null values are a syntactic oddity much like
a vestigial limb now that we have exceptions.

~~~
limmeau
What do you suggest as a replacement for nullable fields?

~~~
ovi256
Ouch, forgot that. Well, I guess the database could use Null values
internally, but they should be translated into exceptions as soon as possible
- as in, throw a NullFieldException if the field is accessed. However,
checking for these all the time would be just as wasteful as checking for null
values.

I now see the advantages of the monad way.

------
sovande
So what happens if I call the new improved method tld with a null argument?
Yep, a NullPointerException raised by lastIndexOf.

