Silne <=> słabe typowanie dotyczy nie tylko kontinuum tego, ile lub jak mało wartości jest automatycznie wymuszanych przez język dla jednego typu danych na inny, ale także tego, jak mocno lub słabo wpisywane są rzeczywiste wartości . W Pythonie i Javie, a głównie w C #, wartości mają swoje typy ustawione w kamieniu. W Perlu nie tak bardzo - tak naprawdę jest tylko kilka różnych typów wartości, które można przechowywać w zmiennej.
Otwórzmy po kolei skrzynki.
Pyton
Na przykład Python 1 + "1"
, +
operator wywołuje __add__
na typ int
nadając mu ciąg "1"
jako argument - Powoduje to jednak w NotImplemented:
>>> (1).__add__('1')
NotImplemented
Następnie interpreter próbuje __radd__
z str:
>>> '1'.__radd__(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'
Ponieważ się nie powiedzie, +
operator zawodzi z wynikiem TypeError: unsupported operand type(s) for +: 'int' and 'str'
. Jako taki, wyjątek nie mówi wiele o silnym typowaniu, ale fakt, że operator +
nie wymusza automatycznie swoich argumentów na ten sam typ, wskazuje na fakt, że Python nie jest najsłabiej typizowanym językiem w kontinuum.
Z drugiej strony, w Pythonie 'a' * 5
jest realizowany:
>>> 'a' * 5
'aaaaa'
To jest,
>>> 'a'.__mul__(5)
'aaaaa'
Fakt, że operacja jest inna, wymaga pewnego silnego typowania - jednak przeciwieństwo *
przekształcania wartości na liczby przed pomnożeniem nadal niekoniecznie powodowałoby, że wartości byłyby słabo typowane.
Jawa
Przykład w Javie String result = "1" + 1;
działa tylko dlatego, że dla wygody operator +
jest przeciążony ciągami. +
Operator Java zastępuje sekwencję utworzeniem StringBuilder
(zobacz to ):
String result = a + b;
// becomes something like
String result = new StringBuilder().append(a).append(b).toString()
Jest to raczej przykład bardzo statycznego pisania bez rzeczywistego przymusu - StringBuilder
ma metodę, append(Object)
która jest tutaj specjalnie używana. Dokumentacja mówi, co następuje:
Dołącza ciąg reprezentujący Object
argument.
Ogólny efekt jest dokładnie taki, jakby argument został przekonwertowany na łańcuch za pomocą metody String.valueOf(Object)
, a znaki tego ciągu zostały następnie dołączone do tej sekwencji znaków.
Gdzie String.valueOf
wtedy
Zwraca ciąg znaków reprezentujący argument Object. [Zwraca] jeśli argumentem jest null
, to ciąg równy "null"
; w przeciwnym razie zwracana obj.toString()
jest wartość .
Jest to zatem przypadek absolutnego braku przymusu ze strony języka - delegowanie wszelkich trosk na same przedmioty.
DO#
Według odpowiedzi Jona Skeeta , operator +
nie jest nawet przeciążony dla string
klasy - podobnie jak w Javie, jest to po prostu wygoda generowana przez kompilator, dzięki zarówno statycznemu, jak i silnemu typowaniu.
Perl
Jak wyjaśnia perldata ,
Perl ma trzy wbudowane typy danych: skalary, tablice skalarów i asocjacyjne tablice skalarów, znane jako „hashe”. Skalar to pojedynczy ciąg (dowolnego rozmiaru, ograniczony tylko dostępną pamięcią), liczba lub odniesienie do czegoś (co zostanie omówione w perlref). Tablice normalne są uporządkowanymi listami skalarów indeksowanych według numeru, zaczynając od 0. Hashe to nieuporządkowane zbiory wartości skalarnych indeksowane przez skojarzony z nimi klucz łańcuchowy.
Perl nie ma jednak oddzielnego typu danych dla liczb, wartości logicznych, łańcuchów, wartości null, undefined
s, odniesień do innych obiektów itp. - ma tylko jeden typ dla wszystkich tych obiektów, typ skalarny; 0 jest wartością skalarną równą „0”. Zmienna skalarna , która została ustawiona jako ciąg znaków, może naprawdę zmienić się w liczbę i od tego momentu zachowywać się inaczej niż „zwykły łańcuch”, jeśli jest dostępna w kontekście numerycznym. Skalar może pomieścić wszystko w Perlu, jest to tyle samo obiektu, ile istnieje w systemie. podczas gdy w Pythonie nazwy odnoszą się tylko do obiektów, w Perlu wartości skalarne w nazwach są obiektami zmiennymi. Co więcej, do tego przyklejony jest system Object Oriented Type: w perlu są tylko 3 typy danych - skalary, listy i hashe. Obiekt zdefiniowany przez użytkownika w Perlu jest odniesieniem (czyli wskaźnikiem do dowolnego z 3 poprzednich) bless
pakietów - możesz wziąć dowolną taką wartość i pobłogosławić ją dowolnej klasie w dowolnym momencie.
Perl pozwala nawet na zmianę klas wartości według kaprysu - nie jest to możliwe w Pythonie, gdzie aby utworzyć wartość jakiejś klasy, musisz jawnie skonstruować wartość należącą do tej klasy object.__new__
lub podobną. W Pythonie nie da się tak naprawdę zmienić istoty obiektu po utworzeniu, w Perlu możesz zrobić wiele:
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";
w ten sposób tożsamość typu jest słabo związana ze zmienną i można ją zmienić za pomocą dowolnego odwołania w locie. W rzeczywistości, jeśli to zrobisz
my $another = $val;
\$another
nie ma tożsamości klasowej, mimo że \$val
nadal będzie stanowić błogosławione odniesienie.
TL; DR
W Perlu jest o wiele więcej niż tylko automatyczne wymuszanie, ale chodzi o to, że same typy wartości nie są utrwalone, w przeciwieństwie do Pythona, który jest dynamicznym, ale bardzo silnie typizowanym językiem. Że pyton daje TypeError
na 1 + "1"
to wskazuje, że język jest silnie wpisany, choć wbrew jeden robi coś pożytecznego, jak w Java lub C # nie wyklucza je jako zdecydowanie wpisywanych języków.