La tipificación fuerte <=> débil no se trata solo del continuo sobre cuánto o cuán poco de los valores son coaccionados automáticamente por el idioma para un tipo de datos a otro, sino cuán fuerte o débilmente se escriben los valores reales . En Python y Java, y principalmente en C #, los valores tienen sus tipos establecidos en piedra. En Perl, no tanto: en realidad solo hay un puñado de diferentes tipos de valores para almacenar en una variable.
Abramos los casos uno por uno.
Pitón
En el ejemplo de Python 1 + "1"
, el +
operador llama al __add__
tipo para int
darle la cadena "1"
como argumento; sin embargo, esto da como resultado NotImplemented:
>>> (1).__add__('1')
NotImplemented
A continuación, el intérprete prueba el __radd__
de str:
>>> '1'.__radd__(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'
Como falla, el +
operador falla con el resultado TypeError: unsupported operand type(s) for +: 'int' and 'str'
. Como tal, la excepción no dice mucho sobre la escritura fuerte, pero el hecho de que el operador +
no coaccione sus argumentos automáticamente al mismo tipo, es un indicador del hecho de que Python no es el lenguaje más débilmente escrito en el continuo.
Por otro lado, en Python 'a' * 5
se implementa:
>>> 'a' * 5
'aaaaa'
Es decir,
>>> 'a'.__mul__(5)
'aaaaa'
El hecho de que la operación sea diferente requiere un tipo de escritura fuerte; sin embargo, lo contrario de *
coaccionar los valores a números antes de multiplicar aún no necesariamente haría que los valores se tipeen débilmente.
Java
El ejemplo de Java String result = "1" + 1;
funciona solo porque, por conveniencia, el operador +
está sobrecargado de cadenas. El +
operador Java reemplaza la secuencia con la creación de StringBuilder
(ver esto ):
String result = a + b;
// becomes something like
String result = new StringBuilder().append(a).append(b).toString()
Este es más bien un ejemplo de tipeo muy estático, sin ninguna coerción real: StringBuilder
tiene un método append(Object)
que se usa específicamente aquí. La documentación dice lo siguiente:
Agrega la representación de cadena del Object
argumento.
El efecto general es exactamente como si el argumento convirtiera el argumento en una cadena String.valueOf(Object)
y los caracteres de esa cadena se agregaran a esta secuencia de caracteres.
Donde String.valueOf
entonces
Devuelve la representación de cadena del argumento Object. [Devuelve] si el argumento es null
, entonces una cadena igual a "null"
; de lo contrario, obj.toString()
se devuelve el valor de .
Por lo tanto, este es un caso de absolutamente ninguna coerción por parte del lenguaje, delegando toda preocupación a los objetos en sí.
C#
De acuerdo con la respuesta de Jon Skeet aquí , el operador +
ni siquiera está sobrecargado para la string
clase, similar a Java, esto es solo la conveniencia generada por el compilador, gracias a la escritura tanto estática como fuerte.
Perl
Como explica el perldata ,
Perl tiene tres tipos de datos integrados: escalares, matrices de escalares y matrices asociativas de escalares, conocidas como "hashes". Un escalar es una cadena única (de cualquier tamaño, limitada solo por la memoria disponible), un número o una referencia a algo (que se analizará en perlref). Las matrices normales son listas ordenadas de escalares indexados por número, comenzando con 0. Los hashes son colecciones desordenadas de valores escalares indexados por su clave de cadena asociada.
Sin embargo, Perl no tiene un tipo de datos separado para números, booleanos, cadenas, nulos, undefined
s, referencias a otros objetos, etc., solo tiene un tipo para todos estos, el tipo escalar; 0 es un valor escalar tanto como "0". Una variable escalar que se estableció como una cadena realmente puede cambiar a un número y, a partir de ahí, comportarse de manera diferente a "solo una cadena", si se accede a ella en un contexto numérico. El escalar puede contener cualquier cosa en Perl, es tanto el objeto como existe en el sistema. mientras que en Python los nombres solo se refieren a los objetos, en Perl los valores escalares en los nombres son objetos modificables. Además, el sistema de tipo orientado a objetos está pegado encima de esto: solo hay 3 tipos de datos en perl: escalares, listas y hashes. Un objeto definido por el usuario en Perl es una referencia (es decir, un puntero a cualquiera de los 3 anteriores) bless
editado a un paquete: puede tomar dicho valor y bendecirlo a cualquier clase en el instante que desee.
Perl incluso le permite cambiar las clases de valores a su antojo; esto no es posible en Python, donde crear un valor de alguna clase necesita construir explícitamente el valor que pertenece a esa clase con object.__new__
o similar. En Python realmente no puedes cambiar la esencia del objeto después de la creación, en Perl puedes hacer casi cualquier cosa:
package Foo;
package Bar;
my $val = 42;
# $val is now a scalar value set from double
bless \$val, Foo;
# all references to $val now belong to class Foo
my $obj = \$val;
# now $obj refers to the SV stored in $val
# thus this prints: Foo=SCALAR(0x1c7d8c8)
print \$val, "\n";
# all references to $val now belong to class Bar
bless \$val, Bar;
# thus this prints Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# we change the value stored in $val from number to a string
$val = 'abc';
# yet still the SV is blessed: Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# and on the course, the $obj now refers to a "Bar" even though
# at the time of copying it did refer to a "Foo".
print $obj, "\n";
por lo tanto, la identidad de tipo está débilmente ligada a la variable y se puede cambiar a través de cualquier referencia sobre la marcha. De hecho, si lo haces
my $another = $val;
\$another
no tiene la identidad de clase, aunque \$val
todavía dará la referencia bendecida.
TL; DR
Hay mucho más sobre la escritura débil en Perl que solo las coerciones automáticas, y se trata más de que los tipos de los valores en sí mismos no están establecidos en piedra, a diferencia de Python, que es un lenguaje de escritura dinámica pero muy fuerte. Eso da pitón TypeError
en 1 + "1"
una indicación de que el lenguaje es fuertemente tipado, aunque el uno en contra de hacer algo útil, como en Java o C # no se opone a ellos siendo idiomas inflexible.