Why foo is not nil anymore - or function within function - ruby

Why in below code snippet foo replaces its definition?
def foo
def foo
1
end
end
for the first time foo is nil
foo
=> nil
foo.foo
=> 1
Now if I call foo again:
foo
=> 1
As you can see foo is not nil anymore. Can some one explain this to me? thanks.

def foo
p "about to redef foo"
def foo
1
end
end
foo
"about to redef foo"
=> nil
foo
=> 1
Also, when you call foo.foo, it seems like you’re trying to access the inner foo method, but it doesn’t work that way. Your foo method is actually defined on Object, so you’re actually calling 1.foo.

If you want this effect, try
def foo
foo = proc {
1
}
end
Since def methods do not create a new self. Every method is bound
to self, which is main in this case, an Object.new which is
instantiated for every file loaded by the ruby interpreter. Inside a
class, self is the class, and you get instance methods.

Method definitions are parsed when read, but are not executed until called. When you do the first foo, the outermost foo is executed, which defines Object#foo as
def foo
1
end
and returns nil as the return value of an operation that defined the method. From then on, when you call foo, the newly defined foo is executed, returning
1

When your first call foo it returns method foo and when you call again foo it returns 1.
Read closure

Nested method definitions in ruby are confusing.
They are actually redefinitions!
What happens is that both definitions apply to the outmost context. That is both definitions define the same(!) method foo. Though the outer definition is interpreted when the file is read, while the inner definition is only interpreted when the outer method is called for the first time. It will then replace the initial definition.
Given this code
def foo
def foo
1
end
end
Let's walk through this:
when loading your file a global method foo is defined with the body def foo; 1; end.
when you call foo() this global method is executed and redefines the global method foo with the body 1, and returns nil since defining a method has no return value.
when you call foo().foo() the global method is executed and returns 1, on which the global method is executed again, returning 1 again.
Confusing here are two things, a) that nested method definition both apply to the same outer scope and b) that a global method can be called on any object.
Here's another example to demonstrate how nested definitions are actually redefinitions.
class A
def m(arg=nil)
def m; 42; end if arg
23
end
end
here's what happens
a = A.new
a.m # => 23
a.m # => 23
a.m(:magic) # => 23
a.m # => 42
a.m # => 42
as you can see, the nested definition is actually a redefinition.

Personally I always thought it very strange that it defines inner def on the class. I would think it more sensible to define it on the singleton. e.g. equivalent to def self.foo, since it is being called at the instance level and not the class level.
Either that, or it could only be callable from the method it is defined in --though that might not be as useful since we have lambdas.
One thing is for certain though, you will almost never see this in practice.

Related

Count initializations of Ruby Class

Is there a way to count the amount of instances that get created as long as the program is running?
Something like
class Foo
#bar = 0
def initialize
#bar += 1
end
end
won't work (#bar is nil in initialize).
Can this be done somehow?
You should use a class variable instead of an instance variable:
class Foo
##count = 0
def initialize
##count += 1
end
def Foo.get_count
##count
end
end
foo1 = Foo.new
foo2 = Foo.new
foo3 = Foo.new
puts Foo.get_count
# => 3
Instance variables belong to objects (aka instances), that's why they are called instance variables after all. Your first #bar is an instance variable of Foo, your second #bar is an instance variable of the newly-created instance of Foo. Those are two completely different objects (they aren't even of the same class: the newly-created instance is of class Foo, whereas Foo is of class Class).
You obviously need to increment #bar in a method called on Foo, not in a method called on instances of Foo. So, can we think about a method that is a) called on Foo and b) called everytime an instance is created? What about new?
class Foo
#bar = 0
def self.new(*)
#bar += 1
super
end
end
Okay, technically speaking, this doesn't count the number of instances, only the number of times new was called. Sometimes, instances get created without calling new, e.g. when de-serializing. This should be the closest you can get without resorting to ugly hacks of the interpreter internals.
You might think you can override allocate instead (I thought so, too), but I just tested it and it doesn't work. Presumably, the default implementation of new doesn't call allocate via normal means but actually uses the interpreter internal implementation directly.

Confusion with method call from IRB in Ruby

