programming-languages - the - top programming languages 2018
¿Cuál es la diferencia entre idiomas tipificados estáticamente y dinámicamente? (16)
Compilado vs interpretado
"Cuando se traduce el código fuente"
- Código fuente : Código original (generalmente escrito por un humano en una computadora)
- Traducción : convertir el código fuente en algo que una computadora puede leer (es decir, código de máquina)
- Tiempo de ejecución : período en el que el programa está ejecutando comandos (después de la compilación, si está compilado)
- Idioma compilado : Código traducido antes del tiempo de ejecución
- Lenguaje interpretado : Código traducido al vuelo, durante la ejecución.
Mecanografía
"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 "coacción de tipo" -> la capacidad de un valor para cambiar el tipo en ciertos contextos como fusionar dos tipos Los lenguajes mal escritos , como JavaScript, no producen un error de tipo (da como resultado ''53''
).
- Estático : tipos verificados antes del tiempo de ejecución
- Dinámico : Tipos verificados al vuelo, durante la ejecución.
Las definiciones de "Static & Compiled" y "Dynamic & Interpreted" son bastante similares ... pero recuerde que es "cuando se comprueban los tipos" frente a "cuando se traduce el código fuente".
¡Obtendrá los mismos errores de tipo independientemente de si el lenguaje se compila o interpreta ! Es necesario separar estos términos conceptualmente.
Ejemplo de Python
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 que se está ejecutando. El bloque else
nunca se ejecuta, por lo que 5 + ''3''
ni siquiera se ve!
¿Y si se escribía estáticamente?
Se generará un error de tipo antes de que se ejecute el código. Todavía realiza una comprobación de tipo antes del tiempo de ejecución, aunque se interprete.
¿Y si fue compilado?
El bloque else
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.
Ir ejemplo
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 comprueban antes de ejecutarse (estático) y el error de tipo se detecta de inmediato. Los tipos 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 a pesar de que el código se vería durante la compilación.
Actuación
Un lenguaje compilado tendrá un mejor rendimiento en tiempo de ejecución si se escribe de forma estática (en lugar de dinámicamente); El conocimiento de los tipos permite la optimización del código de máquina.
Los idiomas escritos de forma estática tienen un mejor rendimiento en el tiempo de ejecución intrínsecamente debido a que no necesitan verificar tipos dinámicamente mientras se ejecutan (verifican antes de ejecutar).
De manera similar, los idiomas compilados son más rápidos en el 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 los idiomas compilados y estáticos tipificados tendrán un retraso antes de ejecutar la traducción y la comprobación de tipos, respectivamente.
Más diferencias
La escritura estática detecta los errores antes, en lugar de encontrarlos durante la ejecución (especialmente útil para programas largos). Es más "estricto" porque no permite errores de tipo en ninguna parte de su programa y, a menudo, evita que las variables cambien de tipo, lo que defiende aún más contra los errores no deseados.
num = 2
num = ''3'' // ERROR
La tipificación dinámica es más flexible, lo que algunos aprecian. Por lo general, permite que las variables cambien de tipo, lo que puede dar como resultado errores inesperados.
Escucho mucho que los nuevos lenguajes de programación se escriben dinámicamente, pero ¿qué significa realmente cuando decimos que un lenguaje se escribe de forma dinámica en lugar de escribir estáticamente?
Lenguajes tipificados estáticamente
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 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 comprobación, y por lo tanto, se detectan muchos errores triviales en una etapa muy temprana.
Lenguajes dinámicamente escritos
Un idioma se escribe dinámicamente si el tipo está asociado con valores de tiempo de ejecución y no con nombre variables / fields / 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 tipo ). Ejemplo: Perl, Ruby, Python
La mayoría de los lenguajes de secuencias de comandos tienen esta función, ya que de todos modos no hay un compilador para realizar la comprobación estática de tipos, pero es posible que esté buscando un error debido a que el intérprete interpreta mal el tipo de variable. Por suerte, los scripts tienden a ser pequeños, por lo que los insectos no tienen tantos lugares donde 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 tipificación dinámica dentro de las funciones, pero impone una tipificación estática para la firma de la función.
Aquí hay un ejemplo que contrasta cómo Python (tipificado dinámicamente) y Go (tipificado estáticamente) manejan un error de tipo:
def silly(a):
if a > 0:
print ''Hi''
else:
print 5 + ''3''
Python realiza la comprobación de tipos en el tiempo de ejecución y, por lo tanto:
silly(2)
Funciona perfectamente bien, y produce la salida esperada 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 fue ejecutada realmente.
Por otro lado, ir haciendo la comprobación de tipos 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)
Definiciones dulces y simples, pero que se ajustan a la necesidad: los idiomas tipificados estáticamente vinculan el tipo a una variable para todo su alcance (Seg: SCALA) Los idiomas tipificados dinámicamente vinculan el tipo al valor real al que hace referencia una variable.
En un lenguaje de tipo estático , cada nombre de variable está vinculado tanto a un tipo (en tiempo de compilación, mediante una declaración de datos) como a un objeto. El enlace a un objeto es opcional: si un nombre no está vinculado a un objeto, se dice que el nombre es nulo. En un lenguaje de tipo dinámico , cada nombre de variable está (a menos que sea nulo) enlazado solo a un objeto.
Los nombres están vinculados a los objetos en el momento de la ejecución por medio de instrucciones de asignación, y es posible vincular un nombre a objetos de diferentes tipos durante la ejecución del programa.
La terminología "tipificada dinámicamente" desafortunadamente es engañosa. Todos los idiomas están escritos de forma estática y los tipos son propiedades de expresiones (no de valores, como algunos piensan). Sin embargo, algunos idiomas tienen un solo tipo. Estos se llaman lenguajes uni-escritos. Un ejemplo de tal lenguaje es el cálculo lambda no tipificado.
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 aplicarla 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 indican un error.
Sin embargo, si aumentáramos el cálculo lambda no tipificado con números primitivos y operaciones aritméticas, podríamos realizar operaciones sin sentido, como la suma de dos términos lambda: (λx.x) + (λy.y)
. Se podría argumentar que lo único sensato es señalar un error cuando esto ocurra, 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 adición luego verificará que, de hecho, ambos argumentos estén etiquetados como números, y si no lo están, señalarán un error. Tenga en cuenta que estas etiquetas no son tipos, porque los tipos son propiedades de programas, no de valores producidos por esos programas.
Un lenguaje de tipo único que hace esto se denomina tipificación dinámica.
Los lenguajes como JavaScript, Python y Ruby están todos tipificados. Nuevamente, el operador typeof
en JavaScript y la función type
en Python tienen nombres confusos; devuelven las etiquetas asociadas con los operandos, no sus tipos. De forma similar, dynamic_cast
en C ++ y instanceof
en Java no realizan comprobaciones de tipo.
Los lenguajes con tipos estáticos como C ++, Java y los lenguajes con tipos dinámicos como Python difieren solo en términos de la ejecución del tipo de variable. Los idiomas tipificados estáticamente tienen un tipo de datos estático 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 idiomas tipificados dinámicamente no hacen lo mismo, el tipo de datos se verifica qué ejecutando el programa y por lo tanto La depuración es un poco difícil.
Además, tienen una diferencia muy pequeña y pueden relacionarse con lenguajes fuertemente tipados y con tipos débiles . Un lenguaje fuertemente tipado no le permite usar un tipo como otro, por ejemplo. C y C ++ ... mientras que los lenguajes mal escritos permiten eg.python
Los lenguajes de programación tipificados estáticamente realizan la verificación de tipos (es decir, el proceso de verificar y hacer cumplir las restricciones de tipos) en tiempo de compilación en lugar de tiempo de ejecución .
Los lenguajes de programación tipificados dinámicamente realizan la comprobación de tipos en tiempo de ejecución en lugar de en tiempo de compilación .
Los tipos de idioma tipificados estáticamente comprueban 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).
Los idiomas tipeados dinámicamente verifican en tiempo de ejecución y el tipo de una variable PUEDE cambiarse en tiempo de ejecución.
Simplemente, póngalo de esta manera: 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 cambiarlo. Esto se debe a que la escritura 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
Por otro lado, donde en un idioma de tipo dinámico , los tipos de variables son dinámicos , es decir, después de establecer una variable en un tipo, PUEDE cambiarlo. Esto se debe a que la escritura 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 de tipo dinámico solo como punteros genéricos a valores escritos.
En resumen, el tipo describe (o debería haber descrito) las variables en el idioma en lugar del idioma en sí. Se podría haber utilizado mejor como lenguaje con variables tipificadas estáticamente frente a un idioma con variables tipificadas dinámicamente, en mi humilde opinión.
Los lenguajes de tipo estático generalmente son lenguajes compilados, por lo tanto, los compiladores verifican los tipos (tiene perfecto sentido, ya que los tipos no se pueden cambiar más adelante en el tiempo de ejecución).
Los idiomas tipeados dinámicamente generalmente se interpretan, por lo tanto, la verificación de tipos (si existe) ocurre en el tiempo de ejecución cuando se usan. Por supuesto, esto conlleva un costo de rendimiento, y es una de las razones por las que los lenguajes dinámicos (por ejemplo, python, ruby, php) no se escalan tan bien como los escritos (java, c #, etc.). Desde otra perspectiva, los idiomas escritos de forma estática tienen más de un costo de inicio: normalmente hace que escriba más código, código más difícil. Pero eso se paga después.
Lo bueno es que ambos lados están prestando características del otro lado. Los lenguajes tipados incorporan características más dinámicas, por ejemplo, genéricos y bibliotecas dinámicas en c #, y los lenguajes dinámicos incluyen más comprobaciones de tipos, por ejemplo, anotaciones de tipo en python, o variante HACK de PHP, que generalmente no son fundamentales para el lenguaje y son utilizables en demanda.
Cuando se trata de la selección de tecnología, ninguna de las partes tiene una superioridad intrínseca sobre la otra. 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 de lo contrario antes de considerar un cambio.
http://en.wikipedia.org/wiki/Type_system
Mecanografia estatica
Se dice que un lenguaje de programación utiliza la escritura estática cuando la verificación de tipos se realiza durante el tiempo de compilación en lugar de en tiempo de ejecución. En la escritura estática, los tipos están asociados con variables, no valores. Los idiomas tipificados estáticamente incluyen Ada, C, C ++, C #, JADE, Java, Fortran, Haskell, ML, Pascal, Perl (con respecto a distinguir los escalares, matrices, hashes 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 son capaces de verificar que las condiciones verificadas se mantienen para todas las ejecuciones posibles del programa, lo que elimina la necesidad de repetir las 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 tener menos memoria) al omitir las verificaciones 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 tener un buen comportamiento en el tiempo de ejecución, pero que no pueden determinarse estáticamente como si estuvieran 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>
se rechazará como mal escrito, porque un análisis estático no puede determinar que no se tomará la rama else. [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 las rutas de código que rara vez se utilizan. Sin la verificación de tipo estático, incluso las pruebas de cobertura de código con una cobertura de código del 100% pueden no ser capaces de encontrar este tipo de errores. Las pruebas de cobertura de código pueden no detectar este tipo de errores debido a que 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 determinado valor.
Los lenguajes de tipo estático más utilizados no son formalmente seguros para tipos. Tienen "lagunas" en la especificación del lenguaje de programación, lo que permite a los programadores escribir código que evite la verificación realizada por un verificador de tipo estático y así abordar una amplia gama de problemas. Por ejemplo, Java y la mayoría de los lenguajes de estilo C tienen el tipo punning, y Haskell tiene características como unsafePerformIO: 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 los valores cuando se ejecuta el programa.
Tipificación dinámica
Se dice que un lenguaje de programación se escribe de forma dinámica, o simplemente "dinámico", cuando la mayoría de su tipo de verificación se realiza en tiempo de ejecución en lugar de en tiempo de compilación. En la tipificación dinámica, los tipos se asocian con valores, no con variables. Los lenguajes de escritura dinámica incluyen Groovy, JavaScript, Lisp, Lua, Objective-C, Perl (con respecto a los tipos definidos por el usuario pero no los tipos incorporados), PHP, Prolog, Python, Ruby, Smalltalk y Tcl. En comparación con la tipificación estática, la tipificación dinámica puede ser más flexible (por ejemplo, al permitir que los programas generen tipos y funciones basadas en datos en 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 un verificador de tipo estático puede descartar como no válido.
La escritura dinámica puede dar como resultado errores de tipo de 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 haber tenido. Esto hace que el error sea difícil de localizar.
Los sistemas de lenguaje de tipo dinámico, en comparación con sus primos de tipo estático, realizan menos comprobaciones de "tiempo de compilación" en el código fuente (pero comprobarán, por ejemplo, que el programa es sintácticamente correcto). Las verificaciones en tiempo de ejecución pueden ser potencialmente más sofisticadas, ya que pueden usar información dinámica así como cualquier información 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 de tipos dinámicos a menudo es apoyado por prácticas de programación como las pruebas unitarias. Las pruebas son una práctica clave en el desarrollo de software profesional, y son particularmente importantes en los lenguajes de tipo dinámico. En la práctica, las pruebas realizadas para garantizar el funcionamiento correcto del programa pueden detectar un rango de errores mucho más amplio que la comprobación de tipos estática, pero, a la inversa, no pueden buscar de forma exhaustiva los errores que tanto las pruebas como la comprobación de tipos estática pueden detectar. Las pruebas pueden incorporarse 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 manualmente dichas pruebas.
Referencias
- Pierce, Benjamin (2002). Tipos y lenguajes de programación. MIT Presione. ISBN 0-262-16209-1.
Escritura estática: los lenguajes como Java y Scala son de tipo estático.
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.
Las variables no necesitan inicializarse antes de ser utilizadas en el código.
y = 10; usa esta variable en la parte posterior del código
La escritura fuerte probablemente significa que las variables tienen un tipo bien definido y que existen reglas estrictas sobre la combinación de variables de diferentes tipos en expresiones. Por ejemplo, si A es un entero y B es un flotante, entonces la regla estricta sobre A + B podría ser que A se convierte en un flotador y el resultado se devuelve como un flotador. Si A es un entero y B es una cadena, entonces la regla estricta podría ser que A + B no es válido.
La escritura estática probablemente significa que los tipos se asignan en el momento de la compilación (o su equivalente para idiomas no compilados) y no pueden cambiar durante la ejecución del programa.
Tenga en cuenta que estas clasificaciones no son mutuamente excluyentes, de hecho espero que se produzcan juntas con frecuencia. Muchos lenguajes fuertemente tipados también están tipificados estáticamente.
Y tenga en cuenta que cuando uso la palabra "probablemente" es porque no hay definiciones universalmente aceptadas de estos términos. Como ya habrás visto por las respuestas hasta ahora.
Simplemente póngalo de esta manera: en un lenguaje de tipo estático , el tipo es estático , lo que significa que una vez que establece una variable en un tipo, NO puede cambiarlo. Esto se debe a que la escritura está asociada con la variable en lugar del valor al que se refiere.
Por ejemplo en Java:
String str = "Hello"; //statically typed as string
str = 5; //would throw an error since java is statically typed
Mientras que en un lenguaje de tipo dinámico , el tipo es dinámico , lo que significa que después de establecer una variable en un tipo, PUEDE cambiarlo. Esto se debe a que la escritura está asociada con el valor en lugar de la variable.
Por ejemplo en Python:
str = "Hello" # it is a string
str = 5 # now it is an integer; perfectly OK
Por otro lado, la escritura fuerte / débil en un lenguaje está relacionada con las conversiones de tipo implícitas (en parte, tomadas de la respuesta de @Dario):
Por ejemplo en Python:
str = 5 + "hello"
# would throw an error since it does not want to cast one type to the other implicitly.
mientras que en PHP:
$str = 5 + "hello"; // equals 5 because "hello" is implicitly casted to 0
// PHP is weakly typed, thus is a very forgiving language.
La escritura estática permite verificar la corrección del tipo en el momento de la compilación. Los lenguajes con tipos estáticos generalmente se compilan, y los idiomas con tipos dinámicos se interpretan. Por lo tanto, los idiomas escritos dinámicamente pueden verificar la escritura en tiempo de ejecución.
Lenguajes tipificados estáticamente : cada variable y expresión ya se conocen en tiempo de compilación.
(int a; a puede tomar solo valores de tipo entero en tiempo de ejecución)
Por ejemplo: C, C ++, Java
Idiomas tipificados dinámicamente : los varialbes 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)
Por ejemplo: Ruby, Python.
el lenguaje tipificado dinámicamente ayuda a crear prototipos de conceptos de algoritmos rápidamente sin la sobrecarga de pensar qué tipos de variables deben usarse (lo cual es una necesidad en el lenguaje tipificado estáticamente ).
- En un lenguaje de tipo estático, una variable se asocia con un tipo que se conoce en el momento de la compilación, y ese tipo permanece sin cambios durante la ejecución de un programa. De forma equivalente, a la variable solo se le puede asignar un valor que es una instancia del tipo conocido / especificado.
- En un lenguaje de tipo dinámico, una variable no tiene tipo, y su valor durante la ejecución puede ser de cualquier forma y forma.