“Without An If” Notes

Here is some notes which I took from a Google Tech Talks video:

When to use Polymorphism

  • if an object should behave differently based on its state
  • If you have to check the same condition in multiple places Use Conditionals

-> Mainly to do comparisons of primitive objects:
<, >, ==, !=

We’re going to focus on where the business logic should behave differently, that’s the interesting part.

If you really want to be if free in your application, the thing you have to do is you got to make sure you don’t return the Null’s.

What you need is to put an if statement over there to make sure you don’t dispatch a Null.
And that clutter your code. So we want to get away from that.

Don’t return error codes, instead throw an Exception.

Never return a null, instead return a Null Object, e. g. an empty list
Null’s are friends of your test but really your enemy inside of production code.
You really don’t get in a situation when you return Null, because when you return a Null from a method, you can’t dispatch off on a Null. You’ll get a NullPointerException. !!!

If you have a method, the method needs to return some kind of an object that probably doesn’t do anything. Typical example of this would be like the Null Logger.
If I need to Log, I’am always logging except sometimes I get a re-logger that logs the file system and sometimes I get a logger to just eats all my messages and doesn’t do anything.

Polymorphism uses subclassing


–> When you have deep inheritance hierarchies, that creates problems from not jus testability, also from understandability and a couple of other abilities probably as well. (It is a fine line!)

Replace conditionals with polymorphism

–> You have a conditional that chooses different behavior depending on the type of an object.
Typically the way this thing happens is you have some kind of field inside of your object. and then based on whether this field is said or a flag, you’d be headed differently.

–> Move each leg of the conditional to an overriding method in a subclass. Make the original method abstract.

Example:

public class Example {

double getSpeed() {

switch(_type) {

case EUROPEAN:
return getBaseSpeed();

case AFRICAN:
return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;

case NORWEGIAN_BLUE:
return (_isNailed) ? 0 : getBaseSpeed(_voltage);

}
throw new RuntimeException ("Should be Unreachable");
}
}
There already a type system!

Model This –> 1 + 2 * 3

a tree

Lets say we want to perform evaluate method on it which computes the result.

evaluate() –> computes the result of an expression

This method computes the result of an expression.

Typical solution:

