0

Most people would return Bools as follows:

bananas(color) {
    return (color = "yellow")
}

and not as literal expressions; that is, not this way:

bananas(color) {
    if (color = "yellow")
        return true
    else
        return false
}

However, in the discussion at wiki.c2.com Jim Perry said that if a method involve complex logic, the latter approach might be better.

In more realistic contexts the coder might well anticipate that the isBigger method might eventually involve more complex logic than a simple compare of two variables.

Could you provide an example of what he talked about?

The only thing which came to my mind is something like this:

somefunction(...) {
    // you need to read the whole line to figure out
    // that the return value is Bool.
    // But it won't take much time (about 2 seconds, I suppose), 
    // and so I don't think this is what Jim mean.
    return (var1 = "foo" && var2 = "bar" && var3 > var4)
}
somefunction(...) {
    // you don't need to read the whole line to figure out
    // that the return value is Bool.
    if (var1 = "foo" && var2 = "bar" && var3 > var4)
        return true
    else
        return false
}

5 Answers 5

4

I don't know what Jim Perry meant, my mindreading capabilities are very restricted. Actually, I disagree to his literal statement: even in a hypothetic "more realistic context" an expression like

  if (<very complex boolean expression>)
       return true; 
  else 
       return false; 

does not look simpler to me than

 return <very complex boolean expression>. 

I can, however, think of examples where splitting up one huge complex boolean expression into multiple simple ones, by using multiple if and return statements will be more readable, like

   public boolean isBigger() {
        // compare tuples (a1,a2,a3) with (b1,b2,3) in lexicographical order

        if(a1 > b1)
            return true;
        if(a1 < b1)
            return false;
        if(a2 > b2)
            return true;
        if(a2 < b2)
            return false;
        return a3 > b3;
    }

looks more readable to me than

   return (a1 > b1) || (a1==b1 && ((a2 > b2) || (a2==b2 && a3 > b3)));
1
  • 1
    @JacobRaihle: thanks, I corrected it, errors in both
    – Doc Brown
    Commented Sep 8, 2020 at 15:38
2

He is referring to code where the reader looses context such as the if statement covering twenty lines, or in a language where logic operators operate by success (have an object)/failure (have an error) necessitating a conversion to a boolean type.

1

One more aspect:

In many IDEs, it's easier to put an unconditional breakpoint on some source line than a conditional one, making the second version more debugging-friendly.

If you e.g want to debug the cases where the function returns false, it's straightforward to set a breakpoint with the second approach (on the return false line), but quite tricky with the first one (you'd need a conditional breakpoint accessing the return value, which you typically cannot access directly, but have to replicate the return-value expression).

1

Regarding your examples:

somefunction(...) {
    // you need to read the whole line to figure out
    // that the return value is Bool.
    // But it won't take much time (about 2 seconds, I suppose), 
    // and so I don't think this is what Jim mean.
    return (var1 = "foo" && var2 = "bar" && var3 > var4)
}

vs.

somefunction(...) {
    // you don't need to read the whole line to figure out
    // that the return value is Bool.
    if (var1 = "foo" && var2 = "bar" && var3 > var4)
        return true
    else
        return false
}

The first thing to note is, that most (? at least many as in 100% of the languages I work with) languages actually declare the return type, or your IDE somehow shows it to you. Thus, the reality looks like this:

bool somefunction(...) {
     // function body does not matter at all for the reader
     // to understand that the return type is bool
}

Regarding the code inside the functions: I don't find

if (var1 = "foo" && var2 = "bar" && var3 > var4)

any better than

return (var1 = "foo" && var2 = "bar" && var3 > var4)

Quite the contrary. It burdens me with a "complex" structure which is much harder to format in a readable way (that's what it is all about, right?) than the plain return.

Consider:

if (var1 = "foo"
    && var2 = "bar"
    && var3 > var4)
    return true;  // no good visual separation of if-body from expression. Or use {...}
    

vs.

return
    var1 = "foo"
    && var2 = "bar"
    && var3 > var4;

The usual professional values apply here. Write code for your reader, not for the compiler. Format in a way that supports understanding the logic. Use line breaks.

2
  • Also write code for the debugger. Depending on the features of your debugger.
    – gnasher729
    Commented Sep 9, 2020 at 7:14
  • Try that last one like this. Commented Sep 9, 2020 at 13:44
0

Complex expressions

A complex expression might profit from splitting in if-else-if's but then probably you rather need secundary test functions: single responsibility principle.

Especially if there would be many ifs, the test coverage of every case becomes harder, the code quality lower. This holds for a single expression too, but one would assume more general factors, not case specific terms.

So there a single return is fine.

Temporary variables

If temporary variables are sensible, one might have an if.

Also chained (java Stream) expressions simply form one large (boolean) expression obligatory.

if (map.containsKey(sought)) {
    return map.get(sought).getSignal().isDiscrete();
} else {
    return DEFAULT_SIGNAL.isContinuous();
}

Could become

return Optional.ofNullable(map.get(sought))
        .map(T::getSignal())
        .map(S::isDiscrete)
        .orElseGet(() -> DEFAULT_SIGNAL.isContinuout());

(An ugly example.)

Effects

And then there is a difference between test and predicate (terms in CDL jargon, not functional language). A test has no side effect, a predicate contains an (optional) action.

A predicate example (grammar style parsing):

boolean couldParseOperation() {
    if (symbol.scansOperator()) {
        ...
        return true;
    }
    return false;
}

So that would be the case for a conditional if-statement.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.