I was playing with method definition and calling to them in the main of IRB.
def show
p "hi"
end
#=> nil
show
#"hi"
#=> "hi"
self.show
#"hi"
#=> "hi"
The above are good and understood.
Now let's try something different:
def Foo
p "hi"
end
#=> nil
Foo
#NameError: uninitialized constant Foo
#from (irb):4
#from C:/Ruby193/bin/irb:12:in `<main>'
While the call to Foo has thrown an error as above,how does the below remove that?
self.Foo
#"hi"
#=> "hi"
In Ruby, you can call methods without a receiver and without an argument list. However, this means that there is an ambiguity: does foo mean "call method foo on the implicit receiver self without arguments, i.e. equivalent to self.foo()" or does it mean "dereference the variable foo"? Ruby can't know which you mean, so there are some simple rules.
For a local variable, the rule is that foo is always a method call, unless foo is statically known at parse time to be a local variable. So, when is it statically known to be a variable? When there was an assignment to that variable which was parsed (but not necessarily executed!) before the use.
Example:
foo # method call
if false
foo = 42 # will never be executed, but *will* be parsed
end
foo # variable dereference, since the `foo` assignment was parsed
For constant variables, the rule is even simpler: Foo is always interpreted as a constant dereference. Period.
So, how do you call a method with such a name? Easy: like I said, the ambiguity arises only for method calls with no argument list and no explicit receiver. So, if we add either one or both of those, Ruby will know that we are trying to call a method and not dereference a variable:
foo()
self.foo
self.foo()
Foo()
self.Foo
self.Foo()
Of course, in the example you gave above, only the first one will work. When you define a method at the top-level, it is added as a private method to Object, and private methods can only be called without an explicit receiver, even if that receiver is self. So, self.Foo won't work, because Foo is private. (Except in IRb, where, for convenience reasons, top-level methods are public.)

Simple Ruby puzzle on variable reference in a method

Why does this method return 1 rather than dying from infinite recursion?
def foo
foo ||= 1
end
foo # => 1
Rewritten the following way it does die:
def foo
foo.nil? ? 1 : foo
end
In the first case, foo ||= 1 refers to a local variable. Ruby always creates a local variable when you do assignment on a bareword, which is why you have to write self.foo = ... if you want to invoke a writer method defined as def foo=(value). The ||= operator is, after all, just a fancy assignment operator.
In the second case, there is no assignment, so when it hits foo.nil?, Ruby interprets the bareword foo as a method call, and blows up.

Why is "hello" printed twice in this Ruby script?

I decided to experiment with defining methods inside methods in Ruby and wrote this:
def foo
def bar
puts "hello"
end
bar
end
This defined, I ran foo and "hello" was printed as I expected. However I then tried foo.bar - which printed out "hello" twice. Why?
foo.bar equals foo().bar() so you call first foo which contains bar so it is executed once here, then bar is executed one more time. At the end bar is called twice.
def foo
puts 'foo called'
def bar
puts 'bar called'
puts "hello"
end
bar
end
foo.bar
#=> foo called
#=> bar called
#=> hello
#=> bar called
#=> hello
What I don't understand is this means the result of foo which is nil can call bar.
>> nil.bar
#=> hello
How is that possible ?
Edit: As explained in some answers, nested method are included in the class scope so weither bar is declared inside or outside foo does not make any difference.
Also Matz said that it may change from Ruby2.0
here is the example he wrote:
class Foo
def foo
def bar
#omited
end
bar # can be called
end
def quux
bar # cannot be called
end
end
edit-Ruby2.0: It finally did not get implemented. So it remains the same.
In Ruby, there is a hidden variable that doesn't get much attention. I don't know what it's called, but I call it the current class. This variable is the target of def
When you go into foo, it doesn't change this variable, you're still in the same class. So when you define another method inside of foo, that method gets defined on the same class as foo was defined on.
In this case, you're defining foo on main, the toplevel object. Main's current class variable is set to object, so any methods you define here will be available inside any object.
Since the last thing you do is return the result of bar, and bar returns nil (b/c puts returns nil), then foo.bar is nil.bar. And since you defined bar on Object, even nil inherits this method.
The interesting part is that bar is public. Since foo is defined in main, and main sets its scope to private, I would have expected bar to also be private, but I guess that state must lost once you go to a different scope.
Did you mean to put class foo? It seems that calling foo.bar calls the function foo and then the function bar. Calling nil.bar prints out 'hello' too.

How do I reference a function in Ruby?

