Los idiomas de tipo dinámico son de tipo único
Comparando sistemas de tipos , no hay ventaja en la escritura dinámica. La escritura dinámica es un caso especial de escritura estática : es un lenguaje de escritura estática donde cada variable tiene el mismo tipo. Puede lograr lo mismo en Java (menos concisión) haciendo que cada variable sea de tipo Object
y que los valores de "objeto" sean de tipo Map<String, Object>
:
void makeItBark(Object dog) {
Map<String, Object> dogMap = (Map<String, Object>) dog;
Runnable bark = (Runnable) dogMap.get("bark");
bark.run();
}
Por lo tanto, incluso sin reflexión, puede lograr el mismo efecto en casi cualquier lenguaje de tipo estático, dejando de lado la comodidad sintáctica. No obtienes ningún poder expresivo adicional; por el contrario, tiene menos poder expresivo porque en un lenguaje de tipo dinámico, se le niega la capacidad de restringir variables a ciertos tipos.
Hacer un ladrido de pato en un lenguaje estáticamente escrito
Además, un buen lenguaje de tipo estático le permitirá escribir código que funcione con cualquier tipo que tenga una bark
operación. En Haskell, esta es una clase de tipo:
class Barkable a where
bark :: a -> unit
Esto expresa la restricción de que para que algún tipo a
se considere Barkable, debe existir una bark
función que tome un valor de ese tipo y no devuelva nada.
Luego puede escribir funciones genéricas en términos de la Barkable
restricción:
makeItBark :: Barkable a => a -> unit
makeItBark barker = bark (barker)
Esto dice que makeItBark
funcionará para cualquier tipo que satisfaga Barkable
los requisitos. Esto puede parecer similar a un interface
en Java o C #, pero tiene una gran ventaja: los tipos no tienen que especificar por adelantado qué clases de tipos satisfacen. Puedo decir que el tipo Duck
es Barkable
en cualquier momento, incluso si Duck
es un tipo de terceros que no escribí. De hecho, no importa que el escritor de Duck
no haya escrito una bark
función; puedo proporcionarla después del hecho cuando digo el idioma que Duck
satisface Barkable
:
instance Barkable Duck where
bark d = quack (punch (d))
makeItBark (aDuck)
Esto dice que Duck
s puede ladrar, y su función de ladrido se implementa golpeando al pato antes de hacerlo graznar. Con eso fuera del camino, podemos llamar makeItBark
a los patos.
Standard ML
y OCaml
son aún más flexibles en el sentido de que puede satisfacer la misma clase de tipo en más de una forma. En estos idiomas puedo decir que los enteros se pueden ordenar usando el orden convencional y luego dar la vuelta y decir que también se pueden ordenar por divisibilidad (por ejemplo, 10 > 5
porque 10 es divisible por 5). En Haskell solo puede crear una instancia de una clase de tipo una vez. (Esto le permite a Haskell saber automáticamente que está bien llamar bark
a un pato; en SML u OCaml debe ser explícito sobre qué bark
función desea, porque puede haber más de una).
Concisión
Por supuesto, hay diferencias sintácticas. El código de Python que presentó es mucho más conciso que el equivalente de Java que escribí. En la práctica, esa concisión es una gran parte del atractivo de los lenguajes de tipo dinámico. Pero la inferencia de tipos le permite escribir código que sea igual de conciso en lenguajes tipados estáticamente, al liberarlo de tener que escribir explícitamente los tipos de cada variable. Un lenguaje de tipo estático también puede proporcionar soporte nativo para el tipeo dinámico, eliminando la verbosidad de todas las manipulaciones de fundición y mapas (por ejemplo, C # 's dynamic
).
Programas correctos pero mal escritos
Para ser justos, la escritura estática necesariamente excluye algunos programas que son técnicamente correctos aunque el verificador de tipos no pueda verificarlo. Por ejemplo:
if this_variable_is_always_true:
return "some string"
else:
return 6
La mayoría de los idiomas de tipo estático rechazarían esta if
afirmación, aunque la rama else nunca ocurrirá. En la práctica, parece que nadie hace uso de este tipo de código; cualquier cosa demasiado inteligente para el verificador de tipos probablemente hará que los futuros mantenedores de su código lo maldigan a usted y a sus familiares. Por ejemplo, alguien tradujo con éxito 4 proyectos de Python de código abierto a Haskell, lo que significa que no estaban haciendo nada que un buen lenguaje de tipo estático no pudiera compilar. Además, el compilador encontró un par de errores relacionados con el tipo que las pruebas unitarias no detectaban.
El argumento más fuerte que he visto para la tipificación dinámica son las macros de Lisp, ya que le permiten extender arbitrariamente la sintaxis del lenguaje. Sin embargo, Typed Racket es un dialecto de Lisp de tipo estático que tiene macros, por lo que parece que el tipeo estático y las macros no son mutuamente excluyentes, aunque tal vez sea más difícil de implementar simultáneamente.
Manzanas y naranjas
Finalmente, no olvide que hay diferencias más grandes en los idiomas que solo su sistema de tipos. Antes de Java 8, hacer cualquier tipo de programación funcional en Java era prácticamente imposible; una lambda simple requeriría 4 líneas de código de clase anónimo repetitivo. Java tampoco tiene soporte para literales de colección (por ejemplo [1, 2, 3]
). También puede haber diferencias en la calidad y disponibilidad de herramientas (IDE, depuradores), bibliotecas y soporte comunitario. Cuando alguien afirma ser más productivo en Python o Ruby que Java, esa disparidad de características debe tenerse en cuenta. Hay una diferencia entre comparar idiomas con todas las baterías incluidas , núcleos de idiomas y sistemas de tipos .
makeItBark(collections.namedtuple("Dog", "bark")(lambda x: "woof woof"))
. Ese argumento ni siquiera es una clase , es una tupla anónima llamada. La escritura de pato ("si suena como un ...") le permite hacer interfaces ad hoc con esencialmente cero restricciones y sin sobrecarga sintáctica. Puedes hacer esto en un lenguaje como Java, pero terminas con mucha reflexión desordenada. Si una función en Java requiere una ArrayList y desea darle otro tipo de colección, es SOL. En python que ni siquiera puede aparecer.