class Node {

char operator;
double value;
Node left;
Node right;

double evaluate() {

switch (operator) {

case '#': return value;

case '+': return left.evaluate() + right.evaluate();

case '*': return lef.evaluate() * right.evaluate();

}
}

There’s actually a bigger problem with this:

Graphical representation of this:

Notice couple of things in there

Our leaf nodes still have the left and right child and they’re pulling thing to nulls, and we already said that nodes are not a good idea in production code. And so we’re going to trip up over our Null values by having the possibilty of having an NPE. So you want to get rid of that.

Also noticing something else which is the plus and the multiplication node has to keep around zero even though it’s a completely meaningless concept for a plus or multiplication to have zero associate.

So there is two different behaviors that are kind of fighting in here.
The different behaviors are basically:

–> operaiton node –> you need your left and right child
–> value node –> you need only the value


you don’t need the value or I need the left and right but I never need both.
And that usually is a perfect example that you have a class that has multiple responsibilities all entangled inside of it and then there’s some kind of a polymorphic behavior going on but the polymorphic behavior is going on through fields and if statements not through polymorphism.

Now, we have a value node and operation node.

Operations and Values

abstract class Node {

abstract double evaluate();

}
class ValueNode extends Node {

double value;
double evaluate() {

return value;

}
}


There is no if statements in there, there’s no possibility for a Null or an NPE or anything like that.


We still have the same problem as we had with the swallows in the previous example. And that is, that the behavior of the node changes based on a type. On this case, it’s the operator field. So dependending on what the operator field is our class behaves differently. And that’s something we want to avoid, rather we want to take advantage of the construct of a language which is the polymorphism to take advantage of this thing rather than encoding it using if statements.

abstract class Node {

abstract double evaluate();

}
class ValueNode extends Node {

double value;
double evaluate() {

return value;

}
}
class abstract OpNode extends Node {

Node left;
Node right;
abstract double evaluate();
}
class AdditionNode extends OpNode {

double evaluate() {

return left.evaluate() + right.evaluate();
}
}
class MultiplicationNode extends OpNode {

double evaluate() {

return left.evaluate() * right.evaluate();
}
}

Keep in mind that in addition and multiplication nodes, you would also have to implement a toString method that it would know how to print the plus operator.

Notice what happens in here


–> The possibility of an NPE has dissappeared, because opearion nodes needs a left and a right child, and therefore it will never throw NPE
–> The Leaf Node doesn’t have a left and child and it will never throw NPE.

So we can really clean up the code simply by breaking it away into smaller subclasses that do individual pieces of work.

Notice how the addition node and multiplication nodes how don’t the operator and value fields.

Define toString() prints the infix expression placing parenthesis only when necessary.
Add new math operators: exponentiation, factorial, logarithm, trigonometry.

Summary: A polymorphic solution is often better because:

–> new behavior can be added without having the original source code, and
–> Each operation/concern is separated in a separate file which makes it easy to test/understand, extend, maintain
Whenever you see a switch statement in your code base, that’s usually a clear sign that polymorphism is begging to be there.

Repeated Condition

When you have the same condition all over the code base.

abstract class Update {
// ...
}

class I18NUpdate extends Update {

execute() { ... }
render() { ... }

}

class NonI18Update extends Update {

execute() { ... }
render() { ... }

}

void testExecuteDoA {

Update u = new MyI18NUpdate();
u.execute();
assertX();

}

void testExecuteDoB {

Update u = new MyNonI18NUpdate();
u.execute();
assertX();

}

When you start repeating the if statements over and over again, that’s a clear sign that what you want there is polymorphism.

class Update {

execute() {

if (FLAG_il8n_ENABLED) {
// do A
}
else {
// do B
}
}

render() {

if (FLAG_il8n_ENABLED) {
// render A
}
else {
// render B
}
}

}

Move each leg of the conditional to an overriding method in a subclass. Make the original method abstract.

From a testing point of view, this is great, because when I instantiate an internationalized subclass, I know exactly what I’m talking about. It’s not some flag that got set somewhere else; it’s a concrete class that I can associate with. It significantly lowers my cognitive load when I think about the test.

Where did the ifs go?

You have two piles of objects which does the business logic.

Pile of Objects
–> business logic

Pile of Construction
–> factories
–> builders
–> Provider

By seperating the objects out into the objects that the business logic and the objects that do contruction, you can basically move your if statement from being inline inside of your code. Move that if statement into the factory. That actually can have great benefits in terms of performance because you don’t have to make the decision over and over again.

Pile of Objects
–> reponsible for business logic, domain abstraction

Pile of Construction
–> responsible for building object graphs

Your contruction pile is also where some of the if statements end up because you want to get in the situation where your application behaves differently, not because you have if statements and flags sprinkled all over your code, but it behaves differently because you’re wired it to get it differently. Because when you can change the behavior of application simply by the way your wire it together differently, you have a lot of possibilities, what you can do at runtime and in terms of compiletime in understanding, in maintainingit and in extending it.

abstract class Update {
// ...
}

class I18NUpdate extends Update {
execute() { //do A }
render() { //do B }
}

This is where if statement happens:

Construction

class Consumer {

Consumer (Update u) { ... }

}
class Factory {

Consumer build { 

Update u = flag_enabled 
? new I18NUpdate()
: new NonI18NUpdate();
return new Consumer(u);
  
}
}

The if statement has moved from being inline in your application to being inside of your factory.

Benefits

–> Conditional is localized in one place
–> No more duplication
–> Seperation of responsibilities, and global state

When to use Polymorphism

–> The behavior changes based on state (the example of multiplication – we had a flag and based on that flag which already was addition or subtraction)
–> The same if statement over and over again (This typically done with flags)

ps.

About Aliyar Güneş

I’am Aliyar Güneş, a learner and software developer from Istanbul, Turkey. I write C# and Java.
This entry was posted in General Concepts and tagged , , . Bookmark the permalink.

Leave a Reply