Escucho mucho que los nuevos lenguajes de programación se escriben dinámicamente, pero ¿qué significa en realidad cuando decimos que un lenguaje se escribe dinámicamente frente a estáticamente?
Escucho mucho que los nuevos lenguajes de programación se escriben dinámicamente, pero ¿qué significa en realidad cuando decimos que un lenguaje se escribe dinámicamente frente a estáticamente?
Respuestas:
Un idioma se escribe estáticamente si el tipo de una variable se conoce en tiempo de compilación. Para algunos lenguajes, esto significa que usted, como programador, debe especificar de qué tipo es cada variable (por ejemplo: Java, C, C ++); otros idiomas ofrecen alguna forma de inferencia de tipos , la capacidad del sistema de tipos para deducir el tipo de una variable (por ejemplo: OCaml, Haskell, Scala, Kotlin)
La principal ventaja aquí es que el compilador puede realizar todo tipo de comprobaciones y, por lo tanto, se detectan muchos errores triviales en una etapa muy temprana.
Ejemplos: C, C ++, Java, Rust, Go, Scala
Un idioma se escribe dinámicamente si el tipo está asociado con valores de tiempo de ejecución y no con variables / campos / etc. Esto significa que usted como programador puede escribir un poco más rápido porque no tiene que especificar tipos cada vez (a menos que use un lenguaje de tipo estático con inferencia de tipos ).
Ejemplos: Perl, Ruby, Python, PHP, JavaScript.
La mayoría de los lenguajes de secuencias de comandos tienen esta característica, ya que de todos modos no hay un compilador para hacer una verificación de tipos estática, pero puede encontrarse buscando un error debido a que el intérprete malinterpreta el tipo de una variable. Afortunadamente, los guiones tienden a ser pequeños, por lo que los errores no tienen tantos lugares para esconderse.
La mayoría de los idiomas escritos dinámicamente le permiten proporcionar información de tipo, pero no la requieren. Un lenguaje que se está desarrollando actualmente, Rascal , adopta un enfoque híbrido que permite la escritura dinámica dentro de las funciones pero que impone la escritura estática para la firma de la función.
Los lenguajes de programación con tipos estáticos realizan la verificación de tipos (es decir, el proceso de verificación y aplicación de las restricciones de los tipos) en tiempo de compilación en lugar de tiempo de ejecución .
Los lenguajes de programación dinámicamente tipados verifican los tipos en tiempo de ejecución en lugar de en tiempo de compilación .
Ejemplos de lenguajes tipados estáticamente son: - Java, C, C ++
Ejemplos de lenguajes escritos dinámicamente son: - Perl, Ruby, Python, PHP, JavaScript
Aquí hay un ejemplo que contrasta cómo Python (de tipo dinámico) y Go (de tipo estático) manejan un error de tipo:
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
Python escribe la verificación en tiempo de ejecución y, por lo tanto:
silly(2)
Funciona perfectamente bien y produce el resultado esperado Hi
. El error solo se genera si se golpea la línea problemática:
silly(-1)
Produce
TypeError: unsupported operand type(s) for +: 'int' and 'str'
porque la línea relevante se ejecutó realmente.
Ir por otro lado hace la verificación de tipo en tiempo de compilación:
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
Lo anterior no se compilará, con el siguiente error:
invalid operation: "3" + 5 (mismatched types string and int)
runhaskell
, por ejemplo.
En pocas palabras: en un lenguaje de tipo estático , los tipos de variables son estáticos , lo que significa que una vez que establece una variable en un tipo, no puede cambiarla. Esto se debe a que la tipificación está asociada con la variable en lugar del valor al que se refiere.
Por ejemplo en Java:
String str = "Hello"; //variable str statically typed as string
str = 5; //would throw an error since str is supposed to be a string only
Donde, por otro lado: en un lenguaje de tipo dinámico , los tipos de variables son dinámicos , lo que significa que después de establecer una variable en un tipo, PUEDE cambiarla. Esto se debe a que la tipificación está asociada con el valor que asume en lugar de la variable en sí.
Por ejemplo en Python:
str = "Hello" # variable str is linked to a string value
str = 5 # now it is linked to an integer value; perfectly OK
Por lo tanto, es mejor pensar en las variables en lenguajes escritos dinámicamente como punteros genéricos a los valores escritos.
En resumen, el tipo describe (o debería haber descrito) las variables en el idioma en lugar del lenguaje en sí. Podría haber sido mejor utilizado como un lenguaje con variables escritas estáticamente frente a un lenguaje con variables escritas dinámicamente en mi humilde opinión.
Los lenguajes de tipo estático generalmente son lenguajes compilados, por lo tanto, los compiladores comprueban los tipos (¿tiene sentido, verdad? Ya que no se permite cambiar los tipos más adelante en tiempo de ejecución).
Los lenguajes de tipo dinámico generalmente se interpretan, por lo tanto, la verificación de tipos (si la hay) ocurre en tiempo de ejecución cuando se usan. Por supuesto, esto conlleva algunos costos de rendimiento y es una de las razones por las que los lenguajes dinámicos (p. Ej., Python, ruby, php) no escalan tan bien como los escritos (java, c #, etc.). Desde otra perspectiva, los idiomas tipados estáticamente tienen un costo inicial más elevado: por lo general, usted escribe más código, un código más difícil. Pero eso paga más tarde.
Lo bueno es que ambas partes están prestando características del otro lado. Los lenguajes mecanografiados están incorporando características más dinámicas, por ejemplo, genéricos y bibliotecas dinámicas en C #, y los lenguajes dinámicos incluyen más verificación de tipos, por ejemplo, anotaciones de tipo en python o HACK variante de PHP, que generalmente no son esenciales para el lenguaje y no se pueden usar en demanda.
Cuando se trata de la selección de tecnología, ninguno de los lados tiene una superioridad intrínseca sobre el otro. Es solo una cuestión de preferencia si desea más control para comenzar o flexibilidad. simplemente elija la herramienta adecuada para el trabajo y asegúrese de verificar lo que está disponible en términos opuestos antes de considerar un cambio.
http://en.wikipedia.org/wiki/Type_system
Mecanografía estática
Se dice que un lenguaje de programación usa la escritura estática cuando la verificación de tipo se realiza durante el tiempo de compilación en lugar del tiempo de ejecución. En la escritura estática, los tipos están asociados con variables, no valores. Los lenguajes de tipo estático incluyen Ada, C, C ++, C #, JADE, Java, Fortran, Haskell, ML, Pascal, Perl (con respecto a la distinción de escalares, matrices, hash y subrutinas) y Scala. La tipificación estática es una forma limitada de verificación del programa (ver seguridad de tipos): en consecuencia, permite detectar muchos errores de tipo al principio del ciclo de desarrollo. Los verificadores de tipo estático evalúan solo la información de tipo que se puede determinar en el momento de la compilación, pero pueden verificar que las condiciones verificadas se cumplan para todas las ejecuciones posibles del programa, lo que elimina la necesidad de repetir verificaciones de tipo cada vez que se ejecuta el programa. La ejecución del programa también puede hacerse más eficiente (es decir, más rápido o con menos memoria) al omitir las comprobaciones de tipo de tiempo de ejecución y habilitar otras optimizaciones.
Debido a que evalúan la información de tipo durante la compilación y, por lo tanto, carecen de información de tipo que solo está disponible en tiempo de ejecución, los verificadores de tipo estático son conservadores. Rechazarán algunos programas que pueden comportarse bien en tiempo de ejecución, pero que no se puede determinar estáticamente que estén bien escritos. Por ejemplo, incluso si una expresión siempre se evalúa como verdadera en tiempo de ejecución, un programa que contiene el código
if <complex test> then 42 else <type error>
será rechazado como mal escrito, porque un análisis estático no puede determinar que la rama else no se tomará. [1] El comportamiento conservador de los verificadores de tipo estático es ventajoso cuando se evalúa como falso con poca frecuencia: un verificador de tipo estático puede detectar errores de tipo en rutas de código poco utilizadas. Sin una verificación de tipo estática, incluso las pruebas de cobertura de código con una cobertura de código del 100% pueden no ser capaces de encontrar tales errores de tipo. Las pruebas de cobertura de código pueden no detectar dichos errores de tipo porque se debe tener en cuenta la combinación de todos los lugares donde se crean los valores y todos los lugares donde se usa un cierto valor.
Los lenguajes de tipo estático más utilizados no son formalmente seguros. Tienen "lagunas" en la especificación del lenguaje de programación que permite a los programadores escribir código que evita la verificación realizada por un verificador de tipo estático y, por lo tanto, aborda una gama más amplia de problemas. Por ejemplo, Java y la mayoría de los lenguajes de estilo C tienen escritura tipográfica, y Haskell tiene características tales como inseguroPerformIO: tales operaciones pueden ser inseguras en el tiempo de ejecución, ya que pueden causar un comportamiento no deseado debido a la escritura incorrecta de valores cuando se ejecuta el programa.
Escritura dinámica
Se dice que un lenguaje de programación se tipea dinámicamente, o simplemente 'dinámico', cuando la mayoría de su verificación de tipo se realiza en tiempo de ejecución en lugar de en tiempo de compilación. En la tipificación dinámica, los tipos están asociados con valores, no con variables. Los lenguajes de tipo dinámico incluyen Groovy, JavaScript, Lisp, Lua, Objective-C, Perl (con respecto a los tipos definidos por el usuario pero no a los tipos integrados), PHP, Prolog, Python, Ruby, Smalltalk y Tcl. En comparación con la escritura estática, la escritura dinámica puede ser más flexible (por ejemplo, al permitir que los programas generen tipos y funcionalidades basados en datos de tiempo de ejecución), aunque a expensas de menos garantías a priori. Esto se debe a que un lenguaje de tipo dinámico acepta e intenta ejecutar algunos programas que pueden ser considerados inválidos por un verificador de tipo estático.
La escritura dinámica puede generar errores de tipo en tiempo de ejecución; es decir, en tiempo de ejecución, un valor puede tener un tipo inesperado y se aplica una operación sin sentido para ese tipo. Esta operación puede ocurrir mucho después del lugar donde se cometió el error de programación, es decir, el lugar donde el tipo incorrecto de datos pasó a un lugar que no debería tener. Esto hace que el error sea difícil de localizar.
Los sistemas de lenguaje tipados dinámicamente, en comparación con sus primos tipados estáticamente, realizan menos verificaciones de "tiempo de compilación" en el código fuente (pero verifican, por ejemplo, que el programa sea sintácticamente correcto). Las comprobaciones en tiempo de ejecución pueden ser potencialmente más sofisticadas, ya que pueden usar información dinámica, así como cualquier información que estuvo presente durante la compilación. Por otro lado, las verificaciones en tiempo de ejecución solo afirman que las condiciones se mantienen en una ejecución particular del programa, y estas verificaciones se repiten para cada ejecución del programa.
El desarrollo en lenguajes tipados dinámicamente a menudo es compatible con prácticas de programación como pruebas unitarias. La prueba es una práctica clave en el desarrollo de software profesional, y es particularmente importante en lenguajes de tipo dinámico. En la práctica, las pruebas realizadas para garantizar el funcionamiento correcto del programa pueden detectar una gama mucho más amplia de errores que la verificación de tipos estática, pero, por el contrario, no pueden buscar de manera tan exhaustiva los errores que tanto la prueba como la verificación de tipos estáticos pueden detectar. Las pruebas se pueden incorporar al ciclo de compilación del software, en cuyo caso se puede considerar como una verificación de "tiempo de compilación", en el sentido de que el usuario del programa no tendrá que ejecutar dichas pruebas manualmente.
Referencias
- Pierce, Benjamin (2002). Tipos y lenguajes de programación. MIT Press. ISBN 0-262-16209-1.
myObject[remoteDataName]
. Entonces no hay forma de saber qué propiedad elegirá o incluso si es una propiedad válida.
La terminología "escrita dinámicamente" es lamentablemente engañosa. Todos los idiomas tienen tipos estáticos y los tipos son propiedades de expresiones (no de valores como algunos piensan). Sin embargo, algunos idiomas tienen solo un tipo. Estos se llaman lenguajes unipatificados. Un ejemplo de tal lenguaje es el cálculo lambda sin tipo.
En el cálculo lambda sin tipo, todos los términos son términos lambda, y la única operación que se puede realizar en un término es aplicarlo a otro término. Por lo tanto, todas las operaciones siempre dan como resultado una recursión infinita o un término lambda, pero nunca señalan un error.
Sin embargo, si tuviéramos que aumentar el cálculo lambda sin tipo con los números primitivos y operaciones aritméticas, entonces podríamos realizar operaciones sin sentido, como la adición de dos términos lambda juntos: (λx.x) + (λy.y)
. Se podría argumentar que lo único sensato es señalar un error cuando esto sucede, pero para poder hacerlo, cada valor debe etiquetarse con un indicador que indique si el término es un término lambda o un número. El operador de suma luego verificará que, de hecho, ambos argumentos estén etiquetados como números y, si no lo están, indicará un error. Tenga en cuenta que estas etiquetas no son tipos, porque los tipos son propiedades de los programas, no de los valores producidos por esos programas.
Un lenguaje de tipo único que hace esto se llama de tipo dinámico.
Los lenguajes como JavaScript, Python y Ruby son todos de tipo único. Nuevamente, el typeof
operador en JavaScript y la type
función en Python tienen nombres engañosos; devuelven las etiquetas asociadas con los operandos, no sus tipos. Del mismo modo, dynamic_cast
en C ++ y instanceof
en Java no realice verificaciones de tipo.
"Cuando se traduce el código fuente"
"Cuando los tipos están marcados"
5 + '3'
es un ejemplo de un error de tipo en lenguajes fuertemente tipados como Go y Python, porque no permiten la "coerción de tipo" -> la capacidad de un valor para cambiar el tipo en ciertos contextos, como la fusión de dos tipos. Los idiomas mal escritos , como JavaScript, no arrojarán un error de tipo (resultados '53'
).
Las definiciones de "Estático y Compilado" y "Dinámico e Interpretado" son bastante similares ... pero recuerde que es "cuando se marcan los tipos" vs. "cuando se traduce el código fuente".
¡Obtendrá los mismos errores de tipo independientemente de si el idioma está compilado o interpretado ! Necesita separar estos términos conceptualmente.
Dinámico, Interpretado
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
silly(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 else
bloque nunca se ejecuta, por 5 + '3'
lo que nunca se mira!
¿Qué pasa si se ha escrito estáticamente?
Se generaría un error de tipo incluso antes de que se ejecute el código. Todavía realiza la verificación de tipo antes del tiempo de ejecución aunque se interprete.
¿Qué pasa si fue compilado?
El else
bloque se traduciría / miraría antes del tiempo de ejecución, pero como se escribe dinámicamente, ¡no arrojaría un error! Los idiomas escritos 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 silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
¡Los tipos se verifican antes de ejecutarse (estáticos) y el error de tipo se detecta inmediatamente! Los tipos aún se verificarían antes del tiempo de ejecución si se interpretaran, teniendo el mismo resultado. Si fuera dinámico, no arrojaría ningún error a pesar de que el código se vería durante la compilación.
Un lenguaje compilado tendrá un mejor rendimiento en tiempo de ejecución si se escribe estáticamente (vs. dinámicamente); El conocimiento de los tipos permite la optimización del código de máquina.
Los lenguajes tipados estáticamente tienen un mejor rendimiento en tiempo de ejecución intrínsecamente debido a que no es necesario verificar los tipos dinámicamente durante la ejecución (se verifica antes de ejecutarse).
Del mismo modo, los lenguajes compilados son más rápidos en tiempo de ejecución ya que el código ya se ha traducido en lugar de tener que "interpretarlo / traducirlo sobre la marcha".
Tenga en cuenta que tanto los idiomas compilados como los estáticamente escritos tendrán un retraso antes de ejecutar la traducción y la verificación de tipos, respectivamente.
La escritura estática detecta los errores temprano, en lugar de encontrarlos durante la ejecución (especialmente útil para programas largos). Es más "estricto", ya que no permitirá errores de tipo en ningún lugar de su programa y, a menudo, evita que las variables cambien de tipo, lo que defiende aún más contra errores no intencionados.
num = 2
num = '3' // ERROR
La escritura dinámica es más flexible, lo que algunos aprecian. Por lo general, permite que las variables cambien los tipos, lo que puede provocar errores inesperados.
Lenguajes estáticamente tipados : cada variable y expresión ya se conoce en tiempo de compilación.
( int a;
a puede tomar solo valores de tipo entero en tiempo de ejecución)
Ejemplos: C, C ++, Java
Lenguajes de tipo dinámico : las variables pueden recibir diferentes valores en tiempo de ejecución y su tipo se define en tiempo de ejecución.
( var a;
a puede tomar cualquier tipo de valores en tiempo de ejecución)
Ejemplos: Ruby, Python.
Verificación de tipos de idiomas estáticamente escritos en tiempo de compilación y el tipo NO puede cambiar. (No te pongas lindo con los comentarios de conversión de tipos, se crea una nueva variable / referencia).
Verificación de tipo de idiomas escritos dinámicamente en tiempo de ejecución y el tipo de una variable PUEDE cambiarse en tiempo de ejecución.
Definiciones dulces y simples, pero que se ajustan a la necesidad: los lenguajes tipados estáticamente vinculan el tipo a una variable para todo su alcance (Seg: SCALA) Los lenguajes tipados dinámicamente vinculan el tipo al valor real al que hace referencia una variable.
Los lenguajes tipados estáticamente como C ++, Java y los lenguajes tipados dinámicamente como Python difieren solo en términos de la ejecución del tipo de la variable. Los lenguajes tipados estáticamente tienen un tipo de datos estáticos para la variable, aquí el tipo de datos se verifica durante la compilación, por lo que la depuración es mucho más simple ... mientras que los lenguajes tipados dinámicamente no hacen lo mismo, se verifica el tipo de datos que ejecuta el programa y, por lo tanto, el La depuración es un poco difícil.
Además, tienen una diferencia muy pequeña y pueden relacionarse con lenguajes fuertemente tipados y débilmente tipados . Un lenguaje fuertemente tipado no le permite usar un tipo como otro, por ejemplo. C y C ++ ... mientras que los lenguajes débilmente escritos permiten, por ejemplo, python
Mecanografiado estáticamente
Los tipos se verifican antes del tiempo de ejecución para que los errores puedan detectarse antes.
Ejemplos = c ++
Mecanografiado dinámicamente
Los tipos se verifican durante la ejecución.
Ejemplos = Python
Lenguajes de tipo estático (el compilador resuelve llamadas a métodos y compila referencias):
Lenguajes de tipo dinámico (decisiones tomadas en la ejecución del programa):
El lenguaje de tipo dinámico ayuda a prototipar rápidamente los conceptos de algoritmo sin la sobrecarga de pensar qué tipos de variables deben usarse (lo cual es una necesidad en el lenguaje de tipo estático ).
Escritura estática: los lenguajes como Java y Scala son de escritura estática.
Las variables deben definirse e inicializarse antes de usarse en un código.
por ej. int x; x = 10;
System.out.println (x);
Escritura dinámica: Perl es un lenguaje de escritura dinámica.
No es necesario inicializar las variables antes de usarlas en el código.
y = 10; use esta variable en la parte posterior del código
$
), array ( @
) y hash ( %
). El tipo de una variable en Perl se conoce en tiempo de compilación y permanece igual para el resto de la vida útil de las variables.