¿Por qué no se sobrecarga el método de soporte ruby?

En lugar de soportar la sobrecarga de métodos, Ruby sobrescribe los métodos existentes. ¿Alguien puede explicar por qué el lenguaje fue diseñado de esta manera?

La sobrecarga de métodos se puede lograr al declarar dos métodos con el mismo nombre y diferentes firmas. Estas diferentes firmas pueden ser cualquiera,

  1. Argumentos con diferentes tipos de datos, por ejemplo: method(int a, int b) vs method(String a, String b)
  2. Número variable de argumentos, por ejemplo: method(a) vs method(a, b)

No podemos lograr la sobrecarga de métodos usando la primera vía porque no hay statement de tipo de datos en ruby ​​( lenguaje de tipado dynamic ). Entonces, la única forma de definir el método anterior es def(a,b)

Con la segunda opción, podría parecer que podemos lograr una sobrecarga de métodos, pero no podemos. Digamos que tengo dos métodos con diferente cantidad de argumentos,

 def method(a); end; def method(a, b = true); end; # second argument has a default value method(10) # Now the method call can match the first one as well as the second one, # so here is the problem. 

Entonces ruby ​​necesita mantener un método en la cadena de búsqueda de métodos con un nombre único.

“Sobrecarga” es un término que simplemente no tiene sentido en Ruby. Básicamente es un sinónimo de “despacho basado en argumentos estáticos”, pero Ruby no tiene despacho estático en absoluto . Por lo tanto, la razón por la que Ruby no admite el envío estático basado en los argumentos es porque no admite el envío estático, punto. No admite el envío estático de ningún tipo , ya sea basado en argumentos o de otro modo.

Ahora, si no está preguntando específicamente sobre la sobrecarga, pero quizás sobre el envío basado en argumentos dynamics , entonces la respuesta es: porque Matz no lo implementó. Porque nadie más se molestó en proponerlo. Porque nadie más se molestó en implementarlo.

En general, el despacho dynamic basado en argumentos en un lenguaje con argumentos opcionales y listas de argumentos de longitud variable es muy difícil de entender, y aún más difícil de entender. Incluso en lenguajes con despacho basado en argumentos estáticos y sin argumentos opcionales (como Java, por ejemplo), a veces es casi imposible distinguir un simple mortal, cuya sobrecarga se va a recoger.

En C #, puedes codificar cualquier problema 3-SAT en resolución de sobrecarga, lo que significa que la resolución de sobrecarga en C # es NP-hard.

Ahora intenta eso con el despacho dynamic , donde tienes la dimensión de tiempo adicional para tener en cuenta.

Hay idiomas que se distribuyen dinámicamente en función de todos los argumentos de un procedimiento, a diferencia de los lenguajes orientados a objetos, que solo se distribuyen en el self argumento zeroth “oculto”. Common Lisp, por ejemplo, distribuye los tipos dynamics e incluso los valores dynamics de todos los argumentos. Clojure distribuye en una función arbitraria de todos los argumentos (que BTW es extremadamente genial y extremadamente poderoso).

Pero no conozco ningún lenguaje OO con despacho dynamic basado en argumentos. Martin Odersky dijo que podría considerar agregar un despacho basado en argumentos a Scala, pero solo si puede eliminar la sobrecarga al mismo tiempo y ser compatible con versiones anteriores tanto con el código Scala existente que usa sobrecarga y compatible con Java (mencionó especialmente Swing y AWT que juegan algunos trucos extremadamente complejos que practican casi todos los desagradables rincón oscuro de las complejas reglas de sobrecarga de Java). También tuve algunas ideas sobre cómo agregar el envío basado en argumentos a Ruby, pero nunca pude encontrar la manera de hacerlo de una manera compatible con versiones anteriores.

Supongo que estás buscando la habilidad de hacer esto:

 def my_method(arg1) .. end def my_method(arg1, arg2) .. end 

Ruby apoya esto de una manera diferente:

 def my_method(*args) if args.length == 1 #method 1 else #method 2 end end 

Un patrón común también es pasar opciones como un hash:

 def my_method(options) if options[:arg1] and options[:arg2] #method 2 elsif options[:arg1] #method 1 end end my_method arg1: 'hello', arg2: 'world' 

Espero que ayude

La sobrecarga de métodos tiene sentido en un lenguaje con tipado estático, donde se puede distinguir entre diferentes tipos de argumentos

 f(1) f('foo') f(true) 

así como también entre diferentes números de argumentos

 f(1) f(1, 'foo') f(1, 'foo', true) 

La primera distinción no existe en ruby. Ruby usa tipeo dynamic o “pato escribiendo”. La segunda distinción se puede manejar mediante argumentos predeterminados o trabajando con argumentos:

 def f(n, s = 'foo', flux_compensator = true) ... end def f(*args) case args.size when ... when 2 ... when 3 ... end end 

Esto no responde a la pregunta de por qué ruby ​​no tiene sobrecarga de método, pero las bibliotecas de terceros pueden proporcionarlo.

La librería contracts.ruby permite la sobrecarga. Ejemplo adaptado del tutorial:

 class Factorial include Contracts Contract 1 => 1 def fact(x) x end Contract Num => Num def fact(x) x * fact(x - 1) end end # try it out Factorial.new.fact(5) # => 120 

Tenga en cuenta que esto es realmente más poderoso que la sobrecarga de Java, porque puede especificar valores para que coincidan (por ejemplo, 1 ), no meramente tipos.

Sin embargo, verá una disminución del rendimiento al usar esto; tendrá que ejecutar puntos de referencia para decidir cuánto puede tolerar.

A menudo hago la siguiente estructura:

 def method(param) case param when String method_for_String(param) when Type1 method_for_Type1(param) ... else #default implementation end end 

Esto permite al usuario del objeto utilizar el método claro y claro method_name: method Pero si desea optimizar la ejecución, puede llamar directamente al método correcto.

Además, hace que tus examinadores de pruebas y mejores.