Issue #6711 has been updated by rosenfeld (Rodrigo Rosenfeld Rosas).


matz (Yukihiro Matsumoto) wrote:
> Good try, but:
> 
> * You cannot use # sign as type specifier, since it's already used as a comment sign.

Wow, how did I completely forget about this?! :P

Well, I need to spend some time thinking in some valid syntax that won't conflict with named arguments.

> * You didn't defined how type match should be done, but simple class hierarchy match would hinder duck typing.

I've defined how type match works. It is just a matter that you don't agree with it :)

The motivation about simple class hierarchy (and not caring about duck typing) is for the usual cases I have in mind like a generic Numeric and specifics Float, Integer and BigDecimal.

Duck typing is simply ortogonal to typed arguments in my opinion.

Could you please elaborate on your opinions about typed arguments and duck typing? I couldn't understand your comment concerning this in #5583 either.

But I agree that I wasn't specific about the rules for included modules ("multiple inheritance"). The problem is that I don't have a real use case for this so this is a bit hard for me to define those rules at this point. I'll have to think more about this.
----------------------------------------
Feature #6711: Optional typing and method overloading
https://bugs.ruby-lang.org/issues/6711#change-27922

Author: rosenfeld (Rodrigo Rosenfeld Rosas)
Status: Rejected
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: 3.0


Today I woke up with some ideas to overcome some of the features I miss in Ruby. I've searched for similar issues and I found this #5583, which was rejected.

But my idea is a bit different and also concerns about method overloading. So I decided to open a new issue. I'll be also creating another feature request soon for introducing super! keyword for overrides of methods by reopening classes.

#5583 wants the checks to be made at compile time, while I think it should be a dynamic check instead.

For example:

class A
  def some_method(a)
    "a"
  end

  def some_method(a # Numeric)
    "a is a number"
  end

  def some_method(a, b)
    "untyped a and b"
  end

  def some_method(a, b # String)
    "typed b"
  end

  def some_method(a # String, b = 2)
    "typed a"
  end
end

class B < A
  def! some_method(*args) # overrides all overloaded methods - *args is not required for this
    if args[0].is_a? Number
      super(args[0])
    else
      'do something else'
    end
  end
end

The rule to decide over multiple alternatives should be by order:

1 - max number of better matched argument types # Float is a better match for 1.2 than Numeric
2 - max number of matched argument types
3 - max number of consecutive matched argument types

Example:

a = A.new
b = B.new

b.some_method == 'do something else'
b.some_method(1.3) == 'a is a number'
b.some_method('s') == 'do something else'
a.some_method('s') == 'typed a'
a.some_method('s', 's') == 'typed a'
a.some_method(:s, 's') == 'typed b'
a.some_method(:s) == 'a'
a.some_method(1, :s) == 'untyped a and b'

Current method and send are not affected. Argument-matching checks would happen at runtime

The goal is to make programmers happier, not be perform better.

m = a.method :some_method
m.call # raise arguments mismatch exception
m.call(:a) == 'a'

To get a specific method one could ask for it like:

m = a.method :some_method, nil, String # some_method(a, b # String)

We should also introduce "methods" for getting a list of all named methods defined:

# HTTP server dispatcher class example:

def handle_http_request(params)
  methods = controller.methods :some_method
  raise "Overloaded actions are not supported" unless methods.size == 1
  action = methods.first
  method_arguments = []
  action.arguments.each do |name, type, default_value = nil|
    hk = params.has_key? name
    (method_arguments << hk ? params[name] : default_value; next) unless hk && !type.nil?
    method_arguments << method(:bind_value, type).call params[name], type
  end
  action.call *method_arguments
end

def bind_value(value, type)
  value
end

def bind_value(value, type # Integer)
  value.to_i
end

def bind_value(value, type # Float)
  value.to_f
end

def bind_value(value, type # Numeric) # BigDecimal and Numeric would match for instance
  BigDecimal.new value
end

def bind_value(value, type # Date)
  Date.parse value
end

#...



-- 
http://bugs.ruby-lang.org/