¿Cuál es la diferencia entre un idioma fuertemente tipado y un lenguaje estáticamente tipado?

Respuestas:

543

¿Cuál es la diferencia entre un idioma fuertemente tipado y un lenguaje estáticamente tipado?

Un lenguaje de tipo estático tiene un sistema de tipos que la implementación verifica en tiempo de compilación (un compilador o intérprete). La verificación de tipo rechaza algunos programas, y los programas que pasan la verificación generalmente vienen con algunas garantías; por ejemplo, el compilador garantiza no usar instrucciones aritméticas de enteros en números de punto flotante.

No existe un acuerdo real sobre lo que significa "fuertemente tipado", aunque la definición más utilizada en la literatura profesional es que en un lenguaje "fuertemente tipado", el programador no puede evitar las restricciones impuestas por el sistema de tipos . Este término casi siempre se usa para describir lenguajes estáticamente escritos.

Estático vs dinámico

Lo contrario de tipado estáticamente es tipado dinámicamente, lo que significa que

  1. Los valores utilizados en tiempo de ejecución se clasifican en tipos.
  2. Existen restricciones sobre cómo se pueden usar dichos valores.
  3. Cuando se violan esas restricciones, la violación se informa como un error de tipo (dinámico).

Por ejemplo, Lua , un lenguaje de tipo dinámico, tiene un tipo de cadena, un tipo de número y un tipo booleano, entre otros. En Lua, cada valor pertenece exactamente a un tipo, pero este no es un requisito para todos los idiomas de tipo dinámico. En Lua, está permitido concatenar dos cadenas, pero no está permitido concatenar una cadena y un booleano.

Fuerte vs débil

Lo contrario de "fuertemente tipado" es "tipeado débilmente", lo que significa que puede evitar el sistema de tipos. C está muy mal escrito porque cualquier tipo de puntero es convertible a cualquier otro tipo de puntero simplemente por conversión. Se pretendía que Pascal estuviera fuertemente tipado, pero un descuido en el diseño (registros de variantes sin etiquetar) introdujo una laguna en el sistema de tipos, por lo que técnicamente está tipado débilmente. Ejemplos de lenguajes verdaderamente fuertemente tipados incluyen CLU, Standard ML y Haskell. De hecho, ML estándar ha sufrido varias revisiones para eliminar las lagunas en el sistema de tipos que se descubrieron después de que el lenguaje se desplegó ampliamente.

¿Qué está pasando realmente aquí?

En general, resulta que no es tan útil hablar de "fuerte" y "débil". Si un sistema de tipo tiene una escapatoria es menos importante que el número exacto y la naturaleza de las escapatorias, qué tan probable es que surjan en la práctica y cuáles son las consecuencias de explotar una escapatoria. En la práctica, es mejor evitar por completo los términos "fuerte" y "débil" , porque

  • Los aficionados a menudo los combinan con "estático" y "dinámico".

  • Aparentemente, algunas personas usan "mecanografía débil" para hablar sobre el predominio relativo o la ausencia de conversiones implícitas.

  • Los profesionales no pueden ponerse de acuerdo sobre el significado exacto de los términos.

  • En general, es poco probable que informe o ilumine a su audiencia.

La triste verdad es que cuando se trata de sistemas de tipos, "fuerte" y "débil" no tienen un significado técnico universalmente acordado. Si desea analizar la fuerza relativa de los sistemas de tipos, es mejor analizar exactamente qué garantías se ofrecen y cuáles no. Por ejemplo, una buena pregunta es: "¿se garantiza que cada valor de un tipo (o clase) determinado se ha creado llamando a uno de los constructores de ese tipo?" En C la respuesta es no. En CLU, F # y Haskell es sí. Para C ++ no estoy seguro, me gustaría saberlo.

Por el contrario, la escritura estática significa que los programas se verifican antes de ejecutarse , y un programa puede ser rechazado antes de que comience. La escritura dinámica significa que los tipos de valores se verifican durante la ejecución, y una operación mal escrita puede causar que el programa se detenga o indique un error en el tiempo de ejecución. Una razón principal para la escritura estática es descartar programas que puedan tener tales "errores de tipo dinámico".

¿Uno implica el otro?

