def foo
"foo"
end
alias foo2 foo
puts "foo2: " + foo2.object_id.to_s
puts "foo: " + foo.object_id.to_s
In the above example, I expected to see the same object_id output for each method call since they reference the same method. Why do I see different object_id's? When you alias a method in Ruby doesn't the alias refer to the original object, not a copy?
Starting over with a new answer in response to your various comments.
In the example code, you are calling the method, not referencing it. You want to use
method(:foo)
to actually get the method itself and not the result of calling it.
Also, object_id is not the right way to test if two methods are the same, because method(:foo) returns a new Method object each time. For an analogy that might make this clearer, if you opened the same file twice you would have two distinct file handles even though the underlying file was the same. Instead, I think you want:
method(:foo) == method(:foo2)
which, as you will see if you try it, returns true.
You're calling object_id on the object returned by foo, which is a string created in the method and thus will be different every time. You'd see the same results if you just called foo twice. It returns a new string every time. If you want a constant string, return the symbol :foo instead.
Past that, even though they share the same implementation right now, they are different methods. If you override foo to return the string "bar", foo2 will still keep returning "foo".
Try:
FOO = "foo"
def foo
FOO
end
alias foo2 foo
puts "foo2: " + foo2.object_id.to_s
puts "foo: " + foo.object_id.to_s
To get the effect you are wanting. "foo" is an expression and it gets evaluated each time the function is called. To see why this is, consider that you could just as well have written:
def foo
"It is now #{Time.now}"
end
alias foo2 foo
puts "foo2: " + foo2.object_id.to_s
puts "foo: " + foo.object_id.to_s
Related
Given this script
def hash
puts "why?"
end
x = {}
x[[1,2]] = 42
It outputs the following
why?
/tmp/a.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError)
from /tmp/a.rb:6:in `<main>'
It seems that the hash function defned in the script is overriding Array#hash in that case. Since the return value of my hash method is nil and not an Integer, it throws an exception. The following script seems to confirm this
puts [1,2,3].hash
def hash
puts "why?"
end
puts [1,2,3].hash
The output is
-4165381473644269435
why?
/tmp/b.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError)
from /tmp/b.rb:6:in `<main>'
I tried looking into the Ruby source code but could not figure out why this happens. Is this behavior documented?
You're not overriding Array#hash, you're shadowing Kernel#hash by creating Object#hash:
puts method(:hash)
def hash
puts "why?"
end
puts method(:hash)
That prints:
#<Method: Object(Kernel)#hash>
#<Method: Object#hash>
Fix it so we can see more:
def hash
puts "why?"
super
end
x = {}
x[[1,2]] = 42
Now the output is:
why?
why?
And no error. Try it with x[[1,2,3,4,5,6,7]] = 42 and you'll instead see why? printed seven times. Once for each array element, since the array's hash method uses the hashes of its elements. And Integer#hash doesn't exist, it inherits its hash method from Object/Kernel, so yours gets used.
This is due to a kind of hack in Ruby top level. Have you ever wondered how this works?
def foo
end
p self
foo
class Bar
def test
p self
foo
end
end
Bar.new.test # no error
How are two totally different objects (main and a Bar) able to call foo like it's a private method call? The reason is because... it is a private method call.
When you define a method at the top level of your Ruby script, it gets included (via Object) in every object. That's why you can call top-level methods like they are global functions.
But why does this break only hash and not other common methods? def to_s;end won't break to_s, for example. The reason is because hash is recursive: most* class implementations ultimately call down to Object#hash for their implementations. By redefining that base case, you break it globally. For other methods like to_s you won't see a global change because it's way up the inheritance chain and doesn't get invoked.
* the only objects this doesn't break are a few literals that probably have hard-coded hash values e.g. [] {} "" true etc.
Method calls can usually omit the receiver and the parentheses for the arguments:
def foo; "foo" end
foo # => "foo"
In the case above, foo is ambiguous between method call and reference to a potential local variable. In the absence of the latter, it is interpreted as a method call.
However, when the method name can in principle be a constant name (i.e., when it starts with a capital letter, and consists only of letters), it seems to need disambiguation.
def Foo; "Foo" end
Foo # => NameError: uninitialized constant Foo
Foo() # => "Foo"
self.Foo # => "Foo"
Why is this the case? Why does a method call need to be explicitly distinguished from a reference to a constant even under the absence of a constant with the same name?
The set of local variables which is in scope at any given point in the program is defined lexically and can thus be determined statically, even as early as parse time. So, Ruby knows even before runtime which local variables are in scope and can thus distinguish between a message send and a local variable dereference.
Constants are looked up first lexically, but then via inheritance, i.e. dynamically. It is not known which constants are in scope before runtime. Therefore, to disambiguate, Ruby always assumes it's a constant, unless obviously it isn't, i.e. it takes arguments or has a receiver or both.
There's no big reason behind the difference. I just wanted foo to be behave like foo(), if there's no local variable foo in the scope. I thought it was useful for creating DSL etc. But I saw no reason to make Foo to behave like Foo().
You ask a great question. As you point out ruby wants to treat it as a constant and therefore do a constant lookup.
The following snippet however shows the current behavior, and then by modifying const_missing, you seem to get the desired behavior. And to tell you the truth I can't seem to break anything.
My conclusion is that this was as somebody already suggested, just a design decision, but its odd because in general ruby favors convention vs enforcement.
Or I am missing some case where things do get confusing and the wrong thing happens.
<script type="text/ruby">
def puts(s); Element['#output'].html = Element['#output'].html + s.to_s.gsub("\n", "<br/>").gsub(" ", " ") + "<br/>"; end
class ImAClass
def self.to_s
"I am ImAClass Class"
end
end
def ImAMethod
"hello"
end
class DontKnowWhatIAm
def self.to_s
"a Class"
end
end
def DontKnowWhatIAm
"a method"
end
puts "ImAClass: #{ImAClass}"
begin
puts "ImAMethod: #{ImAMethod}"
rescue Exception => e
puts "confusion! #{e.message}"
end
puts "ImAMethod(): #{ImAMethod()}"
puts "DontKnowWhatIAm: #{DontKnowWhatIAm}"
puts "DontKnowWhatIAm(): #{DontKnowWhatIAm()}"
class Module
alias_method :old_const_missing, :const_missing
def const_missing(c)
if self.respond_to? c
self.send c
else
old_const_missing(c)
end
end
end
class Foo
def self.Bar
"im at the bar"
end
end
puts "now we can just say: Foo::Bar and it works! #{Foo::Bar}"
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/reactive-ruby/inline-reactive-ruby/master/inline-reactive-ruby.js"></script>
<div id="output" style="font-family: courier"></div>
I am new to ruby and doing some basic string manipulation to get the hang of it and I noticed that foo = 'foo'.downcase! is not the same as downcasing after assigning a vale to foo like this:
foo = 'foo'.downcase!
if foo.include? 'foo'
print 'bar'
end
This will result in an NoMethodError: undefined method `include?' for nil:NilClass (NoMethodError)
While downcasing foo after the value has been assigned does not:
foo = 'foo'
foo.downcase!
if foo.include? 'foo'
print 'bar'
end
I am sorry if this is a trivial question but a few minutes of googling didn't return anything fruitful.
This is because String#downcase! is a destructive method (hence the !) meaning it operates on the object in place. Since it changes the object itself, its return value isn't need. The Ruby designers decided that a good use of the return value would be to indicate if any changes were made.
Downcases the contents of str, returning nil if no changes were made.
Your string is already lowercase, so downcase! returns nil which you then replace the variable with.
String#downase! returns nil if the change can't be done on the receiver string object. That's the reason foo = 'foo'.downcase! causes the local variable foo to be assginbed as nil. Because foo string is already dowcased.
That's why if foo.include? 'foo' became if nil.include? 'foo'. As we know Nilclass#include? doesn't exist, so you got the error.
But String#downcase returns the receiver itself, if no change can be done, or changed new string object if change can be done.
In the below example :
The downcase! method returns nil (reason as I mentioned in the first paragraph), but as you didn't do local variable assignment, while you are calling the method (which is the case of your first example), thus foo still holding the original object 'foo'.
foo = 'foo'
foo.downcase!
That's the reason if foo.include? 'foo' became if "foo".include? "foo". But you are calling #include? on 'foo' an instance of String and String#include? method exist, thus no error you got.
You're seeing this behaviour because of this bit:
'foo'.downcase!
The downcase! method is an in-place substitution, meaning that it affects only the object that it was called on. It will only return a result when the string is changed. For example...
foo = 'foo'.downcase! # foo == NilClass, because 'foo' is already lower-case.
bar = 'BAR'.downcase! # bar == String, because 'BAR' was changed to 'bar'
If you need to guarantee that foo is a string after doing a downcase, you can use the non-intrusive downcase method (note the missing exclamation point).
foo = 'foo'.downcase
if foo.include? 'foo'
print 'bar'
end
The above code should always work. As a rule, it's generally a good idea to work with strings as immutable, rather than using the intrusive methods, as it can simplify code quite a lot, and avoid bugs like this.
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.
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.