68

If I had a complex if statement that I did not want to overflow simply for aesthetic purposes, what would be the most kosher way to break it up since coffeescript will interpret returns as the body of the statement in this case?

if (foo is bar.data.stuff and foo isnt bar.data.otherstuff) or (not foo and not bar)
  awesome sauce
else lame sauce
Evan
  • 7,396
  • 4
  • 32
  • 31
  • If `not bar` is a possibility in the first clause (as the second clause suggests), then the reference `bar.data` is going to cause an error... – Trevor Burnham Jul 08 '11 at 15:43

5 Answers5

86

CoffeeScript will not interpret the next line as the body of the statement if the line ends with an operator, so this is ok:

# OK!
if a and
not 
b
  c()

it compiles to

if (a && !b) {
  c();
}

so your if could be formatted as

# OK!
if (foo is 
bar.data.stuff and 
foo isnt bar.data.otherstuff) or 
(not foo and not bar)
  awesome sauce
else lame sauce

or any other line-breaking scheme so long as the lines end in and or or or is or == or not or some such operator

As to indentation, you can indent the non-first lines of your if so long as the body is even more indented:

# OK!
if (foo is 
  bar.data.stuff and 
  foo isnt bar.data.otherstuff) or 
  (not foo and not bar)
    awesome sauce
else lame sauce

What you cannot do is this:

# BAD
if (foo  #doesn't end on operator!
  is bar.data.stuff and 
  foo isnt bar.data.otherstuff) or 
  (not foo and not bar)
    awesome sauce
else lame sauce
nicolaskruchten
  • 26,384
  • 8
  • 83
  • 101
  • Thanks for the answer. That's a great rule I didn't realize about operators being the key to line breaking in Coffeescript. – Evan Jul 11 '11 at 13:47
  • 2
    If you don't want to indent `if` statmenet's body "even more", you can use `then`, starting at the same level as `if`. It is more readable, IMHO. – Dmytro Shevchenko Jun 27 '12 at 22:11
  • A note on the indentation; the body doesn't have to be more indented than the non-first lines of the `if`. The only rules for correct syntax are (as far as I know): 1) The body cannot have the same indentation as either the first or last line of the `if` and 2) Neither the body nor any line of the `if` can have less indentation than the first line of the `if`. Note also that you can have different indentations on different non-first `if` lines. – LoPoBo Jan 16 '15 at 14:05
  • I usually indent the non-first `if` lines with 2 tabs (so as to make it more visible that they are neither after nor inside the `if`) and the body with 1 tab. – LoPoBo Jan 16 '15 at 14:08
3

This changes your code's meaning somewhat, but may be of some use:

return lame sauce unless foo and bar
if foo is bar.data.stuff isnt bar.data.otherstuff
  awesome sauce
else
  lame sauce

Note the is...isnt chain, which is legit, just as a < b < c is legit in CoffeeScript. Of course, the repetition of lame sauce is unfortunate, and you may not want to return right away. Another approach would be to use soaks to write

data = bar?.data
if foo and foo is data?.stuff isnt data?.otherstuff
  awesome sauce
else
  lame sauce

The if foo and is a little inelegant; you could discard it if there's no chance that foo is undefined.

Trevor Burnham
  • 76,828
  • 33
  • 160
  • 196
2

Escaping the linebreak looks most readable to me:

if (foo is bar.data.stuff and foo isnt bar.data.otherstuff) \
or (not foo and not bar)
  awesome sauce
else lame sauce
Cees Timmerman
  • 17,623
  • 11
  • 91
  • 124
2

Like any other language, by not having them in the first place. Give names to the different parts an treat them separately. Either by declaring predicates, or by just creating a couple of boolean vars.

bar.isBaz = -> @data.stuff != @data.otherstuff
bar.isAwsome = (foo) -> @isBaz() && @data.stuff == foo
if not bar? or bar.isAwesome foo
  awesome sauce
else lame sauce
John Nilsson
  • 17,001
  • 8
  • 32
  • 42
  • 2
    What if some predicates are expensive to calculate and earlier predicates are already likely to conclude the result of the statement if used in a single expression? – Halil Özgür Dec 01 '15 at 11:07
0

When a lot of low-level boilerplate occurs you should increase level of abstract.

The best solutions are:

  • to use good named variables and functions

  • logic rules in if/else statements

One of logic rules is:

(not A and not B) == not (A or B)

The first way. Variables:

isStuff              = foo is bar.data.stuff
isntOtherStuff       = foo isnt bar.data.otherstuff
isStuffNotOtherStuff = isStuff and isntOtherStuff
bothFalse            = not (foo or bar)
if isStuffNotOtherStuff or bothFalse
  awesome sauce
else lame sauce

The main disadvantage of this method is its slowness. We will get better performance if we use and and or operators features and replace variables with functions:

  • C = A and B

If A is false operator and wouldnt call

  • C = A or B

If A is true operator or wouldnt call

The second way. Functions:

isStuff              = -> foo is bar.data.stuff
isntOtherStuff       = -> foo isnt bar.data.otherstuff
isStuffNotOtherStuff = -> do isStuff and do isntOtherStuff
bothFalse            = -> not (foo or bar)
if do isStuffNotOtherStuff or do bothFalse
  awesome sauce
else lame sauce
Nikita
  • 970
  • 9
  • 12
  • Sorry, I have to downvote this. The question was " the most kosher way to break [a long if statement] up", and this answer is highly irrelevant. – Ardee Aram Mar 09 '16 at 09:38