Respuestas:
La sobrecarga de métodos se puede lograr declarando dos métodos con el mismo nombre y firmas diferentes. Estas firmas diferentes pueden ser:
method(int a, int b) vs method(String a, String b)
method(a) vs method(a, b)
No podemos lograr la sobrecarga de métodos usando la primera manera porque no hay una declaración de tipo de datos en ruby ( lenguaje de tipo dinámico ). Entonces, la única forma de definir el método anterior esdef(a,b)
Con la segunda opción, podría parecer que podemos lograr la sobrecarga del método, pero no podemos. Digamos que tengo dos métodos con diferentes números 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.
Por lo tanto, 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 estático basado en argumentos", pero Ruby no tiene despacho estático en absoluto . Entonces, la razón por la cual 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 otra manera.
Ahora, si no está preguntando específicamente sobre la sobrecarga, sino quizás sobre el despacho dinámico basado en argumentos, 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 acertar, y aún más difícil de mantener comprensible. Incluso en lenguajes con despacho estático basado en argumentos y sin argumentos opcionales (como Java, por ejemplo), a veces es casi imposible decir para un simple mortal, qué sobrecarga se va a elegir.
En C #, puede codificar cualquier problema de 3-SAT en resolución de sobrecarga, lo que significa que la resolución de sobrecarga en C # es NP-hard.
Ahora intente eso con el despacho dinámico , donde tiene la dimensión de tiempo adicional para mantener en su cabeza.
Hay lenguajes 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 se despacha en una función arbitraria de todos los argumentos (que por cierto es extremadamente genial y extremadamente poderoso).
Pero no conozco ningún lenguaje OO con envío 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 como con Java (mencionó especialmente Swing y AWT que juegan algunos trucos extremadamente complejos que ejercitan prácticamente todos los casos desagradables de esquina oscura de las reglas de sobrecarga bastante complejas de Java). He tenido algunas ideas sobre cómo agregar un despacho basado en argumentos a Ruby, pero nunca pude descubrir cómo hacerlo de una manera compatible con versiones anteriores.
def method(a, b = true)
no funcionará, por lo tanto, la sobrecarga de métodos es imposible". No es; Solo es difícil. Sin embargo, encontré ESTA respuesta realmente informativa.
Supongo que está buscando la capacidad 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 las 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 tipeo estático, donde puede distinguir entre diferentes tipos de argumentos
f(1)
f('foo')
f(true)
así como entre diferentes números de argumentos
f(1)
f(1, 'foo')
f(1, 'foo', true)
La primera distinción no existe en rubí. Ruby usa tipeo dinámico o "tipeo de pato". La segunda distinción puede manejarse 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 una sobrecarga de métodos, pero las bibliotecas de terceros pueden proporcionarla.
La biblioteca contratos.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 en realidad más poderoso que la sobrecarga de Java, porque puede especificar valores para que coincidan (por ejemplo 1
), no simplemente tipos.
Sin embargo, verá un rendimiento reducido 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 usar el método nombre_método limpio y claro: método Pero si desea optimizar la ejecución, puede llamar directamente al método correcto.
Además, hace que su prueba sea más clara y mejor.
Ya hay excelentes respuestas sobre por qué lado de la pregunta. sin embargo, si alguien busca otras soluciones, busque la gema funcional de rubí inspirada en las características de coincidencia de patrones de Elixir .
class Foo
include Functional::PatternMatching
## Constructor Over loading
defn(:initialize) { @name = 'baz' }
defn(:initialize, _) {|name| @name = name.to_s }
## Method Overloading
defn(:greet, :male) {
puts "Hello, sir!"
}
defn(:greet, :female) {
puts "Hello, ma'am!"
}
end
foo = Foo.new or Foo.new('Bar')
foo.greet(:male) => "Hello, sir!"
foo.greet(:female) => "Hello, ma'am!"