Parece que todos los nuevos lenguajes de programación o al menos los que se hicieron populares usan la inferencia de tipos. Incluso Javascript obtuvo tipos e inferencia de tipos a través de diversas implementaciones (Acscript, mecanografiado, etc.). Me parece genial, pero me pregunto si hay compensaciones o por qué digamos que Java o los viejos buenos idiomas no tienen inferencia de tipos
- Al declarar una variable en Go sin especificar su tipo (usando var sin un tipo o la sintaxis: =), el tipo de la variable se deduce del valor en el lado derecho.
- D permite escribir fragmentos de código grandes sin especificar tipos de forma redundante, como hacen los lenguajes dinámicos. Por otro lado, la inferencia estática deduce tipos y otras propiedades de código, dando lo mejor de los mundos estático y dinámico.
- El motor de inferencia de tipos en Rust es bastante inteligente. Hace más que mirar el tipo del valor r durante una inicialización. También se ve cómo se usa la variable después para inferir su tipo.
- Swift usa la inferencia de tipos para calcular el tipo apropiado. La inferencia de tipos permite que un compilador deduzca el tipo de una expresión particular automáticamente cuando compila su código, simplemente examinando los valores que proporciona.
programming-languages
type-systems
El usuario sin sombrero
fuente
fuente
var
porque a veces puede dañar la legibilidad.var
y C ++auto
) y la inferencia de tipo (bidireccional, como Haskelllet
). En el primer caso, el tipo de un nombre puede inferirse únicamente de su inicializador; sus usos deben seguir el tipo del nombre. En el último caso, el tipo de un nombre también puede inferirse de sus usos, lo cual es útil porque puede escribir simplemente[]
para una secuencia vacía, independientemente del tipo de elemento, onewEmptyMVar
para una nueva referencia mutable nula, independientemente del referente tipo.Respuestas:
El sistema de tipos de Haskell es completamente inferible (dejando de lado la recursividad polimórfica, ciertas extensiones de lenguaje y la temida restricción del monomorfismo ), sin embargo, los programadores con frecuencia proporcionan anotaciones de tipo en el código fuente, incluso cuando no es necesario. ¿Por qué?
map :: (a -> b) -> [a] -> [b]
. Su forma más general (fmap :: Functor f => (a -> b) -> f a -> f b
) se aplica a todos losFunctor
s, no solo a las listas. Pero se consideró quemap
sería más fácil de entender para los principiantes, por lo que sigue viviendo junto a su hermano mayor.En general, los inconvenientes de un sistema estáticamente tipado pero inferible son muy parecidos a los inconvenientes del tipeo estático en general, una discusión muy usada en este sitio y otros (buscar en Google "desventajas de tipeo estático" le dará cientos de páginas de guerras de llamas). Por supuesto, algunas de dichas desventajas se mejoran por la menor cantidad de anotaciones de tipo en un sistema inferible. Además, la inferencia de tipos tiene sus propias ventajas: el desarrollo impulsado por agujeros no sería posible sin la inferencia de tipos.
Java * demuestra que un lenguaje que requiere demasiadas anotaciones de tipo se vuelve molesto, pero con muy poco pierde las ventajas que describí anteriormente. Los idiomas con inferencia de tipo de exclusión voluntaria logran un equilibrio agradable entre los dos extremos.
* Incluso Java, ese gran chivo expiatorio, realiza una cierta cantidad de inferencia de tipo local . En una declaración como
Map<String, Integer> = new HashMap<>();
, no tiene que especificar el tipo genérico del constructor. Por otro lado, los lenguajes de estilo ML son típicamente inferibles globalmente .fuente
Functor
. Listas ymap
es más probable que sean familiares para los Haskellers no experimentados.var
un ejemplo de inferencia de tipos?var
es un buen ejemplo.x
; en este último no hay ningún tipo para determinar, todos los tipos son conocidos y solo hay que verificar que la expresión tenga sentido. La diferencia se vuelve más importante a medida que pasa ejemplos triviales yx
se usa en varios lugares; el compilador tiene que verificar las ubicaciones dondex
se usa para determinar 1) ¿es posible asignarx
un tipo tal que el código escriba check? 2) Si es así, ¿cuál es el tipo más general que podemos asignarle?new HashMap<>();
sintaxis solo se agregó en Java 7, y las lambdas en Java 8 permiten una gran cantidad de inferencia de tipo "real".En C #, la inferencia de tipos se produce en tiempo de compilación, por lo que el costo de tiempo de ejecución es cero.
Como cuestión de estilo,
var
se utiliza para situaciones en las que es inconveniente o innecesario especificar manualmente el tipo. Linq es una de esas situaciones. Otro es:sin el cual estaría repitiendo su nombre de tipo realmente largo (y los parámetros de tipo) en lugar de simplemente decirlo
var
.Usar el nombre real del tipo cuando sea explícito mejora la claridad del código.
Hay algunas situaciones en las que no se puede utilizar la inferencia de tipos, como las declaraciones de variables miembro cuyos valores se establecen en el momento de la construcción, o donde realmente desea que intellisense funcione correctamente (el IDE de Hackerrank no intelisense los miembros de la variable a menos que declare el tipo explícitamente) .
fuente
¡Buena pregunta!
Y hay más lenguajes esotéricos que no pueden hacer su rareza sin una anotación explícita de tipo. Hasta ahora, no hay ninguno que yo sepa que sea lo suficientemente común / popular / prometedor como para mencionar, excepto de pasada.
fuente
var foo = x => x;
falla porque el lenguaje necesita inferirx
aquí y no tiene nada para continuar. Cuando se construyen las lambdas, se construyen como delegados tipados explícitamenteFunc<int, int> foo = x => x
en CIL comoFunc<int, int> foo = new Func<int, int>(x=>x);
donde se construye la lambda como una función generada, tipada explícitamente. Para mí, inferir el tipo dex
es parte integral de la inferencia de tipo ...x => x
está contenida dentro de la propia lambda; no hace referencia a ninguna variable del ámbito circundante. Cualquier lenguaje funcional sano juicio inferir correctamente que su tipo es "para todos los tiposa
,a -> a
". Creo que lo que DeadMG está tratando de decir es que el sistema de tipos de C # carece de la propiedad de tipo principal, lo que significa que siempre es posible descubrir el tipo más general para cualquier expresión. Es una propiedad muy fácil de destruir.Java resulta ser la excepción en lugar de la regla aquí. Incluso C ++ (que creo que califica como un "buen lenguaje antiguo" :)) admite la inferencia de tipos con la
auto
palabra clave desde el estándar C ++ 11. No solo funciona con declaración de variables, sino también como tipo de retorno de función, lo que es especialmente útil con algunas funciones de plantilla complejas.La escritura implícita y la inferencia de tipos tienen muchos casos de uso buenos, y también hay algunos casos de uso en los que realmente no debería hacerlo. Esto es a veces cuestión de gustos y también tema de debate.
Pero que haya indudablemente buenos casos de uso, es en sí mismo una razón legítima para que cualquier lenguaje lo implemente. Tampoco es una característica difícil de implementar, sin penalización de tiempo de ejecución y no afecta significativamente el tiempo de compilación.
No veo un inconveniente real en darle una oportunidad al desarrollador para usar la inferencia de tipos.
Algunos responden que a veces la tipificación explícita es buena, y ciertamente tienen razón. Pero no admitir la tipificación implícita significaría que un lenguaje impone la tipificación explícita todo el tiempo.
Entonces, el verdadero inconveniente es cuando un lenguaje no admite la tipificación implícita, porque con esto se afirma que no hay una razón legítima para que el desarrollador lo use, lo cual no es cierto.
fuente
La distinción principal entre un sistema de inferencia de tipo Hindley-Milner y una inferencia de tipo estilo Go es la dirección del flujo de información. En HM, la información de tipo fluye hacia adelante y hacia atrás a través de la unificación; en Ir, la información de tipo fluye solo hacia delante: solo calcula las sustituciones hacia adelante.
La inferencia de tipo HM es una espléndida innovación que funciona bien con lenguajes funcionales con tipos polimórficos, pero los autores de Go probablemente argumentarán que intenta hacer demasiado:
El hecho de que la información fluya hacia adelante y hacia atrás significa que la inferencia de tipo HM es un asunto muy no local; en ausencia de anotaciones de tipo, cada línea de código en su programa podría estar contribuyendo a escribir una sola línea de código. Si solo tiene sustitución hacia adelante, sabe que la fuente de un error de tipo debe estar en el código que precede a su error; No es el código que viene después.
Con la inferencia de tipo HM, tiende a pensar en restricciones: cuando usa un tipo, restringe los tipos posibles que puede tener. Al final del día, puede haber algunas variables de tipo que se dejan totalmente sin restricciones. La idea de la inferencia de tipos HM es que esos tipos realmente no importan, por lo que se convierten en variables polimórficas. Sin embargo, este polimorfismo adicional puede ser indeseable por varias razones. Primero, como algunas personas han señalado, este polimorfismo adicional podría ser indeseable: HM concluye un tipo polimórfico falso para algún código falso y conduce a errores extraños más tarde. En segundo lugar, cuando un tipo se deja polimórfico, esto puede tener consecuencias para el comportamiento en tiempo de ejecución. Por ejemplo, un resultado intermedio demasiado polimórfico es la razón por la cual 'mostrar. leer 'se considera ambiguo en Haskell; como otro ejemplo,
fuente
Duele la legibilidad.
Comparar
vs
Es especialmente un problema al leer fuera de un IDE como en github.
fuente
var
puede usarse sin perjudicar la legibilidad.var objects = GetBusinessObjects();