Inferencia de tipos
La inferencia de tipos implica que la información de tipos no se comprueba únicamente en el programa, también se transporta y por tanto no tiene por qué ser resuelta de inmediato. Por ejemplo, una variable locale puede ser declarada sin tipo alguno (será del tipo Unknown) y la primera vez que sea usada, su tipo se fijará al que corresponda.
Impresión de tipos
En cualquier parte del programa se puede usar la operación type para conocer el tipo de una expresión dada. Al compilar, se eliminará la operación type y sólo quedará la expresión :
var x : Int = type(0);
Esto imprimirá Int al compilar y se compilará el mismo programa como si no se hubiese usado type.
Esto es útil para averiguar tipos sin necesidad de estar buscando la clase o en la documentación.
Inferencia de variables locales
La inferencia de tipos permite que un programa entero sea de tipado estricto sin necesidad de escribir tipos en todos lados. En particular, no hace falta indicar el tipo de las variables locales, ya que se infieren sus tipos la primera vez que se accede a ellas o se las modifica :
var loc; type(loc); // imprime Unknown<0> loc = "hola"; type(loc); // imprime String
Inferencia de tipo de funciones
También es opcional declarar el tipo de parámetro pasado al método de una clase o a una función local. La primera vez que se use la función, se establecerá el tipo del parámetro siguiendo el del argumento que se use, de la misma manera que con las variables locales. Esto puede ser complicado ya que depende del orden en el que se ejecute el programa. Este ejemplo muestra el problema :
function f( posx ) { // .... } // ... f(134); f(12.2); // Error : Float debería ser Int
La primera invocación a f fija el tipo de posx como Int. La segunda invocación a f provoca un error de compilación porque f espera ahora un Int, no un Float. Sin embargo, si invertimos el orden de las invocaciones a f, el tipo de valor se fija primero como Float. Una segunda invocación usando un Int no falla dado que Int es un subtipo de Float.
function f( posx ) { // .... } // ... f(12.2); // Hace que el tipo de parámetro sea Float f(134); // Éxito
En este ejemplo las dos invocaciones están cerca una de la otra así que es fácil de entender y corregir. En programas grandes con casos complejos, corregir este tipo de problemas de compilación puede ser complicado. La solución más sencilla es establecer explícitamente el tipo de la función. Entonces la invocación que era responsable del problema se hará evidente al recompilar.
Retomando el primer ejemplo:
function f( posx : Int ) { // .... } // ... f(134); f(12.2); // El fallo señalará esta línea
Inferencia y parámetros de tipo
function f<T>(p: Class<T>): T { } function g(p: Float) { } var a: Dynamic = {}; var b = f(a); type(b); //En este punto, el tipo de 'b' aún no se ha inferido y se traza como 'Unknown<0>' g(b); type(b); //De aquí en adelante el tipo de 'b' es conocido como 'Float'
El código anterior ilustra una situación con una invocación de función que inicializa una variable declarada sin tipo (el tipo inferido no aparece en ese punto, porque la combinación de la función llamada y los parámetros de infocación hace esto imposible). La función f de 'tipo parametrizado' depende de su primer parámetro de tipo Class<T> (siendo T una abstracción, véase la página de documentación de Parámetros de tipo), pra decidir el tipo que va a devolver. Sin embargo, cuando se le pasa un objeto Dynamic, está claro que el parámetro de tipo 'T' no tiene sentido y es desconocido. La inferencia de tipos se retrasa hasta más adelante, cuando una invocación a g que toma un Float permite al compilador especificar el tipo de b como Float. Por tanto, la primera sentencia type traza Unknown<0> y la segunda Float. Tras haber sido inferido, el tipo es, naturalmente, inmutable.
Elección del usuario
Usar la inferencia de tipos es una elección. Puedes omitir los tipos de tus variables y funciones y dejar que sea el compilador el que los infiera por ti, o puedes escribir todos y cada uno de ellos de manera que tengas más control sobre el proceso. Quizá lo mejor sea un punto intermedio, añadiendo algo de tipado para mejorar la documentación del código y aún así seguir siendo capaz de escribir rápidamente algunas funciones sin ponerle tipo a todo.
En cualquier caso y aunque uses dinámicos (que se presentarán más adelante), tu programa será tipado estrictamente y cualquier uso erróneo será detectado instantáneamente al compilar.