0

Lambdas (and procs) in Ruby are just objects with a call method, as in any OO language with functional programming glued on as an afterthought. There are also:

  • lambda.(<args>)
  • lambda[<args>]

as syntactic sugar for lambda.call().

Lua allows for a __call meta method, that lets me call an object, and in the background, the arguments (and the table) are handed to a real function that does the actual magic.

Lambdas don't feel like dealing with real functions since they are called with [] or .() instead of (). Why not add a () operator that can be overloaded? Then object() would be translated to mean object.(), same as with +, || or any other operator.

Wouldn't it make sense to have syntactic sugar that allows calling the lambda directly? Is this more a matter of design philosophy than technical limitations?

Addressing some "problems" (that aren't really problems) that people have brought up:

If a method returns a lambda, what does that method followed by () mean? does it call only the method, or also the returned lambda?

method() means call method. If that expression returns a lambda, method()() would then call said lambda. The opposite would make no sense at all.

If there is a method called foo, and a callable object called foo, what does foo() mean?

Answer: if foo is a method and a variable, what do you expect foo to evaluate to? The variable. Ruby already does deal with this kind of ambiguity by simply choosing the more intuitive of two options. Thus, if there is a method foo, foo() should call that method. If there's a callable method foo in the same scope, that'd be shadowed by the real function.

Community
  • 1
  • 1
DarkWiiPlayer
  • 6,871
  • 3
  • 23
  • 38
  • I'd also be interested to know if there's any objective reason to prevent this syntax. Here's a related question (duplicate?) : https://stackoverflow.com/questions/6343812/calling-applying-lambda-vs-function-call-the-syntax-in-ruby-is-different-why The answer isn't very satisfying though IMHO. – Eric Duminil Nov 21 '17 at 07:31
  • Here's [another explanation](https://stackoverflow.com/questions/1686844/why-isnt-the-ruby-1-9-lambda-call-possible-without-the-dot-in-front-of-the-pare). Supposedly Ruby doesn't permit () to be defined on an object because the parentheses are optional in a method call. I agree though, the .() syntax drives me nuts. – vladpisanov Nov 21 '17 at 07:37
  • 1
    Why fuss over just a single period? – sawa Nov 21 '17 at 07:39
  • @sawa: Because Ruby is all about syntactic sugar? – Eric Duminil Nov 21 '17 at 07:47
  • @chickenburgers: This makes the most sense to me. – Eric Duminil Nov 21 '17 at 07:48
  • 3
    @chickenburgers: it isn't really about "permitting it". It is simply impossible. If you were to allow it, then it would no longer be possible to know what `foo()` means. – Jörg W Mittag Nov 21 '17 at 12:48

1 Answers1

5

Why not add a () operator that can be overloaded?

It would be ambiguous. If object is both, a method and a local variable, then object refers to the local variable, whereas object() invokes the method:

def object
  123
end
object = :abc

object   #=> :abc
object() #=> 123

Changing this convention would likely break existing code.

That's (presumably) why Ruby has object.() – it is syntactic sugar for object.call:

class MyClass
  def call
    123
  end
end

object = MyClass.new
object.call #=> 123
object.()   #=> 123

Having a separate syntax to call lambdas allows to distinguish between a method call and calling a lambda which is returned by that method: (thanks Amadan for pointing that out)

def object
  -> { 123 }
end

object    #=> #<Proc:0x007fe494110a78@(irb):2 (lambda)>
object()  #=> #<Proc:0x007fe494110a78@(irb):2 (lambda)>

object.()   #=> 123
object().() #=> 123
Stefan
  • 109,145
  • 14
  • 143
  • 218
  • 1
    Even more so - consider `def make_yo_printer; lambda { puts "yo" }; end`. OP, under your proposal, what do you expect `make_yo_printer()` to do? Under current Ruby syntax, it is clear: `make_yo_printer` returns a lambda, `make_yo_printer()` as well, while `make_yo_printer.()` and `make_yo_printer().()` both execute it. But if `()` executes lambdas, it is not clear what do parentheses belong to in `make_yo_printer()`: to the `make_yo_printer` call, or to the returned lambda. This dilemma does not exist in Python, since `()` is always needed to execute a call. – Amadan Nov 21 '17 at 07:50
  • Code having the same name for local variables and methods probably deserves to break. – Eric Duminil Nov 21 '17 at 07:51
  • @Amadan: That's the reason indeed. Methods can be called without parens. – Eric Duminil Nov 21 '17 at 07:52
  • It seems pretty obvious to me that `object()` should return a lambda; ommitting () is just syntactic sugar, after all. To call the lambda it would be `object()()`. As for the ambiguity of an object and a method sharing a name, first of all I think that's a terrible style choice, secondly in that case `object` should be the object while `object()` should be the method. Simple, isn't it? and you could still access `object.()` like with other overloaded operators (`object.+(other_object)`). – DarkWiiPlayer Nov 21 '17 at 14:02
  • @Amadan same could be said about `method { ... }` though. Is `{ ... }` a block? is it a hash? The answer is simple, it's a block. Why? Because at some point somebody just defined it to be that way. Same goes for your example. Just make clear that `whatever()` calls `whatever` if it's a method, or tries the `()` operator if it isn't. That makes sense, is intuitive and wouldn't break any code. `make_yo_printer()` would then unambiguously call `make_yo_printer` and return a lambda, as any sane programmer would expect. – DarkWiiPlayer Nov 21 '17 at 14:07
  • @DarkWiiPlayer: Is it really that intuitive, and something any sane programmer would expect? It is key to the design of Ruby that there is no distinction between methods and properties. `arr.size` is a method; `arr.size()` is perfectly legal but weird. Now imagine if my method wasn't called `make_yo_printer` but `yo_printer`, and normal access being `yo_printer.call`? Now would you expect it to be equivalent to `yo_printer()` or `yo_printer()()`? – Amadan Nov 22 '17 at 03:32
  • If `yo_printer` returns a lambda, I'd expect both `yo_printer` and `yo_printer()` to return a lambda. Again, because `yo_printer` and `yo_printer()` should be the same according to how ruby is supposed to work. There's no ambiguity or uncertainty either; unlike in other languages, in ruby `object.attribute` is ALWAYS a method, even if its syntax makes it look like a real attribute. Also, if `yo_printer` was meant to be used like that, it'd be `print_yo`; if it returns a lambda, it's probably not meant to be called directly except in a few special cases. – DarkWiiPlayer Nov 23 '17 at 07:15