On Fri, Aug 15, 2003 at 08:21:25PM +0900, Jim Weirich wrote:
> 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::operator()" << 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