Estoy desarrollando un lenguaje compilado estáticamente y fuertemente tipado, y estoy revisando la idea de si incluir la sobrecarga de funciones como una característica del lenguaje. Me di cuenta de que soy un poco parcial, principalmente de un C[++|#]
fondo.
¿Cuáles son las mayoría de los argumentos convincentes para y contra incluyendo la sobrecarga de funciones en un idioma?
EDITAR: ¿No hay nadie que tenga una opinión opuesta?
Bertrand Meyer (creador de Eiffel en 1985/1986) llama al método sobrecargando esto: (fuente)
un mecanismo de vanidad que no aporta nada al poder semántico de un lenguaje OO, pero dificulta la legibilidad y complica la tarea de todos
Ahora, esas son algunas generalizaciones generales, pero es un tipo inteligente, por lo que creo que es seguro decir que podría respaldarlas si fuera necesario. De hecho, casi hizo que Brad Abrams (uno de los desarrolladores de CLSv1) se convenciera de que .NET no debería admitir la sobrecarga de métodos. (fuente) Eso es algo poderoso. ¿Alguien puede arrojar algo de luz sobre sus pensamientos y si su punto de vista todavía está justificado 25 años después?
fuente
Recomiendo al menos estar al tanto de las clases de tipos en Haskell. Las clases de tipos se crearon para ser un enfoque disciplinado de la sobrecarga del operador, pero han encontrado otros usos y, hasta cierto punto, han convertido a Haskell en lo que es.
Por ejemplo, aquí hay un ejemplo de sobrecarga ad-hoc (Haskell no bastante válido):
Y aquí está el mismo ejemplo de sobrecarga con clases de tipo:
Una desventaja de esto es que usted tiene que llegar a nombres muy exóticos para todas sus clases de tipos (como en Haskell, usted tiene la más bien abstracta
Monad
,Functor
,Applicative
así como el más simple y más reconocibleEq
,Num
yOrd
).Una ventaja es que, una vez que está familiarizado con una clase de tipos, sabe cómo usar cualquier tipo en esa clase. Además, es fácil proteger las funciones de los tipos que no implementan las clases necesarias, como en:
Editar: en Haskell, si desea un
==
operador que acepte dos tipos diferentes, puede usar una clase de tipo multiparamétrica:Por supuesto, esta es probablemente una mala idea, ya que explícitamente te permite comparar manzanas y naranjas. Sin embargo, es posible que desee considerar esto
+
, ya que agregar aWord8
aInt
realmente es algo sensato en algunos contextos.fuente
(==) :: Int -> Float -> Bool
cualquier lugar? (independientemente de si es una buena idea, por supuesto)class Eq a ...
traducido a pseudo-C-family seríainterface Eq<A> {bool operator==(A x, A y);}
, y en lugar de usar código con plantilla para comparar objetos arbitrarios, usa esta 'interfaz'. ¿Está bien?==
estar en un espacio de nombres diferente pero no permite anularlo. Tenga en cuenta que hay un único espacio de nombres (Prelude
) incluido de forma predeterminada, pero puede evitar cargarlo utilizando extensiones o importándolo explícitamente (import Prelude ()
no importará nadaPrelude
yimport qualified Prelude as P
no insertará símbolos en el espacio de nombres actual).Permitir la sobrecarga de funciones, no puede hacer lo siguiente con parámetros opcionales (o si puede, no muy bien).
ejemplo trivial no asume ningún
base.ToString()
métodofuente
Siempre he preferido los parámetros predeterminados sobre la sobrecarga de funciones. Las funciones sobrecargadas generalmente solo llaman a una versión "predeterminada" con parámetros predeterminados. Porque escribir
Cuando pude hacer:
Dicho esto, me doy cuenta de que a veces las funciones sobrecargadas hacen cosas diferentes, en lugar de simplemente llamar a otra variante con parámetros predeterminados ... pero en tal caso, no es una mala idea (de hecho, probablemente sea una buena idea) simplemente darle una nombre diferente.
(Además, los argumentos de palabras clave de estilo Python funcionan muy bien con los parámetros predeterminados).
fuente
Array Slice(int start, int length) {...}
con sobrecargadoArray Slice(int start) {return this.Slice(start, this.Count - start);}
? Eso no se puede codificar con los parámetros predeterminados. ¿Crees que deberían recibir nombres diferentes? Si es así, ¿cómo los nombrarías?indexOf(char ch)
+indexOf(Date dt)
en una lista. También me gustan los valores predeterminados, pero no son intercambiables con la escritura estática.Acabas de describir Java. O C #.
¿Por qué estás reinventando la rueda?
Asegúrate de que el tipo de retorno sea parte de la firma del método ysobrecargue el contenido de tu corazón, realmente limpia el código cuando no tienes que decirlo.fuente
EnumX.Flag1 | Flag2 | Flag3
. Sin embargo, no implementaré esto. Si lo hiciera y no se usara el tipo de retorno, buscaría un tipo de retorno devoid
.Grrr ... no hay suficiente privilegio para comentar aún ...
@Mason Wheeler: Tenga en cuenta entonces a Ada, que se sobrecarga en el tipo de retorno. También mi lenguaje Felix lo hace también en algunos contextos, específicamente, cuando una función devuelve otra función y hay una llamada como:
El tipo de b se puede utilizar para la resolución de sobrecarga. También sobrecargas de C ++ en el tipo de retorno en algunas circunstancias:
De hecho, existen algoritmos para sobrecargar el tipo de retorno, utilizando la inferencia de tipos. En realidad no es tan difícil de hacer con una máquina, el problema es que a los humanos les resulta difícil. (Creo que el esquema se da en el Libro del Dragón, el algoritmo se llama algoritmo de ver y ver si recuerdo correctamente)
fuente
Caso de uso contra la sobrecarga de la función de implementación: 25 métodos con nombres similares que hacen las mismas cosas pero con conjuntos de argumentos completamente diferentes en una amplia variedad de patrones.
Caso de uso contra la no implementación de sobrecarga de funciones: 5 métodos con nombres similares con conjuntos de tipos muy similares en exactamente el mismo patrón.
Al final del día, no tengo ganas de leer los documentos para una API producida en cualquier caso.
Pero en un caso se trata de lo que los usuarios podrían hacer. En el otro caso, es lo que los usuarios deben hacer debido a una restricción de idioma. En mi opinión, es mejor al menos permitir la posibilidad de que los autores de programas sean lo suficientemente inteligentes como para sobrecargarse de manera sensata sin crear ambigüedad. Cuando golpeas sus manos y les quitas la opción, básicamente estás garantizando que sucederá la ambigüedad. Me gusta más confiar en que el usuario haga lo correcto que asumir que siempre harán lo incorrecto. En mi experiencia, el proteccionismo tiende a conducir a un comportamiento aún peor por parte de la comunidad de un idioma.
fuente
Elegí proporcionar sobrecarga ordinaria y clases de tipos de tipos múltiples en mi idioma Felix.
Considero que la sobrecarga (abierta) es esencial, especialmente en un lenguaje que tiene muchos tipos numéricos (Felix tiene todos los tipos numéricos de C). Sin embargo, a diferencia de C ++, que abusa de la sobrecarga al hacer que las plantillas dependan de él, el polimorfismo de Felix es paramétrico: es necesario sobrecargar las plantillas en C ++ porque las plantillas en C ++ están mal diseñadas.
Las clases de tipo también se proporcionan en Felix. Para aquellos que conocen C ++ pero no dominan a Haskell, ignoren a aquellos que lo describen como sobrecargado. No es remotamente como una sobrecarga, más bien, es como una especialización de plantilla: declara una plantilla que no implementa, luego proporciona implementaciones para casos particulares cuando los necesita. La tipificación es polimórfica paramétricamente, la implementación es por instanciación ad hoc pero no está destinada a ser sin restricciones: tiene que implementar la semántica prevista.
En Haskell (y C ++) no se puede establecer la semántica. En C ++, la idea de "Conceptos" es más o menos un intento de aproximar la semántica. En Félix, puede aproximar la intención con axiomas, reducciones, lemas y teoremas.
La principal y única ventaja de la sobrecarga (abierta) en un lenguaje bien basado en principios como Felix es que hace que sea más fácil recordar los nombres de las funciones de la biblioteca, tanto para el escritor del programa como para el revisor del código.
La principal desventaja de la sobrecarga es el complejo algoritmo requerido para implementarlo. Tampoco se adapta muy bien a la inferencia de tipos: aunque los dos no son completamente exclusivos, el algoritmo para hacer ambos es lo suficientemente complejo como para que el programador probablemente no pueda predecir los resultados.
En C ++, esto también es un problema porque tiene un algoritmo de coincidencia descuidado y también admite conversiones de tipo automáticas: en Félix "solucioné" este problema al requerir una coincidencia exacta y no conversiones de tipo automáticas.
Entonces, creo que tiene una opción: sobrecarga o inferencia de tipos. La inferencia es linda, pero también es muy difícil de implementar de manera que diagnostique conflictos adecuadamente. Ocaml, por ejemplo, le dice dónde detecta un conflicto, pero no de dónde dedujo el tipo esperado.
La sobrecarga no es mucho mejor, incluso si tiene un compilador de calidad que intenta decirle a todos los candidatos, puede ser difícil de leer si los candidatos son polimórficos, y aún peor si se trata de piratería de plantillas C ++.
fuente
Todo se reduce al contexto, pero creo que la sobrecarga hace que una clase sea mucho más útil cuando estoy usando una escrita por otra persona. A menudo terminas con menos redundancia.
fuente
Si está buscando tener usuarios familiarizados con los lenguajes de la familia C, entonces sí debería, porque sus usuarios lo esperarán.
fuente