Hacker News new | ask | show | jobs
by glutamate 2127 days ago
The whole "this code is problematic because... " section on Boolean blindness reminds me of the worst caricatures of left-wing narratives of oppression based on PhD-level Critical Theory.

Look, a lot of the other patterns are interesting but I really think that if you are getting into criticising code because it has "Boolean blindness" you are probably getting a bit lost in navel gazing. Do you really have nothing better to do?

7 comments

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).
I work at a Haskell shop, and the overuse 'boolean blindness' issue has come up. The common understanding is that booleans are fine to use when the problem calls for it, just don't don't be afraid to use a more expressive data structure if that could make the code concise or understandable.

I think the real "boolean blindless" is something that happens in beginners, who don't yet understand that ADTs can be a rich modeling language, and instead use (Bool, Bool, Bool, Bool) when some combination of product and sum types is better.

I recommend reading this article that's linked in the evidence section: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va...
Hearty lol here. How do you associate some advice to use the type system to explain the meaning of your booleans to left-wing narratives of oppression?

Or are you conflating booleans with black/white and arguing for colour blindness because All Bools Matter or something?

I can't really make sense of this.

do you have any criticisms with actual substance? why do you consider those techniques "navel gazing"?
I really feel that too many rules like this lead beginners astray and focus on issues that make very little difference in delivering a product.

If beginners see a list like this, and start re-factoring the code to remove "Boolean blindness", that's likely not the best way for them to spend their time and the code may become more verbose in the process.

I prefer not to dwell on negativity about code, as long as it does the job and is implemented in a reasonably simple manner. I think in the Haskell community sometimes there can be an unhealthy tendency to nitpick the implementation details.

I wouldn't consider them rules inasmuch as they're things to keep in mind when working in a Haskell codebase, in much the same way GoF has been useful for OO programmers for decades.

Can you write code without using a pattern from GoF? Sure. Will it work? Probably. Does that make GoF useless? No, I'd think not. This type of content is immensely valuable for beginner and practitioner alike because it starts to build a shared language with which to talk about how codebases are organized :)

As a beginner you're just trying to keep your head above water and get the damn thing to compile. For me at least I cared more about that than making the code pretty.

Moreover I don't see much harm refactoring your code with these patterns and maybe losing time, because most people learn haskell off the job.

That's an awfully long-winded and confusing way to say you think "Boolean blindness" is too nitpicky. Personally, it seems like a pretty valid idea to keep in mind, especially as developers transition from a conventional imperative language to Haskell. Making frequent boolean checks is pretty normal in that space, and pattern matching is less common, which might lead new Haskell programmers to write unidiomatic code.