In python, it's fairly straightforward to reference a function:
>>> def foo():
... print "foo called"
... return 1
...
>>> x = foo
>>> foo()
foo called
1
>>> x()
foo called
1
>>> x
<function foo at 0x1004ba5f0>
>>> foo
<function foo at 0x1004ba5f0>
However, it seems to be different in Ruby since a naked foo actually calls foo:
ruby-1.9.2-p0 > def foo
ruby-1.9.2-p0 ?> print "foo called"
ruby-1.9.2-p0 ?> 1
ruby-1.9.2-p0 ?> end
=> nil
ruby-1.9.2-p0 > x = foo
foo called => 1
ruby-1.9.2-p0 > foo
foo called => 1
ruby-1.9.2-p0 > x
=> 1
How do I actually assign the function foo to x and then call it? Or is there a more idiomatic way to do this?
Ruby doesn't have functions. It only has methods (which aren't first-class) and Procs which are first-class, but are not associated with any object.
So, this is a method:
def foo(bar) puts bar end
foo('Hello')
# Hello
Oh, and, yes, this is a real method, not a top-level function or procedure or something. Methods defined at the top-level end up as private(!) instance methods in the Object class:
Object.private_instance_methods(false) # => [:foo]
This is a Proc:
foo = -> bar { puts bar }
foo.('Hello')
# Hello
Notice that Procs are called differently from methods:
foo('Hello') # method
foo.('Hello') # Proc
The foo.(bar) syntax is just syntactic sugar for foo.call(bar) (which for Procs and Methods is also aliased to foo[bar]). Implementing a call method on your object and then calling it with .() is the closest thing you will get to Python's __call__ables.
Note that an important distinction between Ruby Procs and Python lambdas is that there are no restrictions: in Python, a lambda can only contain a single statement, but Ruby doesn't have the distinction between statements and expressions (everything is an expression), and so this limitation simply doesn't exist, therefore in a lot of cases where you need to pass a named function as an argument in Python because you cannot express the logic in a single statement, you would in Ruby simply pass a Proc or a block instead, so that the problem of the ugly syntax for referencing methods doesn't even arise.
You can wrap a method in a Method object (which essentially duck-types Proc) by calling the Object#method method on an object (which will give you a Method whose self is bound to that particular object):
foo_bound = method(:foo)
foo_bound.('Hello')
# Hello
You can also use one of the methods in the Module#instance_method family to get an UnboundMethod from a module (or class, obviously, since a class is-a module), which you can then UnboundMethod#bind to a particular object and call. (I think Python has the same concepts, albeit with a different implementation: an unbound method simply takes the self argument explicitly, just like the way it is declared.)
foo_unbound = Object.instance_method(:foo) # this is an UnboundMethod
foo_unbound.('Hello')
# NoMethodError: undefined method `call' for #<UnboundMethod: Object#foo>
foo_rebound = foo_unbound.bind(self) # this is a Method
foo_rebound.('Hello')
# Hello
Note that you can only bind an UnboundMethod to an object which is an instance of the module you took the method from. You cannot use UnboundMethods to "transplant" behavior between unrelated modules:
bar = module Foo; def bar; puts 'Bye' end; self end.instance_method(:bar)
module Foo; def bar; puts 'Hello' end end
obj = Object.new
bar.bind(obj)
# TypeError: bind argument must be an instance of Foo
obj.extend(Foo)
bar.bind(obj).()
# Bye
obj.bar
# Hello
Note, however, that both the Method and the UnboundMethod are wrappers around the method, not the method itself. Methods are not objects in Ruby. (Contrary to what I have written in other answers, BTW. I really need to go back and fix those.) You can wrap them in objects, but they aren't objects, and you can see that because you essentially get all the same problems you always get with wrappers: identity and state. If you call method multiple times for the same method, you will get a different Method object every time. If you try to store some state on that Method object (such as Python-style __doc__strings, for example), that state will be private to that particular instance, and if you try to retrieve your docstring again via method, you will find that it is gone.
There is also syntactic sugar in the form of the method reference operator .::
bound_method = obj.:foo
Which is identical to
bound_method = obj.method(:foo)
You can use the method instance method inherited from Object to retrieve a Method object, which essentially is a Proc object which you can invoke call on.
In the console, you'd do this:
fooMethod = self.method(:foo) #fooMethod is a Method object
fooMethod.call #invokes fooMethod
Ruby supports proc and lambda which in other languages might be called anonymous functions or closures, depending on how they are used. They might be closer to what you are looking for.
The (main) difference between functions and methods as copied from https://stackoverflow.com/a/26620095/226255
Functions are defined outside of classes, while methods are defined
inside of and part of classes.
Ruby does not have functions and your def foo ends up being a method for the Object class.
If you insist on defining foo like you're doing above, you can extract its "functionality" by doing this:
def foo(a,b)
a+b
end
x = method(:foo).to_proc
x.call(1,2)
=> 3
Explanation:
> method(:foo) # this is Object.method(:foo), returns a Method object bound to
# object of type 'Class(Object)'
=> #<Method: Class(Object)#foo>
method(:foo).to_proc
# a Proc that can be called without the original object the method was bound to
=> #<Proc:0x007f97845f35e8 (lambda)>
Important note:
to_proc "copies" the method's object's associated instance variables if any. Consider this:
class Person
def initialize(name)
#name = name
end
def greet
puts "hello #{#name}"
end
end
greet = Person.new('Abdo').method(:greet)
# note that Person.method(:greet) returns an UnboundMethod and cannot be called
# unless you bind it to an object
> greet.call
hello Abdo
=> nil
Conceptually, if you want a "function" that would work on a certain type of objects, it should be a method and you should organize your code as such. If you only need your "function" in a certain context and wish to pass it around, use lambdas:
greet = lambda { |person| "hello #{person}" }
yell_at = lambda { |person| "HELLO #{person.upcase}" }
def do_to_person(person, m)
m.call(person)
end
do_to_person('Abdo', greet)

Resources