

Don't return null; use a tail call - ranit8
http://joelneely.wordpress.com/2010/04/17/dont-return-null-use-a-tail-call/

======
ufo
The important thing here is not that passing onOK and onError callbacks is a
good idea. The real issue is that NULL pointers are the most dangerous thing
invented in the 20th century and should be avoided like the plague.

From an [expression problem](<http://c2.com/cgi/wiki?ExpressionProblem>) point
of view using a discriminated union (in the same spirit as returning null but
safer, since you can you peek at the value after doing a null check) would
probably be just fine anyway. You still get to avoid the danger of NULL
pointers but you still get a real value to work with (unlike the callback case
that allways immediately splits it) so you can store it, pass it around, etc.

By the way, astute readers might have recognized all that callback passing as
just the [visitor pattern](<https://en.wikipedia.org/wiki/Visitor_pattern>) in
disguise.

~~~
VMG
> _The real issue is that NULL pointers are the most dangerous thing invented
> in the 20th century_

Not sure if serious

~~~
ufo
I am somewhat serious about this. Tony Hoare even called them his "Billion
Dollar mistake" in a talk he gave a while ago
([http://www.infoq.com/presentations/Null-References-The-
Billi...](http://www.infoq.com/presentations/Null-References-The-Billion-
Dollar-Mistake-Tony-Hoare))

~~~
barrybe
That talk gets quoted pretty often, but it's a bit silly for Hoare to take all
the blame/credit. Null references were discovered, not invented. They are so
easy (from the point of view of someone implementing a non-functional
language) that they were inevitable.

------
leppie
Funny article. He mentions 'tail call elimination' once, and then never
mentions 'tail call' again.

Also a 'tail call' and 'tail call elimination' are 2 completely different
things. The former being an implementation detail (to provide proper tail
recursion for languages that require it, ie Scheme), the latter an
optimization technique (to remove (expensive) tail calls!).

~~~
jonmrodriguez
Nonetheless, the term "tail call" should apply to what he is talking about.

If "tail call recursion" means recursing as the last thing you do before
returning, then he is saying to send a message as the last thing you do.

AKA send a message as a tail call instead of returning the value of that
message.

------
dhx
Remember to keep track of the call stack in your head as you write code. The
trap to avoid is to invert control and then fail to invert (return) back to
the main program flow.

In the example referenced, the following call stack could be created:

    
    
      0. authenticateUser
      1. login
      2. authSucceeded
    

If authSucceeded continues to call other functions as if it were the new main
flow of control you could end up with a very deep call stack (it's not
uncommon to see software with a call stack 40 calls deep). This is why I would
have preferred "authSucceeded" to be renamed as "registerUserSession" or
something else that screams "this function will do a well defined bit of work
and _return quickly_" rather than "this is a loosely defined event callback
that may do anything".

~~~
chalst
In the context of the OA's first sentence ("Why should an object-oriented
programmer care about tail-call elimination?"), I think the author is thinking
more of Scala and Ruby than Java, and there's no expectation that the tail
call will return at all.

------
lubutu
Using this approach you would often also need to maintain state about what was
requested, using closures or similar to avoid race conditions. Alternatively,
Haskell offers the _Maybe_ type, where _Nothing_ means "not found" and _Just
x_ means "found _x_ ". Using a callback seems more prone to disaster than just
encoding the possibility of null into the type system.

~~~
troygoode
C# offers this via Nullable<T>:

    
    
      Nullable<int> someNumber = foo.TryAndGetSomeNumber();
      if(someNumber && someNumber.HasValue)
        doSomething( someNumber.Value );

~~~
dkersten
_if(someNumber && someNumber.HasValue)_

You still have to remember to do this check. Will the compiler complain if you
use _someNumber.Value_ without checking that its valid first? If not, then its
not really the same thing.

The point of Haskell's Maybe is that the compiler will make sure that you take
both cases (that there is a value and that there isn't a value) into account
(because to extract the value you must pattern match and pattern matches must
be exhaustive, otherwise you get a compile error).

~~~
chc
Eh, that's putting it a little too strongly. Haskell is a nice language, but
it still doesn't protect you from all your mistakes. The easiest way to
extract the value in Haskell is fromJust, which simply errors if no value was
returned. I do agree that Haskell makes it more natural, though.

------
gurraman
Common idiom in Erlang. Using message passing (untested code):

    
    
        do_something(N) ->
            Pid = self(),
            spawn(fun() -> find_x(Pid, N) end),
            receive
                {found, Item} -> ...;
                not_found -> ...
            end.
        
        find_x(Pid, N) -> find_x (Pid, N, [1, 3, 5]).
        find_x(Pid, _N, []) -> Pid ! not_found;
        find_x(Pid, N, [N|_T]) -> Pid ! {found, N};
        find_x(Pid, N, [_H|T]) -> find_x(Pid, N, T).
    

You can also handle timeouts and stuff.

~~~
mononcqc
Unless you specifically need a timer, I wouldn't use that and would simply
return {ok, N} or {error, not_found}; that would avoid useless copying and
message passing. Something like:

    
    
        find_x(N) -> find_x (N, [1, 3, 5]).
        find_x(N, []) -> {error, not_found};
        find_x(N, [N|_T]) -> {ok, N};
        find_x(N, [_H|T]) -> find_x(N, T).
    

If what you want is to get out of deep recursion and the above doesn't work
especially well, that's what 'throw/1' is for:

    
    
        Res = try find_x(N) of
                 Val -> {ok, Val}
              catch
                 throw:not_found -> {error, not_found}
              end.
    

This will allow to avoid the stack, special cases for returning values and
give you the code result you need.

The spawning of a process for a simple use case like this is only worth it if
you need a timer to give a maximum execution time for a given request.
Otherwise, it's not very useful, clear or efficient. I'd mark it as
'concurrency for the sake of it'.

------
mmariani
IoC is a very useful concept for any OO language. For instance, ObjC uses it a
lot through protocols. More info on that subject can be found here:
<http://martinfowler.com/bliki/InversionOfControl.html>

The above link has some very interesting links about OO design and SmallTalk
right at the end.

------
strictfp
I don't think that this article focuses on the right problem at all. The real
problem in my eyes is that the semantics of 'null' is not agreed upon. It can
mean anything, including but not limited to:

    
    
      * Wrong username
      * Wrong password
      * Login procedure aborted due to external factor
      * Programming error
    

This causes a headache, since the client might forget to check for the magic
value 'null' and the symptom might therefore accidentally be deferred to any
later time.

Instead of using a callback method, why not just return an instance of some
more sophisticated class, i.e something like this:

    
    
      public AuthenticationResult authenticateUser(User user) {
      ...
      }
    

with a possible usage:

    
    
      AuthenticationResult authResult = authenticateUser(user);
      if (authResult.failed()) {
          notifyUser(authResult.getFailureReason());
      }
    

If the client then tries to use a failed AuthenticationResult as a successful
one, or use a successful AuthenticationResult as a failed one, the programmer
is free to throw any informative exception. Example:

    
    
      class AuthenticationResult {
        ...
        public FailureReason getFailureReason() {
          if (!failed) {
            throw new IllegalStateException("you cannot fetch a failure reason from a sucessful AuthenticationResult!");
          }
        }
    
        public AuthToken getAuthToken() {
          if (failed) {
            throw new IllegalStateException("you cannot fetch a auth token from a failed AuthenticationResult!");
          }
        }
      }
    

If one instead would use 'null' as a magic value for 'auth failed', the
dreaded NPE would show up instead!

~~~
politician
I'm not bashing your idea, but throwing an authentication exception covers
this almost entirely.

See, the calling code probably can't correctly proceed unless authentication
was successful, and there's no chance that the caller can simply forget to
handle an exception -- at the very least, it'll hit a top-level exception
handler and/or crash the program.

~~~
strictfp
That is another viable strategy if you don't want to handle the login failure
in any graceful way.

~~~
politician
Exceptions are not a crash-or-nothing proposition. The idea is that the caller
should handle them at the earliest point in the call-stack that can do
something reasonable about the problem.

Also, let me clarify that I don't believe that exceptions should be used as
the only way to return values from a method in languages that support them.
They are simply a tool with certain properties (among them, the ability to be
more difficult to ignore, the topic at hand).

~~~
strictfp
I generally find that one should avoid using exceptions for flow control. They
have their usages, but they should in my opinion only be used when they really
shine - when you have multiple levels of callers between the detection of the
error and the handling. This was not the case in the simple example, and so I
chose a return value instead of an exception.

------
wlievens
Common idiom in javascript/jquery too, where the callback is called after the
asynchronous execution. That's the advantage of this technique of course:
synchronous or asynchronous implementations are interchangeable.

------
batterseapower
AKA double-barrelled continuation passing style

~~~
wickedchicken
Which is annoying as all hell to write directly. I know it's a cliche to bitch
about how 'ugh, language X doesn't have feature Y' but many callback-
spaghettisms of Node would go away with call/cc.

~~~
dustingetz
if anyone's curious, i wrote a presentation about how call/cc can fix
callback-hell per parent.

slides: lets make a blocking API not block. wait, what? (a practical
introduction to continuations)
[<https://docs.google.com/present/view?id=dv9r8sv_82cn7dngcq>]

------
antihero
" In his post, the caller passes itself as an argument (using a suitable
interface type, of course), and the callee responds by invoking either a
“found” or “not found” method on the caller."

Isn't this pretty much what you do in Twisted already?

~~~
andrewcooke
the difference is that twisted uses trampolining - there's a top level
scheduler that manages everything. if twisted worked exactly as described in
this article then you'd run out of stack space (python doesn't eliminate tail
calls) (also, of course, the trampoline allows other work to happen while
processes yield, which is what makes twisted useful).

from another pov: this article describes how the designers of twisted want you
to think (ie continuation passing style), but the actual implementation is
slightly different.

[http://en.wikipedia.org/wiki/Trampoline_(computing)#High_Lev...](http://en.wikipedia.org/wiki/Trampoline_\(computing\)#High_Level_Programming)

<http://en.wikipedia.org/wiki/Continuation-passing_style>

------
dustingetz
OP argues that callbacks are less complex than type-checked null because it
eliminates checking success at the call site. Branching on success at the call
site is similar complexity as implementing onSuccess and onError. I don't
think its the check itself that matters, its remembering the check, and both a
success/failure interface and type-checked null meet this goal.

As to which is better, type-checked null is referentially transparent, which
is a nice objective measurement of complexity, and referentially transparent
functions are generally more reusable than those that aren't. It also keeps my
mental model of the stack tidy, tail-call optimization or no.

QED, right? have I missed anything?

~~~
kinofcain
I agree that it doesn't make things easier but makes it easier to remember.

One thing that the callback style enables is that you can have more than just
success and failure and/or you can provide more information about _why_ it
failed.

I don't particularly like this callback style though. I do like the multi
return value style in languages like Go* where, by convention, an error is
returned as the last parameter. You still have to check whether the error
itself was nil, but at least you get a reason why; It is also part of the
method signature, meaning you can ignore it, but you have to explicitly ignore
it.

While that doesn't make it referentially transparent, it does force the
programmer to acknowledge the possibility of error, even if they don't deal
with it. It also keeps the flow more sequential and often times easier to read
than the callback style.

*C#, Ruby and others also have some form of multiple-return values, but it's rare to see them used in this way.

~~~
dustingetz
the whole point of type-checked null is that the type system (compiler)
_forces_ you to acknowledge potential error states. it doesn't care if you
deal with it; you can ignore the error states, or not, but its not possible to
forget.

------
noblethrasher
Or return an iterator (e.g. IEnumerable<T> in C#).

