if wrapper and header:
...
if wrapper and body:
...
to if wrapper:
if header:
...
if body:
...
when coding? if wrapper and header:
...
if wrapper and body:
...
to if wrapper:
if header:
...
if body:
...
when coding?Consider the case below. If I want to understand what conditions are necessary for body, that code is now offscreen. I generally consider overly-nested conditions as code smell.
if wrapper:
... 30 LOC ...
if header:
... 30 LOC ...
if body:
... 30 LOC ...If ~25 years of doing programming for money taught me something, it's that the code is written to be read and maintained by humans, and having really short, clean, one-purpose, composable functions makes your life easier both long-term and short-term.
"Fit all functions on one screen."
At that time that was roughly 22 lines depending on editor used.
Two If statements, no nesting
vs.
Three If statements, 1 level deep nesting
To me, the first option is clearly simpler and more readable. Then again, looking at the second option I notice immediately that I can dismiss it if wrapper happens to be false. But it really depends on what the other code lines contain. if a:
if b:
if c:
if d:
if e:
if f:
if g:
Vs. if a and b and c:
if a and b and d:
if a and e and f:
if a and e and g:
Or would you perhaps find if a and b and c:
if d and b and a:
if e and a and f:
if g and e and a:
Or if e and f and a:
if c and b and a:
if g and a and e:
if d and a and b:
In any case, now you have 12 comparisons vs. 3 comparisons. (Though this is not entirely comparable to CSS, since selector order is somewhat more restricted.)The problem I foresee with repeat conditions is that during a change, I might forget to update one or more of the repeat conditions.
Also, I wonder, do gcc and/or clang recognize repeat conditions and produce the equivalent of what nested statements would?
The most useful one, and the one that drives me crazy when I see it, is when people write code like this:
if something:
value = do something
else:
value = do something else
return value
These days I write code like this: if something:
return do something
return do something else
In the simple example, it's not a big deal. But once you have 30 lines of code in between each statement (and nested if statements), it gets trickier to maintain every possible code path in your head.This isn't the same as "show all conditions at once" -- instead it's "ignore the conditions that have already been satisfied."
Seeing that we already returned out in condition #1 lets me focus more on condition #2.
I think the main reason returning early works so well is that often times, when you're returning different values, it's because you quickly have an answer (often times that something is invalid) for particular inputs. Generally though, there is "real work" to be done after validating or normalizing your inputs.
If that's not true, you're probably trying to do too many things at once, and the different pieces should be broken into separate functions.
if some_function(arg, arg2):
result = True
else:
result = False
return result
Obviously a waste of time and lines of code. Instead, do return some_function(arg, arg2)
Unless anything else needs to be done with the result of some_function but that's not the case I'm talking about, I'm talking about when it looks like above.> The most useful one, and the one that drives me crazy when I see it, is when people write code like this:
But... your example doesn't show any ways to avoid nesting. There's just as much nesting after as before.
Your change makes the code less tall, which is a problem I've had with Python, but it has nothing to do with nesting at all.
I'm actually fond of a third approach:
if something:
return do something
else:
return do something else
I like the ocaml-style philosophy that it's an error if your condition check isn't capable of handling all possible conditions. if something:
value = do something
else:
if something_else:
value = do something else
else:
value = do a third thing
As I said in my initial post, "it helps once you have nested ifs, and multiple lines of code." Here's the change: if something:
return do something
if something_else:
return do something else
return do a third thing
Again, what I'm stressing here is that if you already have your result, you can return, and it makes the code easier to follow than adding a superfluous "else:" statement. return something
? do_something ()
: do_something_else();Also, it does force you to write CSS more efficiently because if you work with pre-processor language, you often don't see the bloat.
if wrapper:
do_thing_to_wrapper(wrapper)
def do_thing_to_wrapper(wrapper):
...