
If statements considered harmful - setra
https://blog.deprogramandis.co.uk/2013/03/20/if-statements-considered-harmful-or-gotos-evil-twin-or-how-to-achieve-coding-happiness-using-null-objects/
======
somehnreader
Pardon my ignorance, but I don't even understand his point. I wouldn't even
have bothered with a class at that level of abstraction.

If I find repeating if statements throughout my code I put them in a method,
end of story. Pseudopython:

    
    
      def logging(logger, message):
        if null == logger:
          return
        if null == message:
          return
        logger.write(message)
    

I don't understand why the author would even bother with more than this, given
his example. Also note that I used two return (disguised goto's) as guard
statements to check the conditions before I do anything.

------
kowdermeister
I'm really waiting for the ultimate "Programming is considered harmful"
article.

------
moomin
This is a case of employing OO to circumvent a problem in OO languages.
There's two potential problems with if statements: 1) non-locality 2)
fragility.

1) can often be dealt with by changing the code, or parameterising. But in
general, you want to be able to specify your own interface and specify how
specific classes handle it. The article misses out one important detail,
because the average OO language doesn't handle it: you might want to do this
to someone else's class 2) You can make fragile code in any language, but the
absence of pattern matching with totality checking makes it much worse.

Of course, there's a third problem that's implicit throughout the article: the
inability to verify something's not null through the type checker.

The ideas in the article are good, but they're patterns for circumventing
problems in your programming language. There's languages with no OO whatsoever
that avoid the problems.

~~~
millstone
The problem identified has nothing to do with OO. Look at this code:

    
    
        logFile.write(message);
    

We might as well replace `logFile.write` with `fprintf(logFile...)`, and get
the same result in C. So we don't need OO to experience this pain.

Conversely, this is only a "problem" if `logFile.write()` results in SIGSEGV
or NullPointerException or whatever. But some OO languages (Smalltalk,
Objective-C, others?) dodge this by making null a message black hole.
Confusing, but terribly convenient.

One last point: notions of "pattern matching with totality checking" or
"verify something's not null through the type system" presupposes exhaustive
knowledge of the environment in which your code will run. Maybe that's
correct: google.exe on Google owned hardware in Google-owned data centers will
behave very precisely.

But sometimes it's _not_ correct. Your JavaScript code is running in a yet-to-
be-written browser on an ancient version of some OS on random hardware. Your
code's typechecking environment is unrelated to its runtime environment.
Totality checking requires predicting the future. In this highly dynamic
universe, languages like Haskell have no good solutions.

~~~
moomin
You're right, you could certainly experience the pain in a non-OO language
that silently allows invalid values to creep through the system. However, it's
an error _every_ OO language makes. Smalltalk, Objective-C and Clojure dodge
it, but they don't dodge it for long: the nulls can now propagate further
through your program, making it harder to track your problem down.

I'm not sure your last point buys us anything. I mean, any runtime environment
can have bugs, and any future system can have cases you haven't handled. This
will break your OO code just as fast as pattern-matching. Because OO dispatch
is really just a special case of more general mechanisms.

Have a chat to some purescript guys about when they have trouble with
JavaScript nulls. I bet the answer is "when we interface with raw JavaScript
code and don't define our types correctly".

------
egwynn
In this case, I prefer FP-style destructured pattern matching (e.g.
[https://doc.rust-lang.org/book/patterns.html#destructuring](https://doc.rust-
lang.org/book/patterns.html#destructuring)) to OOP-style method overloading
(FTA). In the FP style, the compiler can make sure you handle all
possibilities.

~~~
rdnetto
It's worth noting you can implement something similar in OOP languages using
Church encoding: [http://blog.higher-order.com/blog/2009/08/21/structural-
patt...](http://blog.higher-order.com/blog/2009/08/21/structural-pattern-
matching-in-java/)

------
ouid
tl;dr: OOP is sometimes good.

~~~
joncampbelldev
polymorphism is very good, but not handcuffed to OOP.

Clojure protocols, Haskell typeclasses (and many other examples I'm sure)
provide the same functionality "a la carte" without the rest of OOP's features
coming along for the ride (to paraphrase Rich Hickey and Stuart Halloway).
More eloquently explained details in this talk at around the 21 min mark [0].

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

~~~
millstone
One big missing feature in typeclasses is overriding. You can't "call into
super."

A concrete example: you make a new type in Haskell, and you derive Show so it
can be printed. But the default output isn't quite right - you want to add
something to it. In an OO language you might "call into super" and append to
the string. But in Haskell this isn't possible: you either get the default
implementation, or you do it all from scratch.

More generally, typeclass default implementations are a lame replacement for
overriding, and existentials are anemic compared to dynamic binding. This
pushes Haskell interfaces towards rigid, static designs. That's fine if that's
what you want, but let's not pretend it's equivalent in power to OO
polymorphism.

~~~
joncampbelldev
that sounds a lot like sharing code by inheritance as opposed to composition.
which is unrelated to dispatching by the type of the first (or implicit)
argument.

i personally would prefer to code to interfaces and keep hierarchy separate
from behaviour

~~~
joncampbelldev
perhaps I haven't felt your pain of rigid static designs because i mostly work
in clojure, ymmv

