Cuando decido que quiero entender algo, me obsesiono hasta que finalmente lo logro. ¿Mi último intento? Escritura estática frente a dinámica .
Las respuestas de Stack Overflow fueron confusas, largas e incluso contradictorias. Resulta que estos términos suelen malinterpretarse, por lo que tiene sentido que mi búsqueda resulte difícil. Seguí leyendo todo lo que pude encontrar pero nada satisfizo mi hambre de algo accesible y conciso.
“Cuando se traduce el código fuente”
“Cuando se comprueban los tipos”
"3" + 5
generará un error de tipo en lenguajes fuertemente tipados , como Python y Go, porque no permiten la "coerción de tipo": la capacidad de un valor para cambiar el tipo implícitamente en ciertos contextos (por ejemplo, fusionar dos tipos usando +
). Los lenguajes escritos débilmente , como JavaScript, no generarán un error de tipo (resultado: '35'
).
Las definiciones de "Estático y compilado" y "Dinámico e interpretado" son bastante similares... pero recuerde que es "cuando se comprueban los tipos" frente a "cuando se traduce el código fuente".
¡La verificación de tipos no tiene nada que ver con el lenguaje que se compila o interpreta! Es necesario separar estos términos conceptualmente.
Dinámico, Interpretado
def foo(a): if a > 0: print 'Hi' else: print "3" + 5 foo(2)
Debido a que Python se interpreta y se escribe dinámicamente, solo traduce y verifica el código en el que se está ejecutando. El bloque else
nunca se ejecuta, por lo que "3" + 5
ni siquiera se mira.
¿Qué pasa si fue escrito estáticamente?
Se arrojaría un error de tipo incluso antes de que se ejecute el código. Todavía realiza la verificación de tipos antes del tiempo de ejecución, aunque se interprete.
¿Qué pasa si fue compilado?
El bloque else
se traduciría/miraría antes del tiempo de ejecución, pero debido a que se escribe dinámicamente, ¡no arrojaría un error! Los lenguajes tipeados dinámicamente no verifican los tipos hasta la ejecución, y esa línea nunca se ejecuta.
estático, compilado
package main import ("fmt") func foo(a int) { if (a > 0) { fmt.Println("Hi") } else { fmt.Println("3" + 5) }} func main() { foo(2)}
¡Los tipos se verifican antes de ejecutarse (estáticos) y el error de tipo se detecta de inmediato! Los tipos aún se verificarían antes del tiempo de ejecución si se interpretara, con el mismo resultado. Si fuera dinámico, no arrojaría ningún error aunque el código se examinaría durante la compilación.
Un lenguaje compilado tendrá un mejor rendimiento en tiempo de ejecución si está tipificado estáticamente porque el conocimiento de los tipos permite la optimización del código de máquina.
Los lenguajes tipificados estáticamente tienen un mejor rendimiento en tiempo de ejecución intrínsecamente debido a que no necesitan verificar los tipos dinámicamente mientras se ejecutan (verifica antes de ejecutar).
Del mismo modo, los lenguajes compilados son más rápidos en tiempo de ejecución, ya que el código ya se tradujo en lugar de tener que "interpretarlo"/traducirlo sobre la marcha.
Tenga en cuenta que tanto los lenguajes compilados como los tipificados estáticamente tendrán un retraso antes de ejecutar la traducción y la verificación de tipos, respectivamente.
La escritura estática detecta los errores antes de tiempo, en lugar de encontrarlos durante la ejecución (especialmente útil para programas largos). Es más "estricto" en el sentido de que no permitirá errores de tipo en ninguna parte de su programa y, a menudo, evita que las variables cambien de tipo, lo que protege aún más contra errores no deseados.
num = 2num = '3' // ERROR
La escritura dinámica es más flexible (algo que algunos aprecian) pero permite que las variables cambien de tipo (a veces creando errores inesperados).
¿Eso te aclaró las cosas? ¡Házmelo saber en los comentarios!