From: Thomas E Enebo Date: 2011-02-02T00:34:44+09:00 Subject: Re: why is overloading invalid in ruby. On Mon, Jan 31, 2011 at 9:10 PM, Gary Wright wrote: > > On Jan 31, 2011, at 2:47 PM, Charles Oliver Nutter wrote: > >> On Mon, Jan 31, 2011 at 1:27 PM, Thomas E Enebo wrote: >>> On Mon, Jan 31, 2011 at 9:00 AM, Gary Wright wrote: >>>> I think the original poster provided an example of overloading based on the number of parameters but not their type. >>>> Even restricting yourself to overloading by arity is a bit problematic in Ruby because the arity still has to be determined (in some cases) dynamically: >>> Actually, arity of callsite is always calculated  in Ruby to know if >>> you should throw an ArgumentError (3 for 0 specified sort of errors) > > Maybe I'm overlooking something but I wasn't suggesting that you don't need to calculate arity but instead was pointing out that you can't just calculate it at parse time but sometimes need to calculate it at call time. > > foo(1,2)     # the call arity can be computed at parse time > foo(*a)      # the call arity must be computed at call time > > So in an 'overload-based-on-arity' scheme there might be some optimization opportunities for some call sites but not for every call site. Yeah, that is certainly true in the general sense even in existing Ruby semantics. In your first example, we know that it is always a two-arg call (at parse time) so we can go through a two-arity call path and not 'box' the call parameters into an array. In the second case we might be able to know arity at parse time if we know 'a' is a literal array. If we don't then the optimizations we can do get more limited. You are correct that adding arity to the mix would make the optimizations more complex, but I think it depends on the case and what you get by supporting it. For example, in the second case if we made our callsite cache lookup the methods foo and cache all of them at the site, then dispatch to the appropriate one, we would have quite a bit more complicated callsite cache (since we would need to invalidate it if any arity version changed), but this would dispatch much faster than doing things like you are showing in the example later in your email (actually much faster than any pure-Ruby logic for arity resolution). In the case where there was only one arity it would behave more or less like it does currently. The main change would be on any same-named method we would need to invalidate. [Note: This is just one way this could be done and callsite invalidation would be about the same as what it is now since it would invalidate based on name. We could do it name+arity. We could do it both ways even (perhaps name+arity for first case and only name for second). With all this said, it seems like a good idea to me, but OTOH no feature is without its caveats. I am more worried about Ruby programming style than performance and though it seems to pass a smell test for me...I don't think I am in the 'yeah let's do it camp' yet. I am probably in the 'someone should play with this' camp. > > Seems like you can get pretty far though with just a little meta-programming with no special language support: > > module Arity >  def overload(base) >    define_method(base) do |*args| >      argc = args.size >      method_name = "#{base}_#{argc}" >      if respond_to?(method_name) >        send(method_name, *args) >      else >        raise ArgumentError, "wrong number of arguments (no method for #{argc} arguments)" >      end >    end >  end > end > > class A >  extend Arity > >  overload :foo > >  def foo_0 >    puts "foo with no arguments" >  end > >  def foo_1(arg1) >    puts "foo with 1 argument: #{arg1.inspect}" >  end > > end > > A.new.foo           # dispatches to A#foo_0 > A.new.foo(1)        # dispatches to A#foo_1 > A.new.foo(1,2)      # ArgumentError > > > Gary Wright > > -- blog: http://blog.enebo.com       twitter: tom_enebo mail: tom.enebo@gmail.com