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.
Related
Say I am monkey patching a method in a class, how could I call the overridden method from the overriding method? I.e. Something a bit like super
E.g.
class Foo
def bar()
"Hello"
end
end
class Foo
def bar()
super() + " World"
end
end
>> Foo.new.bar == "Hello World"
EDIT: It has been 9 years since I originally wrote this answer, and it deserves some cosmetic surgery to keep it current.
You can see the last version before the edit here.
You can’t call the overwritten method by name or keyword. That’s one of the many reasons why monkey patching should be avoided and inheritance be preferred instead, since obviously you can call the overridden method.
Avoiding Monkey Patching
Inheritance
So, if at all possible, you should prefer something like this:
class Foo
def bar
'Hello'
end
end
class ExtendedFoo < Foo
def bar
super + ' World'
end
end
ExtendedFoo.new.bar # => 'Hello World'
This works, if you control creation of the Foo objects. Just change every place which creates a Foo to instead create an ExtendedFoo. This works even better if you use the Dependency Injection Design Pattern, the Factory Method Design Pattern, the Abstract Factory Design Pattern or something along those lines, because in that case, there is only place you need to change.
Delegation
If you do not control creation of the Foo objects, for example because they are created by a framework that is outside of your control (like ruby-on-rails for example), then you could use the Wrapper Design Pattern:
require 'delegate'
class Foo
def bar
'Hello'
end
end
class WrappedFoo < DelegateClass(Foo)
def initialize(wrapped_foo)
super
end
def bar
super + ' World'
end
end
foo = Foo.new # this is not actually in your code, it comes from somewhere else
wrapped_foo = WrappedFoo.new(foo) # this is under your control
wrapped_foo.bar # => 'Hello World'
Basically, at the boundary of the system, where the Foo object comes into your code, you wrap it into another object, and then use that object instead of the original one everywhere else in your code.
This uses the Object#DelegateClass helper method from the delegate library in the stdlib.
“Clean” Monkey Patching
Module#prepend: Mixin Prepending
The two methods above require changing the system to avoid monkey patching. This section shows the preferred and least invasive method of monkey patching, should changing the system not be an option.
Module#prepend was added to support more or less exactly this use case. Module#prepend does the same thing as Module#include, except it mixes in the mixin directly below the class:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super + ' World'
end
end
class Foo
prepend FooExtensions
end
Foo.new.bar # => 'Hello World'
Note: I also wrote a little bit about Module#prepend in this question: Ruby module prepend vs derivation
Mixin Inheritance (broken)
I have seen some people try (and ask about why it doesn’t work here on StackOverflow) something like this, i.e. includeing a mixin instead of prepending it:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super + ' World'
end
end
class Foo
include FooExtensions
end
Unfortunately, that won’t work. It’s a good idea, because it uses inheritance, which means that you can use super. However, Module#include inserts the mixin above the class in the inheritance hierarchy, which means that FooExtensions#bar will never be called (and if it were called, the super would not actually refer to Foo#bar but rather to Object#bar which doesn’t exist), since Foo#bar will always be found first.
Method Wrapping
The big question is: how can we hold on to the bar method, without actually keeping around an actual method? The answer lies, as it does so often, in functional programming. We get a hold of the method as an actual object, and we use a closure (i.e. a block) to make sure that we and only we hold on to that object:
class Foo
def bar
'Hello'
end
end
class Foo
old_bar = instance_method(:bar)
define_method(:bar) do
old_bar.bind(self).() + ' World'
end
end
Foo.new.bar # => 'Hello World'
This is very clean: since old_bar is just a local variable, it will go out of scope at the end of the class body, and it is impossible to access it from anywhere, even using reflection! And since Module#define_method takes a block, and blocks close over their surrounding lexical environment (which is why we are using define_method instead of def here), it (and only it) will still have access to old_bar, even after it has gone out of scope.
Short explanation:
old_bar = instance_method(:bar)
Here we are wrapping the bar method into an UnboundMethod method object and assigning it to the local variable old_bar. This means, we now have a way to hold on to bar even after it has been overwritten.
old_bar.bind(self)
This is a bit tricky. Basically, in Ruby (and in pretty much all single-dispatch based OO languages), a method is bound to a specific receiver object, called self in Ruby. In other words: a method always knows what object it was called on, it knows what its self is. But, we grabbed the method directly from a class, how does it know what its self is?
Well, it doesn’t, which is why we need to bind our UnboundMethod to an object first, which will return a Method object that we can then call. (UnboundMethods cannot be called, because they don’t know what to do without knowing their self.)
And what do we bind it to? We simply bind it to ourselves, that way it will behave exactly like the original bar would have!
Lastly, we need to call the Method that is returned from bind. In Ruby 1.9, there is some nifty new syntax for that (.()), but if you are on 1.8, you can simply use the call method; that’s what .() gets translated to anyway.
Here are a couple of other questions, where some of those concepts are explained:
How do I reference a function in Ruby?
Is Ruby’s code block same as C♯’s lambda expression?
“Dirty” Monkey Patching
alias_method chain
The problem we are having with our monkey patching is that when we overwrite the method, the method is gone, so we cannot call it anymore. So, let’s just make a backup copy!
class Foo
def bar
'Hello'
end
end
class Foo
alias_method :old_bar, :bar
def bar
old_bar + ' World'
end
end
Foo.new.bar # => 'Hello World'
Foo.new.old_bar # => 'Hello'
The problem with this is that we have now polluted the namespace with a superfluous old_bar method. This method will show up in our documentation, it will show up in code completion in our IDEs, it will show up during reflection. Also, it still can be called, but presumably we monkey patched it, because we didn’t like its behavior in the first place, so we might not want other people to call it.
Despite the fact that this has some undesirable properties, it has unfortunately become popularized through AciveSupport’s Module#alias_method_chain.
An aside: Refinements
In case you only need the different behavior in a few specific places and not throughout the whole system, you can use Refinements to restrict the monkey patch to a specific scope. I am going to demonstrate it here using the Module#prepend example from above:
class Foo
def bar
'Hello'
end
end
module ExtendedFoo
module FooExtensions
def bar
super + ' World'
end
end
refine Foo do
prepend FooExtensions
end
end
Foo.new.bar # => 'Hello'
# We haven’t activated our Refinement yet!
using ExtendedFoo
# Activate our Refinement
Foo.new.bar # => 'Hello World'
# There it is!
You can see a more sophisticated example of using Refinements in this question: How to enable monkey patch for specific method?
Abandoned ideas
Before the Ruby community settled on Module#prepend, there were multiple different ideas floating around that you may occasionally see referenced in older discussions. All of these are subsumed by Module#prepend.
Method Combinators
One idea was the idea of method combinators from CLOS. This is basically a very lightweight version of a subset of Aspect-Oriented Programming.
Using syntax like
class Foo
def bar:before
# will always run before bar, when bar is called
end
def bar:after
# will always run after bar, when bar is called
# may or may not be able to access and/or change bar’s return value
end
end
you would be able to “hook into” the execution of the bar method.
It is however not quite clear if and how you get access to bar’s return value within bar:after. Maybe we could (ab)use the super keyword?
class Foo
def bar
'Hello'
end
end
class Foo
def bar:after
super + ' World'
end
end
Replacement
The before combinator is equivalent to prepending a mixin with an overriding method that calls super at the very end of the method. Likewise, the after combinator is equivalent to prepending a mixin with an overriding method that calls super at the very beginning of the method.
You can also do stuff before and after calling super, you can call super multiple times, and both retrieve and manipulate super’s return value, making prepend more powerful than method combinators.
class Foo
def bar:before
# will always run before bar, when bar is called
end
end
# is the same as
module BarBefore
def bar
# will always run before bar, when bar is called
super
end
end
class Foo
prepend BarBefore
end
and
class Foo
def bar:after
# will always run after bar, when bar is called
# may or may not be able to access and/or change bar’s return value
end
end
# is the same as
class BarAfter
def bar
original_return_value = super
# will always run after bar, when bar is called
# has access to and can change bar’s return value
end
end
class Foo
prepend BarAfter
end
old keyword
This idea adds a new keyword similar to super, which allows you to call the overwritten method the same way super lets you call the overridden method:
class Foo
def bar
'Hello'
end
end
class Foo
def bar
old + ' World'
end
end
Foo.new.bar # => 'Hello World'
The main problem with this is that it is backwards incompatible: if you have method called old, you will no longer be able to call it!
Replacement
super in an overriding method in a prepended mixin is essentially the same as old in this proposal.
redef keyword
Similar to above, but instead of adding a new keyword for calling the overwritten method and leaving def alone, we add a new keyword for redefining methods. This is backwards compatible, since the syntax currently is illegal anyway:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
old + ' World'
end
end
Foo.new.bar # => 'Hello World'
Instead of adding two new keywords, we could also redefine the meaning of super inside redef:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
super + ' World'
end
end
Foo.new.bar # => 'Hello World'
Replacement
redefining a method is equivalent to overriding the method in a prepended mixin. super in the overriding method behaves like super or old in this proposal.
Take a look at aliasing methods, this is kind of renaming the method to a new name.
For more information and a starting point take a look at this replacing methods article (especially the first part).
The Ruby API docs, also provides (a less elaborate) example.
The class that will make override must to be reloaded after class that contains the original method, so require it in the file that will make overrride.
When I want to include a module into a Minitest/spec test, I can access the functions from the module, but not the classes defined in it. Example:
module Foo
def do_stuff
end
class Bar
end
end
x=describe Foo do
include Foo
end
p x.constants # shows :Bar
describe Foo do
include Foo
it "foos" do
do_stuff # works
Bar.new # raises a NameError
end
end
Running this snippet gives me a "NameError: uninitialized constant Bar", however, the p x.constantsshows that Bar is defined. I looked into the Minitest source code for describe and it uses class_eval on the block in the context of some anonymous class. When I do that in the context of a normal class it works fine and I can access Bar. Why doesn't it work with describe/it or what do I have to do in order to access the classes directly?
EDIT:
Interestingly, if you call class_eval directly on some class the included class Bar can be found, e.g.
class Quux
def it_foos
do_stuff # works
Bar.new # does NOT raise a NameError
end
end
Quux.class_eval do
include Foo
end
Quux.new.it_foos
won't throw a NameError...
If you check the documentation for #class_eval (for example, https://ruby-doc.org/core-2.5.0/Module.html#method-i-class_eval) you will see the answer there: "Evaluates the string or block in the context of mod, except that when a block is given, constant/class variable lookup is not affected".
So, include within class_eval simply doesn't affect constants resolution.
As far as I understand from the short look at minitest's source code, describe internally creates a new anonymous class (let's name it C) and casts class_eval on it with the block you provide. During this call its create the respective test instance methods that are executed later. But include doesn't affect constants resolution for C, so Bar stays unknown.
There is an obvious (and quite ugly) solution - the following should work because you include Foo into outer context, so Bar goes into lexical scope accessible for describe:
include Foo
describe Foo do
it "foos" do
do_stuff
Bar.new
end
end
But tbh I'd avoid such code. Probably it's better to set up the class mock explicitly, smth like
module Foo
def do_stuff
"foo"
end
class Bar
def do_stuff
"bar"
end
end
end
...
describe Foo do
let(:cls) { Class.new }
before { cls.include(Foo) }
it "foos" do
assert cls.new.do_stuff == "foo"
end
it "bars" do
assert cls::Bar.new.do_stuff == "bar"
end
end
(but take pls the latter with a grain of salt - I almost never use Minitest so have no idea of its "common idioms")
From what I understand about self, it refers to the current instance of the class.
Isn't this the default behaviour at all times anyways? For example, isn't
self.var_one = method(args)
equivalent to
var_one = method(args)
If so, what is the use of self?
There are several important uses, most of which are basically to disambiguate between instance methods, class methods, and variables.
First, this is the best way to define class methods:
class Foo
def self.bar
"class method bar"
end
def bar
"instance method bar"
end
end
Foo.bar #returns "class method bar"
foo = Foo.new
foo.bar #returns "instance method bar"
Also, within instance methods self refers to the instance, within class methods it refers to the class, and it can always be used to distinguish from local variables.
class Bar
def self.foo
"foo!"
end
def baz
"baz!"
end
def self.success
foo #looks for variable foo, doesn't find one, looks for class method foo, finds it, returns "foo!"
end
def self.fail
baz #looks for variable baz, doesn't find one, looks for class method baz, doesn't find one, raises exception
end
def instance_success
baz #looks for variable baz, doesn't find one, looks for instance method baz, finds it, returns "baz!"
end
def instance_fail
foo #looks for variable foo, doesn't find one, looks for instance method foo, doesn't find one, raises exception
end
def local_variable
baz = "is my favorite method"
baz #looks for variable baz, finds it, returns "is my favorite method"
end
def disambiguate
baz = " is my favorite method"
self.baz + baz #looks for instance method baz, finds it, looks for local variable baz, finds it, returns "baz! is my favorite method"
end
end
So, in the end, you can avoid using self in many cases, but it's often helpful to use it to make sure that you don't inadvertently create naming conflicts later on. Sometimes those can create bugs that are very hard to find. In the end it's often a matter of personal style.
As noted in the comments, one more really important thing:
In a class, if you have a method like this:
def bar=(string)
...
end
And in another method you call:
def other_method
bar = "abcd"
end
It isn't going to call your bar= method, it's going to create a local variable bar. So, in this case you use self to tell Ruby not to create a local variable:
def other_method
self.bar = "abcd"
end
The same thing applies if you want to take an argument with the name of a method:
def example
...
end
def other_thing(example)
self.example(example)
end
If you left off self Ruby would assume you meant the local variable with the same name.
So, in general, self in method names is used to distinguish between class and instance variables, and everywhere else you use it when Ruby needs help distinguishing between method calls and local variables or local variable assignment.
I hope that makes sense.
In most cases self.foo is indeed redundant because you can just write foo for the same effect, but in this case it is not and the self is required.
var_one = method(args) will create a local variable called var_one, it will not call any method or do anything else to self.
self.var_one = method(args) will call the method var_one= on self with the argument method(args).
Another case where the use of self is non-optional would be if you want to pass it as an argument to a method, i.e. some_method(self) - you can't do that without the self keyword.
One other use of self is to declare class methods (similar to static methods in Java).
class foo
def self.bar
#do class related stuff here
end
end
That being said, you could also have used def foo.bar instead for the method signature.
Here's an example:
def run miles
self.miles = miles
end
In this case self will help. In most cases self is redundant.
I have a base class with child classes that override a method that takes multiple arguments.
class Parent
def foo *bar
end
end
class Child < Parent
def foo bar, baz
end
end
This works fine. However, suppose there is a method foobar in Parent that calls foo:
def foobar *foo_args
foo foo_args
end
This raises a ArgumentError when called on a Child instance because foo_args is one single array, while Child.new.foo expects two objects. Is there a way around this?
Your question is not clear, but I think this may be what you want:
def foobar *foo_args
foo(*foo_args)
end
Still, Child.new.foo must take exactly two arguments for it to not raise an error.
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.