Procedural Language Eliminated GOTOs; OO Eliminated IFs

August 14th, 2008 · 7 Comments ·

by Miško Hevery

Procedural languages allowed us to remove GOTOs in our code. I would like to think that OO languages allow us to remove IFs (conditionals). I know you can’t remove of all the IFs, but it is interesting just how many IFs you can remove in an application.

You can’t remove these IFs:

  • Comparing relative sizes (>, < operators)
  • Comparing primitives

Recently I came across a very interesting and clever way to get rid of IFs when doing lazy initialization. Many thanks to my friend Pascal for pointing it out.

private interface Getter {
  T get();
}

class abstract LazyInitializer implements Getter {
  private Getter getter = new Getter() {
    public T get() {
      final T value = initialize();
      getter = new Getter(){
        T get() { return value; }
      }
    }
  };

  protected abstract T initialize();

  public T get() {
    return getter.get();
  }
}

class Sum extends LazyInitializer {
  public Double initialize() {
    return 1+2+3+4+5+6+7+8+9;
  }
}

Getter sum = new Sum();
sum.get(); // Causes the initialization
sum.get(); // returns the previous value

For extra credit you can do thread safe initializer as well

class abstract ThreadSafeLazyInitializer
               implements Getter {
  private Getter getter = new Getter() {
    public synchronize T get() {
      return synchronizedGetter.get();
    }
  };

  private Getter synchornizedGetter = new Getter() {
    public T get() {
      final T value = initialize();
      gettter = new Getter(){
        T get() { return value; }
      }
      synchronizedGetter = gettter;
    }
  };

  protected abstract T initialize();

  public T get() {
    return getter.get();
  }
}

The cool part about the thread-safe initializer: the cost of thread synchronization only gets paid the first time.

From a testing point of view, this helps with the Separation of Concerns principle. You want your lazy initialization/thread synchronization code to be separate from the logic which computes the value. This way, you can test the laziness once and know that it works everywhere. It is also less likely that you will make a mistake in the initialization code, since you only have one.

Now, the above piece of code is very wordy, and you may wonder why you would write all this code when it can be written in three lines. Point well taken; but if Java was less wordy and supported closures, the above code would be significantly shorter. In languages such as JavaScript, where functions are first class citizens, the above can be written almost as succinctly as the IF clause:

function myValue() {
  return ?; // Do your computation here.
}

function decorateLazy(initialize){
  var lazy =  function() { return lazy.getter(); };
  lazy.getter = function() {
    var value = initialize();
    lazy.getter = function() { return value; };
    return value;
  }
  return lazy;
}

myValue = decorateLazy(myValue);

Tags: Advice · OO · Testability · Uncategorized

7 responses so far ↓

  • john smith // Aug 15, 2008 at 5:35 am

    I don’t understand. When did anyone say IFs were bad? I cannot see at all how all that code is better than an IF statement.

    You want to add all kinds of gunk to the Java language to avoid IFs? No one has ever shown me that adding closures in Java will allow it to do something it doesn’t do now. Just because it saves a couple of lines of code doesn’t mean the language should be changed. In this case, it adds lines to code.

  • John M. Długosz // Oct 20, 2008 at 9:27 am

    Your assertion of “You can’t remove these IFs” is language centric. Polymorphism and overloading in Java replaces explicit comparisons against types, and only types. Furthermore, virtual function calling distinguishes polymorphic types at run-time, and signature overloading does so with declared types at compile time.

    Other languages don’t necessarily have these specific features or these limitations. In functional languages, you can typically “overload” values so you could write a factorial function as two forms: one for the base case and one for the recursive case. Something like

    fact[1] := 1
    fact[n] := n×fact[n-1]

    To be more concrete, in Perl 6 you could write:

    multi sub fact (Int $n)
    { return $n * fact($n – 1); }
    multi sub fact (Int $n where 1)
    { return 1; }

    and then you can check for improper arguments as well, by adding another form:

    multi sub fact (Int $n where { $_ < 1 })
    { fail; }

    As for your specific example, how is what you describe different from simply using a ‘final’ variable directly (I assume this is like ‘static’ in C++’) which implements the specific feature of “initialize on first use”? I don’t know the meaning of the Java syntax

    new Getter() { class-like-block }

    which is key to your idiom.

  • Christian Gruber // Nov 5, 2008 at 9:35 pm

    I’m really starting to like Scala, since it runs in the JVM, but allows me to pass functions similar to your javascript example.

    As to the ifs, ifs aren’t per-se bad, but they are harder to test, since you have to test each possible boolean outcome, and in complicated if/elseif/elseif/else constructs, you are often having to stage a lot of tests. If you could separate the flow/decision logic from the processing logic (the stuff done in each test), you can abstract and make the flow logic generic and test is separately from the work itself.

  • How to leave a comment // Apr 28, 2009 at 10:57 pm

    private Getter getter = new Getter() {
    public T get() {
    final T value = initialize();
    getter = new Getter(){
    T get() { return value; }
    }
    }
    };

  • Berlin Brown // Nov 25, 2009 at 9:32 am

    He is insane? Remove logic?

    I like it.

  • How to think about OO : Clevertester // Jun 7, 2010 at 12:52 pm

    [...] Now that we took advantage of polymorphism, each different kind of user knows how to log in and we can easily add new kind of user type to the system. Also notice how the user no longer has all of the flag fields which were controlling the ifs to give the user different behavior. The ifs and flags have disappeared. [...]

  • If-Then Syntax for Business Rules « Sim4BPM // Dec 15, 2010 at 1:59 pm

    [...] Procedural Language Eliminated GOTOs; OO Eliminated IFs [...]

Leave a Comment