Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programming without if-statements? [closed]

I remember some time (years, probably) ago I read on Stackoverflow about the charms of programming with as few if-tests as possible. This question is somewhat relevant but I think the stress was on using many small functions that returned values determined by tests depending on the parameter they receive. A very simple example would be using this:

int i = 5; 
bool iIsSmall = isSmall(i);

with isSmall() looking like this:

private bool isSmall(int number)
{
    return (i < 10);
}

instead of just doing this:

int i = 5;
bool isSmall;
if (i < 10) {
    isSmall = true;
} else {
    isSmall = false;
}

(Logically this code is just sample code. It is not part of a program I am making.)

The reason for doing this, I believe, was because it looks nicer and makes a programmer less prone to logical errors. If this coding convention is applied correctly, you would see virtually no if-tests anywhere, except in functions whose only purpose is to do that test.

Now, my question is: is there any documentation about this convention? Is there anyplace where you can see wild arguments between supporters and opposers of this style? I tried searching for the Stackoverflow post that introduced me to this, but I can't find it anymore.

Lastly, I hope this question doesn't get shot down because I am not asking for a solution to a problem. I am simply hoping to hear more about this coding style and maybe increase the quality of all coding I will do in the future.

like image 614
Lee White Avatar asked Apr 19 '13 07:04

Lee White


People also ask

Is it possible to code without if statements?

There is nothing wrong with using if-statements, but avoiding them can sometimes make the code a bit more readable to humans. This is definitely not a general rule as sometimes avoiding if-statements will make the code a lot less readable.

Can I write if {}?

An if statement is written with the if keyword, followed by a condition in parentheses, with the code to be executed in between curly brackets. In short, it can be written as if () {} .

What can I use instead of IF statement in Python?

Switch Case is a cleaner and faster alternative to if-else conditions in your code. Python does not directly support Switch Case but it does provide some very useful and efficient workarounds.


1 Answers

This whole "if" vs "no if" thing makes me think of the Expression Problem1. Basically, it's an observation that programming with if statements or without if statements is a matter of encapsulation and extensibility and that sometimes it's better to use if statements2 and sometimes it's better to use dynamic dispatching with methods / function pointers.

When we want to model something, there are two axes to worry about:

  1. The different cases (or types) of the inputs we need to deal with.
  2. The different operations we want to perform over these inputs.

One way to implement this sort of thing is with if statements / pattern matching / the visitor pattern:

data List = Nil | Cons Int List

length xs = case xs of
  Nil -> 0
  Cons a as -> 1 + length x

concat xs ys = case ii of
  Nil -> jj
  Cons a as -> Cons a (concat as ys)

The other way is to use object orientation:

data List = {
    length :: Int
    concat :: (List -> List)
}

nil = List {
    length = 0,
    concat = (\ys -> ys)
}

cons x xs = List {
    length = 1 + length xs,
    concat = (\ys -> cons x (concat xs ys))
}

It's not hard to see that the first version using if statements makes it easy to add new operations on our data type: just create a new function and do a case analysis inside it. On the other hand, this makes it hard to add new cases to our data type since that would mean going back through the program and modifying all the branching statements.

The second version is kind of the opposite. It's very easy to add new cases to the datatype: just create a new "class" and tell what to do for each of the methods we need to implement. However, it's now hard to add new operations to the interface since this means adding a new method for all the old classes that implemented the interface.

There are many different approaches that languages use to try to solve the Expression Problem and make it easy to add both new cases and new operations to a model. However, there are pros and cons to these solutions3 so in general I think it's a good rule of thumb to choose between OO and if statements depending on what axis you want to make it easier to extend stuff.

Anyway, going back to your question there are couple of things I would like to point out:

The first one is that I think the OO "mantra" of getting rid of all if statements and replacing them with method dispatching has more to do with how most OO languages don't have typesafe Algebraic Data Types than it has to do with "if statemsnts" being bad for encapsulation. Since the only way to be type safe is to use method calls you are encouraged to convert programs using if statements into programs using the Visitor Pattern4 or worse: convert programs that should be using the visitor pattern into programs using simple method dispatch, therefore making extensibility easy in the wrong direction.

The second thing is that I'm not a big fan of breaking things into functions just because you can. In particular, I find that style where all the functions have just 5 lines and call tons of other functions is pretty hard to read.

Finally, I think your example doesn't really get rid of if statements. Essentially, what you are doing is having a function from Integers to a new datatype (with two cases, one for Big and one for Small) and then you still need to use if statements when working with the datatype:

data Size = Big | Small

toSize :: Int -> Size
toSize n = if n < 10 then Small else Big

someOp :: Size -> String
someOp Small = "Wow, its small"
someOp Big   = "Wow, its big"

Going back to the expression problem point of view, the advantage of defining our toSize / isSmall function is that we put the logic of choosing what case our number fits in a single place and that our functions can only operate on the case after that. However, this does not mean that we have removed if statements from our code! If we have the toSize being a factory function and we have Big and Small be classes sharing an interface then yes, we will have removed if statements from our code. However, if our isSmall just returns a boolean or enum then there will be just as many if statements as there were before. (and you should choose what implementation to use depending if you want to make it easier to add new methods or new cases - say Medium - in the future)


1 - The name of the problem comes from the problem where you have an "expression" datatype (numbers, variables, addition/multiplication of subexpressions, etc) and want to implement things like evaluation functions and other things.

2 - Or pattern matching over Algebraic Data Types, if you want to be more type safe...

3 - For example, you might have to define all multimethods on the "top level" where the "dispatcher" can see them. This is a limitation compared to the general case since you can use if statements (and lambdas) nested deeply inside other code.

4 - Essentially a "church encoding" of an algebraic data type

like image 192
hugomg Avatar answered Sep 18 '22 15:09

hugomg