Respuestas:
¿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.
Lo contrario de tipado estáticamente es tipado dinámicamente, lo que significa que
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.
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.
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.
Esto a menudo se entiende mal, así que déjame aclararlo.
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";
s
será "para siempre" a String
. Durante su vida puede apuntar a diferentes String
s (ya que s
es una referencia en Java). Puede tener un null
valor, pero nunca se referirá a un Integer
o 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.
(¡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 false
y, 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.
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.
"abc" + 123
es 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.
Ambos son polos en dos ejes diferentes:
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.
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.
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.
La respuesta ya está dada arriba. Tratando de diferenciar entre fuerte vs semana y estático vs concepto dinámico.
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.pl
y obtendrá la salida 10.
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.
¿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
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.
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.