Сильная <=> слабая типизация касается не только континуума того, сколько или насколько мало значений автоматически приводится языком для одного типа данных в другой, но насколько сильно или слабо фактические значения набраны. В Python и Java, и в основном в C #, значения имеют свои типы, установленные в камне. В Perl не так много - на самом деле есть лишь несколько различных типов значений для хранения в переменной.
Давайте откроем дела по одному.
Python
В примере Python 1 + "1"
, оператор +
вызывает __add__
для типа int
, давая ему строку "1"
в качестве аргумента - однако это приводит к NotImplemented:
>>> (1).__add__('1')
NotImplemented
Затем интерпретатор пытается __radd__
из str:
>>> '1'.__radd__(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'
При сбое оператор +
завершается ошибкой с результатом TypeError: unsupported operand type(s) for +: 'int' and 'str'
. Таким образом, исключение не говорит много о строгой типизации, но тот факт, что оператор +
не приводит свои аргументы автоматически к одному и тому же типу, указывает на то, что Python не является наиболее слабо типизированный язык в континууме.
С другой стороны, в Python 'a' * 5
реализовано :
>>> 'a' * 5
'aaaaa'
То есть
>>> 'a'.__mul__(5)
'aaaaa'
Тот факт, что операция отличается, требует некоторой строгой типизации - однако противоположность *
приведению значений к числам перед умножением еще не обязательно приведет к слабой типизации значений.
Java
Пример Java, String result = "1" + 1;
, работает только потому, что для удобства оператор +
перегружен для строк. Оператор Java +
заменяет последовательность созданием StringBuilder
(см. this ):
String result = a + b;
// becomes something like
String result = new StringBuilder().append(a).append(b).toString()
Это скорее пример очень статичной типизации, без фактического принуждения - у StringBuilder
есть метод append(Object)
, который специально используется здесь. В документации сказано следующее:
Добавляет строковое представление аргумента Object
.
Общий эффект такой, как если бы аргумент был преобразован в
строка по методу String.valueOf(Object)
и символы
эта строка затем была добавлена к этой последовательности символов.
Где String.valueOf
, затем
Возвращает строковое представление аргумента Object.
[Возвращает], если аргумент null
, то строка, равная "null"
; в противном случае возвращается значение obj.toString()
.
Таким образом, это тот случай, когда язык полностью не принуждается - делегировать все заботы самим объектам.
C #
Согласно ответу Джона Скита здесь , оператор +
даже не перегружен для класса string
- сродни Java, это просто удобство, генерируемое компилятором, благодаря как статическим, так и строгий набор текста.
Perl
Как объясняет perldata ,
Perl имеет три встроенных типа данных: скаляры, массивы скаляров и ассоциативные массивы скаляров, известные как «хэши». Скаляр - это отдельная строка (любого размера, ограниченная только доступной памятью), число или ссылка на что-либо (что будет обсуждаться в perlref). Обычные массивы - это упорядоченные списки скаляров, проиндексированные по номерам, начиная с 0. Хэши - это неупорядоченные наборы скалярных значений, проиндексированных по соответствующему строковому ключу.
Perl, однако, не имеет отдельного типа данных для чисел, логических значений, строк, нулей, undefined
s, ссылок на другие объекты и т. Д. - у него есть только один тип для всех этих, скалярный тип;0 - это скалярное значение, равно как и «0».Скалярная переменная , заданная в виде строки, может действительно измениться на число, и с этого момента вести себя иначе, чем "просто строка", , если к ней обращаются в числовом контексте .Скаляр может содержать что угодно в Perl, он такой же объект, как и существующий в системе.тогда как в Python имена просто ссылаются на объекты, в Perl скалярные значения в именах являются изменяемыми объектами.Более того, система объектно-ориентированного типа приклеена поверх этого: в perl - всего 3 типа данных - скаляры, списки и хэши.Пользовательский объект в Perl - это ссылка (то есть указатель на любой из 3 предыдущих), bless
редактируемый для пакета - вы можете принять любое такое значение и благословить его для любого класса в любой момент, когда захотите.
Perl даже позволяет вам изменять классы значений по своему усмотрению - это не возможно в Python, где для создания значения некоторого класса вам нужно явно создать значение, принадлежащее этому классу, с помощью object.__new__
или подобного,В Python вы не можете реально изменить сущность объекта после создания, в Perl вы можете делать много всего:
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";
, таким образом, идентификатор типа слабо связан с переменной, и его можно изменить с помощью любогоСсылка на лету.Фактически, если у вас
my $another = $val;
\$another
нет идентификатора класса, даже если \$val
все равно даст благословенную ссылку.
TL; DR
Существует гораздо больше о слабой типизации в Perl, чем просто автоматическое принуждение, и больше о том, что типы самих значений не заложены в камень, в отличие от Python, который является динамически, но очень строго типизированным языком.То, что python дает TypeError
на 1 + "1"
, указывает на то, что язык строго типизирован, хотя, наоборот, делает что-то полезное, как в Java или C #, не исключает, что они являются строго типизированными языками.