Hacker News new | ask | show | jobs
by chriswarbo 2128 days ago
Their particular example of boolean blindness was perhaps too simple, but it's definitely a useful thing to avoid. For example, this sort of thing comes up a lot:

    foo x y z = if (isNothing x) then bar y else baz z
      where bar val = [val]
            baz val = [fromJust x, val]
Here we're using a boolean like 'isNothing x' to choose what to do, but one of those choices (baz) is making implicit assumptions about the meaning of that choice ('fromJust x' is an unsafe function, which will crash if x isn't 'Just'). In real code this sort of implicit coupling can spread across larger pieces of code, with more complicated and less obvious behaviour (e.g. indexing into a list, assuming it's safe due to some arithmetic written elsewhere). This is bad for a few reasons:

- If we don't get it exactly right (including edge cases, etc.) then it can go pretty badly wrong (a crash in this case).

- The dependency/coupling between the check and the assumption are implicit and may break in the future; e.g. if we try to re-use the assumption-riddled code without performing the check; or if the condition in the check needs to change and we don't realise it breaks the assumption-riddled code.

- The logic usually ends up being overly-complicated, since we're performing redundant work. In my above example we could do this instead:

    foo x y z = maybe (bar y) (baz z) x
      where bar val    = [val]
            baz val x' = [x', val]
Branching on the value we care about ('x', using the 'maybe' function) ensures that each branch (a) has the context it needs to do it's job (e.g. the x' parameter) and (b) isn't given any more context than what is known at that point (e.g. the compiler can tell us if we're forgetting unhandled cases, which it can't if our assumptions are implicit).