user4196197
user4196197

Reputation:

Ruby Scope/Bindings

The output of the following snippet of Ruby code

def foo; "foo:function"; end
puts foo
puts foo()
foo = "foo:value"
puts foo
puts foo() # Didn't expect this to work!

is

foo:function
foo:function
foo:value
foo:function

This is puzzling, I would have thought that in the current scope there is only one binding for foo, but looks like this is not the case.

PS: Running equivalent code in python gives the expected result (i.e. after binding a string to foo, the last statement trying to call foo() gives an error).

Edit:

The following is the equivalent example in python:

def foo(): return "foo:function"
print foo
print foo()
foo = "foo:value"
print foo
print foo() 

which produces the output (edited):

<function foo at 0x7fb71d912578>
foo:function
foo:value
TypeError: 'str' object is not callable

Edit 2:

So, it seems in Ruby, unlike Python, a given symbol can have two binds in the same scope (as a method and as an instance variable).

Upvotes: 2

Views: 97

Answers (1)

daremkd
daremkd

Reputation: 8424

Try puts foo without the parentheses and you'll get "foo:value". With the () you're explicitly saying this is a method. Try putting these 2 lines at the end of your code:

puts defined? foo #=> local-variable
puts defined? foo() #=> method

You may find this SO answer to be useful, especially this part:

Why does it make sense for local variables to "shadow" methods and not the way around? Well, if methods did shadow local variables, there would no longer be a way to dereference those local variables. However, if local variables shadow methods, then there is still a way to call those methods: remember, the ambiguity only exists for receiverless argumentless methods calls, if you add an explicit receiver or an explicit argument list, you can still call the method:

Upvotes: 2

Related Questions