1. 1

    Ok, so I fell down the Rabbit Hole of the Anti-IF campaign.

    It sucked me in because I have long ranted against booleans as a code smell. They are a hint you have some code in the wrong place.

    I also hate if’s from the lispy point of view…. If everything is an expression, what is the type of an if without an else? Or an if with different expressions in each branch.

    Falling deeper into the Rabbit hole, I discovered Francesco Cirillo and his twisty maze of links, all the same, each hinting of insight and enlightenment in programming if you just buy his epub.

    He does have the claim to fame of inventing the Pomodoro technique, he drops the right words that hints he is on The Right Track….

    …but is there anything down there in his twisty maze of links?

    1. 1

      I also hate if’s from the lispy point of view…. If everything is an expression, what is the type of an if without an else? Or an if with different expressions in each branch.

      In an if expression where the else branch should never be evaluated, you can explicitly throw/cause an exception. Languages like SML have functions like raise for explicitly throwing an exception. It takes an exception as an argument and returns a polymorphic value according to its type, so any application of raise to an exception can stand in for a needed expression, but a return value will never actually materialize because of the control flow change of actually throwing an exception.

      The type of an if expression in Lisp can be anything since it’s a dynamically typed language, so both branches can have different types. In statically typed languages like SML, the type constraints of the then and else expressions are determined separately and then unified (basically, handle polymorphic type constraints) to determine a single type for the entire if expression.

      Generally speaking, functional programming tends to not run into scenarios where you have if’s without an else; that’s more of an imperative style.

    1. 1

      The short-circuiting evaluation of A andalso B is just syntactic sugar for if A then B else false. There’s no escaping conditionals, you’re only hiding it behind veneer.

      1. 3

        I give it one or two more weeks. The game is in its honeymoon phase currently. People will get bored/tired of the game mechanics and soon move on. Sure, there will still be die hard fans but we should see a huge shift soon as the novelty factor wears out.

        1. 2

          Or as soon as winter rolls around :)

          1. 1

            Could move geographically? There are large areas where it’s nicer to be outdoors in October than July, e.g. most of the southern U.S.

        1. 5

          This post seems to be arguing for two things that are actually unrelated to conditional expressions, which are unavoidable:

          1. The type signature of a function with multiple parameters that share the same non-descriptive type (bool, int, etc) can be made more descriptive and less error prone (i.e., wrong argument order) by introducing new types.

          2. You can change a function to be more general purpose by parameterizing them with functions in the quintessential functional style used by functions like map or filter.

          I think introducing a lot of tiny, single-purpose, two-valued sum types like in (1) is ugly from a code aesthetics point of view. What we’re really after here are compiler-checked names for arguments, which can be achieved using records (example in ML):

          match : string -> { ignoreCase : bool, globalMatch : bool } -> string -> bool
          

          My problem with the overall argument about “removing conditionals” is in the real-world example provided, where a function is basically just split into two pieces, and the caller is assumed to be passing a constant value that represents either the piece that performs a dry run, or the real deal. What if that value is dependent upon a dynamic value, or some other more complicated situation? The conditional would just move somewhere else:

          if dryRunCmdOption() then publish dryRunOptions else publish forRealOptions
          

          I don’t think breaking functions into pieces to avoid a conditional expression is a rational design choice.

          1. 6

            The conditional would just move somewhere else…

            That sums up my read of this article as well. The author seems to be making an argument that either ignores Conway’s Law or underhandedly exploits it by trying to move decisions from the callee to the caller. Any code that has value is going to need to make decisions of some form, and the author hints at this in the aside “now the function match has been simplified so much, it no longer needs to exist, but in general that won’t happen.”

            They might be trying to push the decision making off to some other team as you describe, but what’s to stop that team from passing the buck further? It seems that you would end up pushing everything to the “business” people who write configurations, which leaves you with code that works perfectly but doesn’t do anything, and pathologically complex configurations that never quite work but hold all the cards. Which, I guess, is exactly what happens in shitty enterprise-ware.

            The point of decision is where the work happens, by definition. There are better and worse places to put that depending on context, but pretending it can be entirely shoved-off is not realistic.

            1. 1

              Introducing sum types for things like booleans does, in my experience, reduce errors; but I wasn’t arguing for that. I was arguing for one step beyond that, which is the elimination of the sum type (boolean or otherwise) by extracting the effect of the branch into a lambda, which is passed by caller to callee.