sirve - ruby tutorial
¿Por qué no se sobrecarga el método de soporte ruby? (6)
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?
"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 dinámicos , 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 dinámico 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 dinámico , 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 dinámicos e incluso los valores dinámicos 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 dinámico 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.
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.
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.
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,
- Argumentos con diferentes tipos de datos, por ejemplo:
method(int a, int b) vs method(String a, String b)
- 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 declaración de tipo de datos en ruby ( lenguaje de tipado dinámico ). 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.
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 dinámico 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
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