Overloading ()

D

Dan Doel

Hi,

I was reading the comp.lang.functional group, and happened across a
little discussion of Ruby vs. Python on there.
One thing the Python guy asked was whether you could pass a function in
Ruby so that you could call it like:

f(args)

Which looks more like a real function call. And I must admit, that at
first, I was kind of put off at not being able
to pass functions around in Ruby and call them like normal functions
(I've since gotten used to the alternatives).
It got me thinking, why isn't it possible to overload a () operator for
this purpose? Was it a design decision of
the language or does it just add too much of a hassle for the parser? Or
was it something else?

Not that I'm complaining or anything, since I don't mind the way Ruby
does it. I'm just curious what the reasoning
was.

Thanks in advance.

- Dan
 
J

Joel VanderWerf

Dan said:
Hi,

I was reading the comp.lang.functional group, and happened across a
little discussion of Ruby vs. Python on there.
One thing the Python guy asked was whether you could pass a function in
Ruby so that you could call it like:

f(args)

Which looks more like a real function call. And I must admit, that at
first, I was kind of put off at not being able
to pass functions around in Ruby and call them like normal functions
(I've since gotten used to the alternatives).
It got me thinking, why isn't it possible to overload a () operator for
this purpose? Was it a design decision of
the language or does it just add too much of a hassle for the parser? Or
was it something else?

Not that I'm complaining or anything, since I don't mind the way Ruby
does it. I'm just curious what the reasoning
was.

Here's one construction that becomes possible because () is not an operator:

def foo
3
end

foo = foo()
foo += 1
p foo # ==> 4

If () were an operator, the "foo()" syntax would have to be interpreted
as sending a #call message to the value of the local var "foo".

I don't know if that's the main justification or a side effect, though.
 
D

Dan Doel

Here's one construction that becomes possible because () is not an
operator:

def foo
3
end

foo = foo()
foo += 1
p foo # ==> 4

If () were an operator, the "foo()" syntax would have to be
interpreted as sending a #call message to the value of the local var
"foo".

I don't know if that's the main justification or a side effect, though.


Ah, that's true. I hadn't thought of that.

Seems like writing code like that is a bad idea, though, if you want to
be able to understand it in the future. :)

- Dan
 
F

Florian Frank

You probably already know this, but you can call it like:

f[args]

which looks somewhat similar to a regular function call.

BTW: That's syntactic sugar for Proc#call. I recently had a problem with
this method while experimenting with CPS and current continuations. I
have used [] to call a Proc object and the program broke as I
wanted to drop in Continuation object in its place because the latter
only support the call method. Perhaps it would be a good idea to add []
to Continuation to enable both to repsond to the same protocol?
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Overloading ()"

|Perhaps it would be a good idea to add []
|to Continuation to enable both to repsond to the same protocol?

Nice idea. I will add it.

matz.
 
D

Dave Benjamin

Phil Tomson said:
I know you can overload () in C++, but can you overload () in Python?

Yes, it's quite simple, actually:

class CallableClass:
def __call__(self):
print 'Hey there!'

cc = CallableClass()
cc()

Output:
"Hey, there!"
Seems like allowing overloading of () is a potential tarpit... and there
are potential parser issues as well, but I defer to matz to answer your
question.

I won't comment on whether the ability to overload () is good or bad,
necessarily (although it would be nice if Ruby's lambdas had normal
functional semantics), but I would be very interested in understanding the
issue from a language design standpoint, if you'd be so kind, Matz.

Thanks!
Dave
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: Overloading ()"

|I'm the "Python guy" from comp.lang.functional. ;) I'd still like to
|understand why the () operator can't be overloaded in Ruby, necessitating
|the use of [] for Proc objects instead. What was the motivation behind that
|restriction?

Because you don't always need parenthesises for method calls, for
example,

foo(1,2,3)
foo 1,2,3

obj.bar() # calling obj's method bar
obj.bar # still calling bar (*)

The last line is very important difference from Python. Python gives
you the method object "bar". It's functional, but Ruby way allows
attribute abstraction.

In addition, Ruby has separate namespace for variables and methods,
for example,

def foo
puts 55
end
foo = 42
puts foo # "42"
puts foo() # "55"

This also makes () hard to be overloaded.
matz.
 
P

Paul Brannan

But ... I'm wondering.

Is there some idiom that would be facilitated by overloading ()? The
only thing I can think of are C++ templates where the same bit of code
might cause f in "f()" to be bound to a function name at one invocation
or a functor object in another. Since Ruby doesn't have C++ like
templates, this isn't an issue.

I can't think of other useful scenarios, but then I'm probably
insufficiently imaginative.

The short answer is "no, I can't think of any". The longer answer
follows in the form of thinking out loud.

All callable objects in C++ respond to (). This includes function
objects, function pointers, and member function pointers.

All callable objects in Ruby repond to #call(). This includes Procs,
Methods, Continuations, and other objects. Many callable objects also
respond to #[] and #to_proc().

The same idioms apply in both cases; there is an object, and you want to
call it, but you don't care what kind of object it is. In C++ you use
(), and in Ruby you use #call().

I can imagine one other situation in C++:

#include <iostream>

struct Foo
{
void foo() { std::cout << "Foo::Foo()" << std::endl; }
};

struct Bar
{
struct Boo
{
void operator()() { std::cout << "Bar::Boo::eek:perator()" << std::endl; }
};
Boo foo;
};

template<typename T>
void foo(T t)
{
t.foo();
}

int main()
{
Foo f; foo(f);
Bar b; foo(b);
}

Here Foo and Bar both act like they have a member function foo(), but in
the case of Bar, it's just a function object that responds to ().

With a little bit of black magic, I can do this in Ruby without
overloading ():

class Foo
def foo; puts "Foo#foo"; end
end

class Bar
class Boo
def call; puts "Bar::Boo#call"; end
end
def initialize
@b = Boo.new
p = proc { @b.call() }
m = Module.new
m.instance_eval do
define_method:)foo, p)
end
self.extend(m)
end
end

def foo(t)
t.foo()
end

f = Foo.new; foo(f)
b = Bar.new; foo(b)

It's all a matter of creating an object that responds to the agreed-upon
protocol. C++ needs to be able to overload () for
backward-compatibility with C, because function pointers are not
first-class objects and can't have member functions. In Ruby there is
no such requirement.

Paul
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,109
Messages
2,570,671
Members
47,262
Latest member
EffiePju4

Latest Threads

Top