Why can you chain this:
"Test".upcase.reverse.next.swapcase
but not this:
x = My_Class.new
x.a.b.c
where
class My_Class
def a
@b = 1
end
def b
@b = @b + 2
end
def c
@b = @b -72
end
end
The upcase
, reverse
, next
and swapcase
methods all return String
objects and all those methods are for... you guessed it, String
objects!
When you call a method (more often than not, like 99.9999% of the time) it returns an object. This object has methods defined on it which can then be called which explains why you can do this:
"Test".upcase.reverse.next.swapcase
You can even call reverse
as many times as you like:
"Test".reverse.reverse.reverse.reverse.reverse.reverse.reverse.reverse
All because it returns the same kind of object, a String
object!
But you can't do this with your MyClass
:
x = My_Class.new
x.a.b.c
For that to work, the a
method would have to return an object which has the b
method defined on it. Right now, that seems like only instances of MyClass
would have that. To get this to work you could make the return value of a
the object itself, like this:
def a
@b += 2
self
end
Extrapolating this, the b
method would also need to return self
as the c
method is available only on instances of the MyClass
class. It's not important what c
returns in this example, because it's the end of the chain. It could return self
, it could not. Schrödinger's cat method. Nobody knows until we open the box.
As support for other answers, this code:
"Test".upcase.reverse.next.swapcase
...is almost exactly the same as...
a = "Test"
b = a.upcase
c = b.reverse
d = c.next
e = d.swapcase
....except that my code above has extra variables left over pointing to the intermediary results, whereas the original leaves no extra references around. If we do this with your code:
x = MyClass.new # x is an instance of MyClass
y = x.a # y is 1, the last expression in the a method
z = y.b # Error: Fixnums have no method named 'b'
Using Ruby 1.9's tap
method, we can even make this more explicit:
irb> "Test".upcase.tap{|o| p o}.reverse.tap{|o| p o}.next.tap{|o| p o}.swapcase
#=> "TEST"
#=> "TSET"
#=> "TSEU"
=> "tseu"
irb> class MyClass
irb> def a
irb> @b = 1
irb> end
irb> def b
irb> @b += 2
irb> end
irb> end
=> nil
irb(main):011:0> x = MyClass.new
=> #<MyClass:0x000001010202e0>
irb> x.a.tap{|o| p o}.b.tap{|o| p o}.c
#=> 1
NoMethodError: undefined method `b' for 1:Fixnum
from (irb):12
from /usr/local/bin/irb:12:in `<main>'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With