I recently came across some code using a method call consisting of the format object.(arg1, arg2) without seeing a good explanation of how it works. See this sample code:
class TestServiceObject
def call
'method'
end
end
TestServiceObject.new.()
# => 'method'
What's the term for this kind of shorthand?
The dot-parentheses notation is a shorthand way for passing arguments to the implicit call method on a Ruby object:
foo = lambda {|bar| puts bar}
foo.call('baz')
#=> baz
foo.('baz')
foo.call('baz') === foo.('baz')
#=> true
Also note that the following notations are also valid (and equivalent) invocations of the call method:
foo['baz']
#=> baz
foo::('baz')
#=> baz
In your example, you're explicitly overriding the call method on the TestServiceObject class such that it returns the string 'method' when called. Accordingly, you can explicitly override the the call method to accept arguments:
class TestServiceObject
def call(foo=nil)
foo || 'method'
end
end
TestServiceObject.new.()
#=> method
TestServicesObject.new.('bar')
#=> bar
UPDATE:
As commenter #LoganSerman duly notes, the shorthand operator appears to work on anything that responds to call, which is validated in part by the following example:
m = 12.method("+")
m.call(3)
#=> 15
m.(3)
#=> 15
UPDATE 2:
As commenter #Stefan also points out from the documentation on Proc#call:
prc.() invokes prc.call() with the parameters given. It’s a syntax sugar to hide “call”.
foo.(bar, baz)
is interpreted as
foo.call(bar, baz)
just like
foo + bar
is interpreted as
foo.+(bar)
or
foo[bar, baz] = quux
is interpreted as
foo.[]=(bar, baz, quux)
The intention is to make calling function-like objects look similar to calling methods:
foo.(bar, baz) # function
foo(bar, baz) # method
Despite claims in other answers to this question, it has nothing to do with an "implicit call method" (Ruby doesn't even have implicit methods, only Scala does) or the indexing operator.
The indexing operator is translated into a different method call ([]) and not into a call to call:
o = Object.new
def o.call(*args); "`call` called with #{args.join(', ')}" end
o.(42)
# => "`call` called with 42"
o[42]
# NoMethodError: undefined method `[]' for #<Object:0xdeadbeefc0ffee>
def o.[](*args); "`[]` called with #{args.join(', ')}" end
o[42]
# => "`[]` called with 42"
obj.(args) is just a feature provided through the parser. Not technically an alias, but it simply has the same effect as invoking obj.call(args) on an object that defines the call method.
Related
When I'm coding in Ruby, to avoid type checks and respond_to?s and nil checks I often coerce objects into the type I expect. If I expect an Array, instead of foo.nil? ? handle_nil(foo) : handle_array(foo) I prefer to just handle_foo(foo.to_a) since nil.to_a # => [].
This doesn't work for everything, 1.to_a raises NoMethodError: undefined method 'to_a' for 1:Integer. 1.to_ary raises the same error. Array() seems to solve the problem, handling what seems like any object and either making a sensible conversion to an Array or wrapping it in [].
Array(nil) # => []
Array('') # => [""]
Array(Class) # => [Class]
Array(1) # => [1]
Array(Object.new) # => [#<Object:0x007fdbd40df4c8>]
Array({}) # => []
Array(foo: :bar) # => [[:foo, :bar]]
You can do the same thing with other classes too. String(), Float()... I'd used it a lot without thinking about the unusual syntax. I wanted to learn more about the implementation. Is it syntactic sugar for a special method, similar to #[]?
Both of these raise a SyntaxError
def self.(foo)
puts foo
end
def self.()(foo)
puts foo
end
You use Array() like you would use a method. Looking at the docs for Kernel it becomes clear that that's what's going on. The following works as you'd expect:
class Thing
attr_accessor :name
def initialize(name)
#name = name
end
end
module Kernel
def Thing(name)
Thing.new(name)
end
end
thing = Thing('name') # => #<Thing:0x007fefef89d8e8 #name="name">
thing.name # => "name"
You can also do this
HI = 'hi'.freeze
def HI(word)
word
end
HI # => "hi"
HI("ho") # => "ho"
My question is: How does Ruby interpret this? How does it distinguish between the method and the constant? Is this a silly question? Given "normal" behavior, one might expect Ruby to complain with a name warning when you define the method, or raise a SyntaxError. Does anyone know how Ruby handles this under the hood?
Thanks!
How does Ruby interpret this? How does it distinguish between the method and the constant?
The rules are pretty much the same as with local variables: Ruby will assume it is a constant unless it's obvious that it isn't: constants can't have arguments, and constants can't have receivers.
FOO # constant
self.FOO # message send
FOO() # message send
FOO :bar # message send
Given "normal" behavior, one might expect Ruby to complain with a name warning when you define the method, or raise a SyntaxError.
Why? Defining a method is perfectly legal syntactically (after all, that's what OO is all about), and Array is a perfectly legal Ruby identifier.
Say, inside of irb if I do
def foo
return 123
end
foo
it will give 123. That's because Ruby doesn't need the () to invoke the function. But how do I actually print out the function object? (kind of like in the JavaScript console, when I say function foo() {} and type foo, it will show foo as a function (object).)
You can use defined? for that:
def foo
return 123
end
foo
#=> 123
defined?(foo)
#=> "method"
A local variable would return:
bar = 123
#=> 123
defined?(bar)
#=> "local-variable"
Or:
def foo
return 123
end
foo
#=> 123
method(:foo)
#=> Object#foo()
method(:foo).call
#=> 123
Ruby in general doesn't use function / method objects. Oh, they're there: Method Class, but in general you don't pass method objects around in Ruby.
What you usually do instead are one of the following things:
Pass a symbol to execute on an object. So pass :foo instead (the the caller will use __send__ to execute the method.
Use the block syntax where you in Javascript would use an anon function
To see the source of a method, use something like pry show-method Class#method
Use defined? as previously suggested to test if a method is there
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.)
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)
In Ruby, I can define a method foo=(bar):
irb(main):001:0> def foo=(bar)
irb(main):002:1> p "foo=#{bar}"
irb(main):003:1> end
=> nil
Now I'd like to check if it has been defined,
irb(main):004:0> defined?(foo=)
SyntaxError: compile error
(irb):4: syntax error, unexpected ')'
from (irb):4
from :0
What is the proper syntax to use here? I assume there must be a way to escape "foo=" such that it is parsed and passed correctly to the defined? operator.
The problem is that the foo= method is designed to be used in assignments. You can use defined? in the following way to see what's going on:
defined?(self.foo=())
#=> nil
defined?(self.foo = "bar")
#=> nil
def foo=(bar)
end
defined?(self.foo=())
#=> "assignment"
defined?(self.foo = "bar")
#=> "assignment"
Compare that to:
def foo
end
defined?(foo)
#=> "method"
To test if the foo= method is defined, you should use respond_to? instead:
respond_to?(:foo=)
#=> false
def foo=(bar)
end
respond_to?(:foo=)
#=> true
You can check if a method exists by using the respond_to? method, and you pass it a symbol, e.g. bar.respond_to?(:foo=) to see if the object bar has a method foo=. If you want to know if instances of a class respond to a method you can use method_defined? on the class (or module), e.g. Foo.method_defined?(:bar=).
defined? isn't a method, but an operator which returns a description of the operand (or nil if it is not defined, which is why it can be used in an if statement). The operand can be any expression, i.e. a constant, a variable, an assignment, a method, a method call, etc. The reason why it doesn't work when you do defined?(foo=) is because of the parentheses, skip them and it should work more or less as expected. That being said, defined? is a pretty weird operator, and no one uses it to test for the existence of methods.