Perhaps, but I would rather have testable code than untestable code that is nothing more than a series of unnecessary, nested if blocks. We have all seen code that has a structure like
if (depObj1.isSomething()) {
if (depOboj1.getAttr() == CONST1) {
// Do something
} else if (depObj1.getAttr() == CONST2) {
// Do something different
}
} else if ... {
// repeat with minor differences
}
Most of the time the above structure can be abstracted. Abstracting It also has the benefit of making this code more testable: you don't have to set up many different objects, just one.The OP is correct: in OO languages if statements are a code smell. Like all smells, though, they are not hard and fast rules, but rather indicators that things could probably be done better. No one, certainly not OP, is recommending abandoning if statements. What he is recommending, and I agree with, is that they can and should be avoided, and certainly not turned to as a primary tool in the toolbelt.
You do introduce more named test points, but you risk of creating too many tests at a too small granularity, that will only slow you down for no good reason. Consider using a code coverage tool to help you navigate all the branches, without explicitly naming them.
Keep in mind readability. Jumping around source files is costly on the reader, don't break the flow if you don't have to.
Now, you could make depObj1 of type Obj1 and Obj2 to replace the if, which may simplify testing because the method is "simpler" in Obj1/Obj2/ObjBase but in the end it isn't!
Why? Because your test of Obj1/2 has to take care of their dependency to ObjBase. It's usually a dependency hell, needing lots of workarounds to test properly.
For example I recently did some work on a graphics library which had a lot of ifs to do with line and fill styles. By changing those into an inheritance hierarchy I found a couple of places where clauses had been missed and so fixed some bugs, but more importantly when we needed to add new fill styles which were more complicated to draw it became very easy to turn the fill style objects into fillers which had all the responsibility for filling paths, not simply setting the graphics state.
But this doesn't mean that it's better to completely eliminate ifs
It is partially my fault because I failed to express what I really ment. English not my native, so sorry.
What I really ment in this sentece is "why using (a lot of) ifs can be a bad practice in a Object Oriented language"
Or maybe better: how can ifs be replaced (sometimes) using OO principles
If you've been writing OO code for 10-15 years, you evolve into a model which is pretty if and block free. It just sort of happens one day. It isn't decomposed into millions of classes either - just a data model and some kind of effector such as specification/Builder/visitor. SRP only needs to go as far as method really as well.
I don't use functional pattern matching either.
If your code reads like math, I expect that its probably done right.
var minutesToAddToAlert = (timeToAddInMinutes) + (900 * ((timeToAddInMinutes +
(currentTimeOfDayInMinutes - 510)) / 540)) +
(2880*(((currentTimeOfDayInMinutes + (1440*dayOfTheWeek)) +
((timeToAddInMinutes) + (900 * ((timeToAddInMinutes +
(currentTimeOfDayInMinutes - 510)) / 540))) ) / 7200));
var nextAlertDate = currentDate.AddMinutes(minutesToAddToAlert);
There is definitely a lot more to it than just this, but I don't like blocks of code that don't fit on my vertical 24 inch screens. So I always end up converting "logic" (if's and else's) to math. It's a pet peeve of mine (as is overusing ternary operators as my own personal way of doing haiku), and while I certainly decrease the vertical size of the code itself, it makes it a hell of a lot harder to understand for everyone else. I then have to write comments explaining what stuff like this does, and those comments can get rather obtuse depending on the time of day.Everyone winces when they see my commits with this message: "Math. Converted X and Y to M-A-T-H. Math. :D"
var accumulator = new TimeSpan();
accumulator.Add(TimeSpan.FromMinutes(currentTimeOfDayInMinutes));
accumulator.Add(TimeSpan.FromDays(dayOfTheWeek));
// ... etc - can't be bothered to do the rest...
var nextAlertDate = currentDate.Add(accumulator);
No magic numbers, no arithmetic and clear to anyone who understands the TimeSpan class (which is the all powerful lord of the fourth dimension in .Net).Oh and I work on a 1280x800 screen on an old ThinkPad T61. If the function doesn't fit on that, I'm concerned :)
In my defense, moving the logic to a pure arithmetic solution resulted in a procedure that takes a bit less than one third of my screen, while the old one was at least 6 or 7 pages of scrolling through nested conditionals.
In any decent language, if will be an expression, not a statement. There is no difference between if and a function.
There is a huge difference between an if and a function. Consider SICP where lazy evaluation is introduced (read it if you haven't). An if statement encompasses the lazy evaluation as a native concept whereas a function's arguments are always evaluated (assumption for now - please carry on reading).
So consider an if statement as a control flow structure which automatically supports lazy evaluation and leaves the return semantics up to the user. This abstraction is clean from the highest level, right down to the CPU which uses conditional branching to perform the if operation. There is a 1:1 match all the way down.
The function on the other hand does not natively support lazy evaluation and enforces the return semantics. You then have to apply a lazy evaluation mechanism over the top (another layer of abstraction!). This layer of abstraction conveniently ends up using conditional branching to perform the if operation when it gets to CPU level. There is not a 1:1 match all the way down.
Big hint there: your functional if at the end of the day is just a compiler abstraction over a state machine which uses ifs.
As for OO, the industry I think has decided who won that battle.
But alas, no religious war is required. Use what tools work for you.
"your functional if at the end of the day is just a compiler abstraction over a state machine which uses ifs"
Yes, that's the 'sad' part of it. In the end there's the Intel/AMD/ARM chip and nothing more
In Lisp: (setq a (if b c d))
Only Lisp implements them as a function (more precisely, a macro), but to the programmer there's no difference between using if and calling a function.
Of course, they don't compile into function calls in assembly code :)
http://www.lispworks.com/documentation/HyperSpec/Body/03_aba...
IF can't be implemented as a function because of evaluation rules.
I still thought you could pass macros around like normal functions in Common-Lisp. The Lisp interpreter I wrote for fun could do that since the function value is resolved before arguments are evaluated for late macro expansions.
def iff(cond, x, y)
if cond then
x
else
y
end
end
puts iff(true, 1, puts('2'))
echoes 2
1
if may behave as a function, but you can't write a function that acts like if.edit: R does have real lazy evalution, e.g.
> iff <- function(cond, x, y) { if (cond) x else y }
> iff(TRUE, 1, cat('foo'))
[1] 1 if x then y else z
is sugar for: case x of
True -> y
False -> z
There have been suggestions to replace this sugaring with a proper "if" function, e.g.: if :: Bool -> a -> a -> a
if True x _ = x
if False _ y = y
to remove arguably redundant syntax, but it seems unlikely that this change would happen. See more here: http://www.haskell.org/haskellwiki/If-then-elseYou can write: a = b ? c : d; in C/C++, you can't write a = if(b) { c; } else { d; }.
I would suggest that decision tables, rule engines, workflow, DSLs, even finite automaton and other abstractions etc are better than having many many objects that are avoiding ifs :)
This is not about getting rid of "if" (as he mentions in the talk), this is about structuring large software systems for maintainability, extensibility, testability, etc.
If we wanted to program in assembly, we would be programming in assembly.
" ifs are a smelly thing in a Object Oriented language."
What's smelly is such a absurd assumption. Yes, let's replace every small decision in our program with inheritance and another level of abstraction, that will work out swell
Please go read an Assembly manual because you have obviously forgotten what a computer is and does
And then we end up with unmaintainable systems with a class hierarchy higher than the Empire State.
Of course, as mentioned, replacing an if with a "software structure" (like pattern matching in an functional language) is beneficial, but to call it a code smell is ridiculous