3

ruby has some edge cases which is hard to explain because parsing brings some interesting issues. Here I am listing two of them. If you know of more then add to the list.

def foo
  5
end

# this one works
if (tmp = foo)
  puts tmp.to_s
end

# However if you attempt to squeeze the above
# three lines into one line then code will fail
# take a look at this one. I am naming tmp2 to 
# avoid any side effect

# Error: undefined local variable or method ‘tmp2’ for main:Object
puts tmp2.to_s if (tmp2 = foo)

Here is another one.

def x
  4
end

def y
  x = 1 if false 
  x + 2
end

# Error: undefined method `+' for nil:NilClass
puts y

However if you comment out the line x = 1 if false then code will work fine.

New Alexandria
  • 6,951
  • 4
  • 57
  • 77
Neeraj Singh
  • 2,116
  • 4
  • 19
  • 24
  • The first one makes sense because you haven't defined tmp2 by the time you reach `tmp2.to_s` and I don't believe `if (...)` gets parsed first when it's at the end of a line. – theIV Sep 22 '09 at 20:40
  • I used the term edge case loosely. Anyone who is new to ruby would expect that reducing three lines to one line by moving if statement around should not break the code. – Neeraj Singh Sep 23 '09 at 01:51
  • possible duplicate of [What are the Ruby Gotchas a newbie should be warned about?](http://stackoverflow.com/questions/372652/what-are-the-ruby-gotchas-a-newbie-should-be-warned-about) – Andrew Grimm Jun 27 '11 at 02:17

2 Answers2

6

Program bugs are not edge cases


Hmm. In your first example, you assign 5 to tmp, thereby defining the tmp symbol, and then discover that class Fixnum does in fact respond to to_s. But in the first example failure case you try dotting into an undefined symbol ... it's a one-pass interpreter ... and the statement can't be parsed.

Not exactly an "edge case", and I have to wonder if you thought you were comparing tmp and foo.

In the second case, you create a local variable x, but leave it nil because of the if false, and then naturally discover that nil doesn't have a + method. If you comment out the line, the method x is visible and gets called.

That's called lexical scope, not "an edge case".

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • 2
    In the first case the edge case was supposed to be that `if exp1 then exp2 end` behaves differently than `exp2 if exp1` if exp1 creates a new local variable. In the second case the edge case was supposed to be that x gets created at all. Note that the line does not get parsed as `x = (1 if false)`, it gets parsed as `(x = 1) if false` so one might wonder why an assignment that never executes introduces a new variable. The answer is of course that such things are decided at parse-time, not run-time, but I'd still say those qualify as edge cases. – sepp2k Sep 23 '09 at 09:34
6

In your first example tmp2 is not assigned until it reaches the if statement.

Your second example is not unexpected. Even though x is never assigned it informs the interpreter that you are talking about variable x not function x in the next line. Ruby tries to be pretty loose when determining the context of a name but it will take clues where available. It helps to be specific, for instance:

def y
  x = 1 if false
  x() + 2
end
Corban Brook
  • 21,270
  • 4
  • 28
  • 34
  • I know it helps to be specific. In the first pass my code failed. And then I fixed it by not having another variable with the same name to avoid any conflict. But it raised a flag and I thought it would qualify as an edge case and hopefully would help teach others that in ruby parsers play a role in making or breaking your code. – Neeraj Singh Sep 23 '09 at 01:55