Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CoffeeScript, Why do I need the explicit return on a conditional

Tags:

coffeescript

I was trying to learn CoffeeScript, and made this simple class as first try:

class test    
  fib: (x) -> 
     x if x == 0 || x == 1   
     (this.fib x-1) + (this.fib x-2)

t = new test
alert(t.fib(6));

This code doesn't work because it gets compiled without a return statement in the if statement. This works:

fib: (x) -> 
  return x if x == 0 || x == 1   
  (this.fib x-1) + (this.fib x-2)

Why do I need the explicit return ? Based on the language description, especially http://jashkenas.github.com/coffee-script/#expressions, I expected the x expression to be converted to a return by the compiler.

like image 833
driis Avatar asked Jul 14 '26 00:07

driis


2 Answers

Why would you expect the x expression to be converted to a return? Only the last expression in a method or function is converted to a return.

In Jeremy's if/then/else example, there are two possible last expressions, and the coffeescript parser understands to be the case in an if/then/else, which is not what you have here: instead, you have on expression with no lvalue, followed by another perfectly valid expression. (There's some discussion as to whether or not the if statement itself is an expression; arguably, it should be read as one, but the compiled output of an if/then/else contains a return keyword in both the then clause and the else clause.)

The compiler can't read your mind. It doesn't know what your intent is there with that rvalue x expression. All it knows is that another perfectly valid expression in the same scope follows it.

To get the effect you want:

if x == 0 or x == 1
    x
else 
    (@fib x-1) + (@fib x-2)

Or one-liner:

if x == 0 or x == 1 then x else (@fib x-1) + (@fib x-2)
like image 185
Elf Sternberg Avatar answered Jul 18 '26 16:07

Elf Sternberg


It's because CoffeeScript doesn't know, for sure, that the x if x == 0 || x == 1 line is a return statement.

What you want is

class test
  fib: (x) ->
    if x == 0 || x == 1
      x
    else
      @fib(x-1) + @fib(x-2)

Which compiles into

(function() {
  var test;
  test = (function() {
    function test() {}
    test.prototype.fib = function(x) {
      if (x === 0 || x === 1) {
        return x;
      } else {
        return this.fib(x - 1) + this.fib(x - 2);
      }
    };
    return test;
  })();
}).call(this);

Without the else, the conditional isn't the last block of the function, so doesn't get the return treatment.

like image 43
Travis Avatar answered Jul 18 '26 14:07

Travis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!