En un nivel pedante, no, porque la palabra "fuerte" realmente no significa nada. Pero en la práctica, las personas casi siempre hacen una de dos cosas:

  • Usan (incorrectamente) "fuerte" y "débil" para referirse a "estático" y "dinámico", en cuyo caso están (incorrectamente) usando indistintamente "fuertemente tipado" y "tipado estáticamente".

  • Utilizan "fuerte" y "débil" para comparar las propiedades de los sistemas de tipo estático. Es muy raro escuchar a alguien hablar sobre un sistema de tipo dinámico "fuerte" o "débil". A excepción de FORTH, que realmente no tiene ningún tipo de sistema de tipos, no puedo pensar en un lenguaje de tipo dinámico donde el sistema de tipos pueda ser subvertido. Por definición, esas comprobaciones se incorporan al motor de ejecución, y cada operación se verifica para verificar su cordura antes de ejecutarse.

De cualquier manera, si una persona llama a un idioma "fuertemente tipado", es muy probable que esa persona esté hablando de un lenguaje estáticamente tipado.

Norman Ramsey
fuente
3
@ Adam: evidentemente no es lo suficientemente correcto como para ser votado :) Debido a que la respuesta de Cletus contiene tantas ideas falsas (aunque eliminé la peor de ellas), me sentí obligado a deletrear todo en palabras de una sílaba ...
Norman Ramsey
1
Bueno, te voté :) Incluso la palabra "compilar" no es clara con las máquinas virtuales de hoy en día que ejecutan lenguajes dinámicos. Técnicamente, Java y C # se compilan dos veces (JIT) y ambos realizan algún tipo de análisis. Un lenguaje como Javascript que se ejecuta en .NET vm podría ser más seguro debido a la VM.
Adam Gent
2
Estoy tan confundido ahora! Bien, queridos grandes gladiadores de la arena, ¿puede una pobre alma como yo ir con la siguiente comprensión simple? 1. Estático: los valores están asociados con el tipo durante el tiempo de compilación y no el tiempo de ejecución 2. Dinámico: los valores están asociados con el tipo durante el tiempo de ejecución, por lo tanto, el tipo del valor puede cambiar durante el tiempo de ejecución ~ por lo que es más propenso a problemas relacionados con la conversión de tipos durante el tiempo de ejecución. 3. Fuerte / débil: ¡Olvídalo! Estos no son términos técnicos y solo una mala nomenclatura. Depende de qué contexto se está hablando. ¿Puedo continuar mi vida con esta simple comprensión? :(
Saurabh Patil
"¿se garantiza que cada valor de un tipo (o clase) dado se ha creado llamando a uno de los constructores de ese tipo?" En C la respuesta es no. ¿Podría alguien proporcionar una situación de ejemplo donde esto ocurre en C? ¿Supongo que implica lanzar punteros a estructuras?
corazza
Mecanografía fuerte y débil: no existe tal clasificación.
Raúl
248

Esto a menudo se entiende mal, así que déjame aclararlo.

Escritura Estática / Dinámica

La escritura estática es donde el tipo está vinculado a la variable . Los tipos se verifican en tiempo de compilación.

La escritura dinámica es donde el tipo está vinculado al valor . Los tipos se verifican en tiempo de ejecución.

Entonces, en Java, por ejemplo:

String s = "abcd";

sserá "para siempre" a String. Durante su vida puede apuntar a diferentes Strings (ya que ses una referencia en Java). Puede tener un nullvalor, pero nunca se referirá a un Integero a List. Eso es tipeo estático.

En PHP:

$s = "abcd";          // $s is a string
$s = 123;             // $s is now an integer
$s = array(1, 2, 3);  // $s is now an array
$s = new DOMDocument; // $s is an instance of the DOMDocument class

Eso es tipeo dinámico.

Mecanografía fuerte / débil

(¡Editar alerta!)

La tipificación fuerte es una frase sin un significado ampliamente aceptado. La mayoría de los programadores que usan este término para significar algo más que la escritura estática lo usan para implicar que el compilador impone una disciplina de tipo. Por ejemplo, CLU tiene un sistema de tipo fuerte que no permite que el código del cliente cree un valor de tipo abstracto, excepto mediante el uso de los constructores proporcionados por el tipo. C tiene un sistema de tipo algo fuerte, pero se puede "subvertir" hasta cierto punto porque un programa siempre puede convertir un valor de un tipo de puntero en un valor de otro tipo de puntero. Entonces, por ejemplo, en C puede tomar un valor devuelto malloc()y emitirlo alegremente FILE*, y el compilador no intentará detenerlo, o incluso advertirle que está haciendo algo dudoso.

(La respuesta original decía algo acerca de un valor "no cambiar el tipo en tiempo de ejecución". He conocido a muchos diseñadores de idiomas y escritores de compiladores y no he conocido uno que hable sobre valores que cambian el tipo en tiempo de ejecución, excepto posiblemente una investigación muy avanzada en tipo sistemas, donde esto se conoce como el "fuerte problema de actualización".)

La escritura débil implica que el compilador no impone una línea de disco de escritura, o tal vez esa aplicación se puede subvertir fácilmente.

El original de esta respuesta combinaba la tipificación débil con la conversión implícita (a veces también llamada "promoción implícita"). Por ejemplo, en Java:

String s = "abc" + 123; // "abc123";

Este código es un ejemplo de promoción implícita: 123 se convierte implícitamente en una cadena antes de concatenarse con "abc". Se puede argumentar que el compilador de Java reescribe ese código como:

String s = "abc" + new Integer(123).toString();

Considere un problema clásico de PHP "comienza con":

if (strpos('abcdef', 'abc') == false) {
  // not found
}

El error aquí es que strpos()devuelve el índice de la coincidencia, siendo 0. 0 se convierte en booleano falsey, por lo tanto, la condición es verdadera. La solución es usar en ===lugar de ==evitar la conversión implícita.

Este ejemplo ilustra cómo una combinación de conversión implícita y escritura dinámica puede llevar a los programadores por mal camino.

Compare eso con Ruby:

val = "abc" + 123

que es un error de tiempo de ejecución porque en Ruby el objeto 123 no se convierte implícitamente solo porque se pasa a un +método. En Ruby, el programador debe hacer explícita la conversión:

val = "abc" + 123.to_s

Comparar PHP y Ruby es una buena ilustración aquí. Ambos son lenguajes de tipo dinámico, pero PHP tiene muchas conversiones implícitas y Ruby (quizás sorprendentemente si no está familiarizado con él) no.

Estático / Dinámico vs Fuerte / Débil

El punto aquí es que el eje estático / dinámico es independiente del eje fuerte / débil. La gente los confunde probablemente en parte porque la tipificación fuerte frente a débil no solo está menos claramente definida, no existe un consenso real sobre exactamente qué se entiende por fuerte y débil. Por esta razón, la escritura fuerte / débil es mucho más de un tono de gris en lugar de negro o blanco.

Entonces, para responder a su pregunta: otra forma de ver esto que es principalmente correcta es decir que la escritura estática es seguridad de tipo de tiempo de compilación y la escritura fuerte es seguridad de tipo de tiempo de ejecución.

La razón de esto es que las variables en un lenguaje de tipo estático tienen un tipo que debe declararse y puede verificarse en tiempo de compilación. Un lenguaje fuertemente tipado tiene valores que tienen un tipo en tiempo de ejecución, y es difícil para el programador subvertir el sistema de tipos sin una verificación dinámica.

Pero es importante comprender que un lenguaje puede ser Estático / Fuerte, Estático / Débil, Dinámico / Fuerte o Dinámico / Débil.

cletus
fuente
En lugar de decir que $ s es un entero o una cadena, hubiera sido mejor si dijera que el tipo está asociado con el "abcd" o 1234 no con la variable $ s.
Srinivas Reddy Thatiparthy
Excelente respuesta con ejemplos claros. Sin embargo, creo que no aborda por completo la confusión sobre POR QUÉ las personas preguntan sobre conceptos fuertes / estáticos como un par de conceptos gemelos. Por ejemplo, la redacción del OP de "¿la escritura estática IMPLICA la escritura fuerte?" Su respuesta enfatiza su independencia. Para continuar la aclaración de por qué el fuerte a menudo se EMPAREJA con estática, la respuesta anterior de Norman Ramsey es muy buena: stackoverflow.com/questions/376611/…
JasDev
1
"abc" + 123es un error de tiempo de ejecución , no un error de compilación en ruby. Si se tratara de un error de compilación, ruby ​​se escribiría estáticamente.
sepp2k
Los ejemplos de mecanografía débil deben mejorarse (ver mi respuesta) pero, por lo demás, un buen formato.
Adam Gent
En mi opinión, el tipo fuerte frente a débil es el siguiente: Fuerte: "c" + Verdadero = error de tiempo de ejecución o error de tiempo de compilación. Débil: "c" + Verdadero = "b" o "d" porque todo se trata como bytes sin formato. Fuerte: C #, Ruby, C ++ Débil: Asamblea, C (debido a punteros de vacío implícitos)
Jonathan Allen
17

Ambos son polos en dos ejes diferentes:

  • fuertemente tipado vs. débilmente tipado
  • de tipo estático frente a de tipo dinámico

Tipeado significa que a no se convertirá automáticamente de un tipo a otro. Débilmente escrito es lo contrario: Perl puede usar una cadena como "123"en un contexto numérico, convirtiéndola automáticamente en int 123. Un lenguaje fuertemente tipado como python no hará esto.

Significa estáticamente significa que el compilador determina el tipo de cada variable en tiempo de compilación. Los lenguajes de tipo dinámico solo calculan los tipos de variables en tiempo de ejecución.

Daren Thomas
fuente
66
Tengo que estar en desacuerdo. Un lenguaje fuertemente tipado es aquel que sabe cuáles son los tipos en tiempo de ejecución. Un lenguaje débilmente tipado es aquel que no le gusta el ensamblado. Su ejemplo está en un tercer eje, "conversiones implícitas vs explícitas".
Jonathan Allen el
1
En realidad normal, estoy de acuerdo con Jonathan, pero no es necesario tener los tipos disponibles en tiempo de ejecución para escribirlos con firmeza si realiza un análisis estático completo y no permite la conversión. (ver mi respuesta editada)
Adam Gent el
1
Python es un ejemplo de un lenguaje de tipo dinámico y de tipo fuerte
MaRoBet
13

Tipeado con firmeza significa que existen restricciones entre las conversiones entre tipos. Tipo estático significa que los tipos no son dinámicos: no puede cambiar el tipo de una variable una vez que se ha creado.

Svetlozar Angelov
fuente
Para demostrar esto: en un lenguaje fuertemente tipado, no puede comparar "5" == 5 y hacer que sea verdadero: las cadenas no son enteros. Si mi memoria funciona, la mayoría de los lenguajes de script modernos están fuertemente tipados dinámicamente. Tcl / Tk, sin embargo, tiene un tipo débil: todo se puede tratar como una cadena.
Little Bobby Tables
Bobby, en un lenguaje débilmente escrito "5" == 5 se lee como 0x35 == 0x05. O en otras palabras, todo se trata como bytes sin formato.
Jonathan Allen el
Tengo que estar en desacuerdo con los dos. Toma Lua; puede comparar "5" == 5 y devolverá falso, sin embargo, se puede hacer una conversión rápida yendo a "5" + 0.
RCIX
12

La coerción de datos no significa necesariamente un tipo débil porque a veces su azúcar sintáctica:

El ejemplo anterior de Java está tipeado débilmente debido a

String s = "abc" + 123;

No es un ejemplo débilmente escrito porque realmente está haciendo:

String s = "abc" + new Integer(123).toString()

La coerción de datos tampoco se tipea débilmente si está construyendo un nuevo objeto. Java es un muy mal ejemplo de tipeado débil (y cualquier lenguaje que tenga una buena reflexión probablemente no se tipeará débilmente). Debido a que el tiempo de ejecución del lenguaje siempre sabe cuál es el tipo (la excepción podría ser tipos nativos).

Esto es diferente a C. C es uno de los mejores ejemplos de tipos débiles. El tiempo de ejecución no tiene idea si 4 bytes es un número entero, una estructura, un puntero o un 4 caracteres.

El tiempo de ejecución del lenguaje realmente define si está tipeado débilmente o no, de lo contrario es realmente una opinión justa.

EDITAR: Después de pensarlo más, esto no es necesariamente cierto, ya que el tiempo de ejecución no tiene que tener todos los tipos reified en el sistema de tiempo de ejecución para ser un sistema fuertemente tipado. Haskell y ML tienen un análisis estático tan completo que pueden omitir potencialmente la información de tipo del tiempo de ejecución.

Adam Gent
fuente
B es probablemente un ejemplo mejor, aunque un poco menos conocido.
Tom Hawtin - tackline
Javascript también es de tipo bastante débil, pero porque hay muy pocos tipos y porque realmente no se pueden construir nuevos tipos.
Adam Gent
10

La respuesta ya está dada arriba. Tratando de diferenciar entre fuerte vs semana y estático vs concepto dinámico.

¿Qué se escribe fuertemente VS se escribe débilmente?

Tipo fuerte: no se convertirá automáticamente de un tipo a otro

En Go o Python, los lenguajes fuertemente tipados "2" + 8 generarán un error de tipo, ya que no permiten la "coerción de tipo".

Tipeado débilmente (flojo): se convertirá automáticamente de un tipo a otro: los idiomas débilmente escritos como JavaScript o Perl no arrojarán un error y, en este caso, JavaScript dará como resultado '28' y Perl dará como resultado 10.

Perl Ejemplo:

my $a = "2" + 8;
print $a,"\n";

Guárdelo en main.pl y ejecútelo, perl main.ply obtendrá la salida 10.

¿Qué es el tipo estático VS dinámico?

En programación, el programador define la tipificación estática y la dinámica con respecto al punto en el que se verifican los tipos de variables. Los lenguajes tipados estáticos son aquellos en los que la verificación de tipos se realiza en tiempo de compilación, mientras que los lenguajes tipados dinámicos son aquellos en los que la verificación de tipos se realiza en tiempo de ejecución.

  • Estático: Tipos verificados antes del tiempo de ejecución
  • Dinámico: tipos marcados sobre la marcha, durante la ejecución

¿Qué significa esto?

En Go, verifica los tipos escritos antes del tiempo de ejecución (comprobación estática). Esto significa que no solo traduce y verifica el código que está ejecutando, sino que escaneará todo el código y se generará un error de tipo incluso antes de que se ejecute el código. Por ejemplo,

package main

import "fmt"

func foo(a int) {
    if (a > 0) {
        fmt.Println("I am feeling lucky (maybe).")
    } else {
        fmt.Println("2" + 8)
    }
}

func main() {
    foo(2)
}

Guarde este archivo en main.go y ejecútelo, obtendrá un mensaje de compilación fallido para esto.

go run main.go
# command-line-arguments
./main.go:9:25: cannot convert "2" (type untyped string) to type int
./main.go:9:25: invalid operation: "2" + 8 (mismatched types string and int)

Pero este caso no es válido para Python. Por ejemplo, el siguiente bloque de código se ejecutará para la primera llamada foo (2) y fallará para la segunda llamada foo (0). Es porque Python se escribe dinámicamente, solo traduce y verifica el código en el que se está ejecutando. El bloque else nunca se ejecuta para foo (2), por lo que nunca se mira "2" + 8 y para la llamada foo (0) intentará ejecutar ese bloque y falló.

def foo(a):
    if a > 0:
        print 'I am feeling lucky.'
    else:
        print "2" + 8
foo(2)
foo(0)

Verá la siguiente salida

python main.py
I am feeling lucky.
Traceback (most recent call last):
  File "pyth.py", line 7, in <module>
    foo(0)
  File "pyth.py", line 5, in foo
    print "2" + 8
TypeError: cannot concatenate 'str' and 'int' objects
Balkrishna
fuente
8

Uno no implica el otro. Para que un lenguaje se tipee estáticamente , significa que los tipos de todas las variables son conocidos o inferidos en tiempo de compilación.

Un lenguaje fuertemente tipado no le permite usar un tipo como otro. C es un lenguaje débilmente tipado y es un buen ejemplo de lo que los lenguajes fuertemente tipados no permiten. En C puede pasar un elemento de datos del tipo incorrecto y no se quejará. En idiomas fuertemente tipados no puedes.

Joe Cannatti
fuente
7

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 convierta en un flotante y el resultado se devuelva como flotante. Si A es un número entero y B es una cadena, entonces la regla estricta podría ser que A + B no sea válida.

La escritura estática probablemente significa que los tipos se asignan en tiempo de compilación (o su equivalente para lenguajes no compilados) y no pueden cambiar durante la ejecución del programa.

Tenga en cuenta que estas clasificaciones no son mutuamente excluyentes, de hecho, esperaría que ocurrieran juntas con frecuencia. Muchos idiomas fuertemente tipados también están tipados 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 en las respuestas hasta ahora.

Marca de alto rendimiento
fuente