Dążenie do wyjaśnienia pozornych sprzeczności dotyczących słabo typowanych języków

Myślę, że rozumiem silne typowanie , ale za każdym razem, gdy szukam przykładów na to, czym jest słabe typowanie, znajduję przykłady języków programowania, które po prostu wymuszają/konwertują typy automatycznie.

Na przykład, w tym artykule o nazwie Typing: Strong vs. Weak, Static vs. Dynamic mówi, że Python jest mocno wpisywany, ponieważ otrzymasz wyjątek, jeśli spróbujesz:

Python

1 + "1"
Traceback (most recent call last):
File "", line 1, in ? 
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Jednak takie rzeczy są możliwe w Javie i w C#, a my nie uważajcie ich za słabo napisane tylko po to.

Java

  int a = 10;
  String b = "b";
  String result = a + b;
  System.out.println(result);

C #

int a = 10;
string b = "b";
string c = a + b;
Console.WriteLine(c);

W innym artykule o nazwie języki słabo typowane autor mówi, że Perl jest słabo typowany po prostu dlatego, że mogę połączyć łańcuch znaków z liczbą i viceversa bez wyraźnej konwersji.

Perl

$a=10;
$b="a";
$c=$a.$b;
print $c; #10a

Więc ten sam przykład sprawia, że Perl jest słabo napisany, ale nie Java i C#?.

[[4]}Gee, to jest mylące Tutaj wpisz opis obrazka

Autorzy zdają się sugerować, że język, który uniemożliwia stosowanie pewnych operacji na wartościach różnych typów, jest silnie wpisany, a przeciwnie oznacza słabo wpisany.

Dlatego w pewnym momencie poczułem się skłaniany do przekonania, że jeśli język zapewnia wiele automatycznych konwersji lub przymusu między typami (jak perl), może skończyć się być uważany za słabo napisany, podczas gdy inne języki, które zapewniają tylko kilka konwersji, mogą skończyć się być uważane za silnie wpisana na maszynie.

Jestem skłonny wierzyć, że muszę się mylić w tej interpretacji, po prostu nie wiem dlaczego i jak to wyjaśnić. Moje pytania to:]}
  • co tak naprawdę oznacza, że język jest naprawdę słabo pisany?
  • czy mógłbyś wymienić jakieś dobre przykłady słabego typowania, które nie są związane z automatyczną konwersją / automatycznym przymusem wykonywanym przez język?
  • czy język może być słabo pisany i mocno pisany jednocześnie czas?
Author: peter-b, 2012-03-29

9 answers

UPDATE: to pytanie było tematem mojego bloga 15 października 2012 roku. dzięki za świetne pytanie!


Co tak naprawdę oznacza, że język jest "słabo pisany"?

To znaczy "ten język używa systemu typów, który uważam za niesmaczny". Język" silnie typowany " jest natomiast językiem z systemem typów, który uważam za przyjemny.

Terminy są zasadniczo bez znaczenia i należy ich unikać. Wikipedia listy jedenaście różnych znaczeń dla "mocno wpisanego", z których kilka jest sprzecznych. Oznacza to, że szanse na powstanie zamieszania są wysokie w każdej rozmowie z użyciem terminu "silnie wpisany" lub "słabo wpisany".

Wszystko, co można naprawdę powiedzieć z całą pewnością, to to, że" silnie wpisany "język w dyskusji ma pewne dodatkowe ograniczenia w systemie typów, zarówno w czasie wykonywania, jak i kompilacji, że" słabo wpisanego " języka w dyskusji brakuje. Co? tego ograniczenia nie można określić bez dalszego kontekstu.

Zamiast używać "mocno wpisane" i "słabo wpisane", powinieneś szczegółowo opisać, jaki rodzaj bezpieczeństwa typu masz na myśli. Na przykład, C# jest językiem statycznie wpisywanym i językiem typu safe oraz językiem pamięci safe, w większości. C# pozwala na łamanie wszystkich trzech form" silnego " typowania. Operator obsady narusza statyczne typowanie; mówi do kompilator "wiem więcej o typie runtime tego wyrażenia niż ty". Jeśli programista się myli, wtedy runtime wyrzuci wyjątek w celu ochrony bezpieczeństwa typu. Jeśli programista chce złamać bezpieczeństwo typu lub bezpieczeństwa pamięci, może to zrobić, wyłączając system bezpieczeństwa typu, tworząc "niebezpieczny" blok. W niebezpiecznym bloku możesz użyć magii wskaźnika, aby traktować int jako float (naruszając bezpieczeństwo typu) lub zapisać do pamięci, której nie posiadasz. (Naruszenie bezpieczeństwa pamięci.)

C# nakłada ograniczenia typu, które są sprawdzane zarówno w czasie kompilacji, jak i w czasie wykonywania, czyniąc z niego język "silnie wpisany" w porównaniu z językami, które mniej sprawdzają w czasie kompilacji lub mniej sprawdzają w czasie wykonywania. C# pozwala również w szczególnych okolicznościach wykonać end-run wokół tych ograniczeń, co czyni go językiem "słabo typowanym"w porównaniu z językami, które nie pozwalają na takie End-run.

Co to jest naprawdę? Nie da się powiedzieć; zależy to od punktu widzenia mówca i ich stosunek do różnych cech językowych.

 206
Author: Eric Lippert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-20 19:03:09

Jak zauważyli inni, terminy "mocno wpisane" i "słabo wpisane" mają tak wiele różnych znaczeń, że nie ma jednej odpowiedzi na twoje pytanie. Jednakże, ponieważ w swoim pytaniu wyraźnie wspomniałeś o perlu, pozwól, że postaram się wyjaśnić w jakim sensie Perl jest słabo napisany.

Chodzi o to, że w Perlu nie ma czegoś takiego jak "zmienna całkowita", "zmienna zmiennoprzecinkowa", "zmienna łańcuchowa"lub" zmienna logiczna". W rzeczywistości, o ile użytkownik może (zazwyczaj) stwierdzić, nie ma even integer, float, string lub boolean wartości: wszystko, co masz, to "Skalary", które są wszystkimi tymi rzeczami w tym samym czasie. Można więc np. napisać:

$foo = "123" + "456";           # $foo = 579
$bar = substr($foo, 2, 1);      # $bar = 9
$bar .= " lives";               # $bar = "9 lives"
$foo -= $bar;                   # $foo = 579 - 9 = 570

Oczywiście, jak słusznie zauważyłeś, wszystko to może być postrzegane jako przymus typu. Ale chodzi o to, że w Perlu typy są zawsze przymuszane. W rzeczywistości, jest to dość trudne dla użytkownika, aby powiedzieć, co wewnętrzny" typ " zmiennej może być: w linii 2 w moim przykładzie powyżej, pytając, czy wartość $bar czy łańcuch "9" lub liczba 9jest w zasadzie bez znaczenia, ponieważ, jeśli chodzi o Perl, są to te same rzeczy. W rzeczywistości, możliwe jest nawet, że Skalar Perla wewnętrznie ma zarówno ciąg znaków, jak i wartość liczbową w tym samym czasie, jak to ma miejsce np. w przypadku $foo po linii 2 powyżej.

Druga strona tego wszystkiego jest taka, że ponieważ zmienne Perla nie są typowane (a raczej nie ujawniają ich wewnętrznego typu użytkownikowi), operatorzy nie mogą być przeciążeni, aby to zrobić różne rzeczy dla różnych typów argumentów; nie można po prostu powiedzieć "ten operator zrobi x dla liczb I Y dla ciągów", ponieważ operator nie może (nie będzie) powiedzieć, jakiego rodzaju wartości są jego argumenty.

Tak więc, na przykład, Perl ma i potrzebuje zarówno operatora dodawania liczb (+), jak i operatora konkatenacji łańcuchów (.): Jak widać powyżej, idealnie jest dodawać łańcuchy ("1" + "2" == "3") lub łączyć liczby (1 . 2 == 12). Podobnie, operatory porównania liczb ==, !=, <, >, <=, >= i <=> porównują wartości liczbowe ich argumentów, podczas gdy operatory porównania łańcuchóweq, ne, lt, gt, le, ge i cmp porównaj je leksykograficznie jako ciągi. Więc 2 < 10, Ale 2 gt 10 (ale "02" lt 10, natomiast "02" == 2). (Pamiętaj, niektóre Inne języki, takie jak JavaScript, starają się dostosować do słabego pisania Perla, podczas gdy również robi przeciążenie operatorów. Często prowadzi to do brzydoty, jak utrata Asocjacja dla +.)

(mucha w maści jest taka, że ze względów historycznych Perl 5 ma kilka przypadków narożnych, takich jak bitowe operatory logiczne, których zachowanie zależy od wewnętrznej reprezentacji ich argumentów. Są one ogólnie uważane za irytującą wadę projektową, ponieważ wewnętrzna reprezentacja może się zmienić z zaskakujących powodów, a więc przewidywanie tego, co operatorzy robią w danej sytuacji, może być trudne.)

Wszystko, co powiedział, można argumentuj, że Perl ma silne typy; po prostu nie są to typy, których możesz się spodziewać. W szczególności, oprócz omawianego powyżej typu" scalar", Perl ma również dwa typy strukturyzowane:" array "i"hash". Są to Bardzo różne od skalarów, do tego stopnia, że zmienne Perla mają różne sigile wskazujące ich typ ($ dla skalarów, @ dla tablic, % dla hashów)1. Istnieją reguły przymusu między tymi typami, tak więc możesz zapisać np. %foo = @bar, ale wiele z nich jest dość stratnych: na przykład $foo = @barprzypisuje Długość tablicy @bar do $foo, a nie jej zawartość. (Istnieje również kilka innych dziwnych typów, takich jak typeglobs i uchwyty We / Wy, które często nie są widoczne.)

W 1995 r., w związku z tym, że w 1998 r., w wyniku reformy administracyjnej, w 1999 r., w 1999 r., w 1999 r., w 1999 r., w 1999 r., w 1999 r., w 1999 r., w 1999 r., w 1999 r., w 1999 r., w 1999 r., w 1999 r.]} operator). Możliwe jest używanie referencji jako zwykłych skalarów, ale ich wartości łańcuchowe/liczbowe nie są szczególnie użyteczne i zwykle tracą swoją specjalną referencję, jeśli zmodyfikujesz je za pomocą normalnych operacji skalarnych. Również Dowolna zmienna Perla2 może być blessed do klasy, zamieniając ją w obiekt tej klasy; system klasy oo w Perlu jest nieco ortogonalny do opisanego powyżej systemu typu prymitywnego (lub typelessness), chociaż jest również "słaby" w sensie podążając za paradygmatem typowania kaczki . Ogólna opinia jest taka, że jeśli sprawdzasz klasę obiektu w Perlu, robisz coś złego.

1 W rzeczywistości sigil oznacza typ wywołanej wartości, tak że np. pierwszy Skalar w tablicy @foo jest oznaczony $foo[0]. Zobacz perlfaq4 po więcej szczegółów.

2 obiekty w Perlu są (normalnie) dostępne poprzez odniesienia do nich, ale co tak naprawdę gets blessed jest zmienną (prawdopodobnie anonimową), do której odnosi się odniesienie. Jednak błogosławieństwo jest rzeczywiście własnością zmiennej , a nie jej wartości, więc np. przypisanie rzeczywistej błogosławionej zmiennej do innej daje płytką, niezabezpieczoną kopię tej zmiennej. Zobacz perlobj po więcej szczegółów.

 63
Author: Ilmari Karonen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-04 05:37:11

Oprócz tego, co powiedział Eric, rozważ następujący kod C:

void f(void* x);

f(42);
f("hello");

W przeciwieństwie do języków takich jak Python, C#, Java czy cokolwiek innego, powyższe jest słabo wpisane, ponieważ tracimy informacje o typie. Eric słusznie zauważył, że w C# możemy obejść kompilator przez casting, skutecznie mówiąc mu "wiem więcej o typie tej zmiennej niż ty".

Ale nawet wtedy, runtime nadal będzie sprawdzać Typ! Jeśli cast jest nieprawidłowy, runtime system będzie złap go i rzuć wyjątek.

Przy kasowaniu typu, tak się nie dzieje – informacja typu jest wyrzucana. Rzut do void* W C robi dokładnie to. Pod tym względem powyższe zasadniczo różni się od deklaracji metody C#, takiej jak void f(Object x).

(technicznie rzecz biorąc, C# pozwala również na kasowanie typu za pomocą niebezpiecznego kodu lub)

to {[7] } jest tak słabo napisane, jak tylko się da. Wszystko inne jest tylko kwestią statycznego vs. dynamicznego sprawdzania typu, czyli czasu Gdy typ jest sprawdzany.

 19
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-29 23:12:38

Doskonały przykład pochodzi z artykułu Wikipedii o mocnym typowaniu :

Ogólnie silne typowanie oznacza, że język programowania nakłada poważne ograniczenia na dozwolone mieszanie.

Słabe Typowanie

a = 2
b = "2"

concatenate(a, b) # returns "22"
add(a, b) # returns 4

Mocne Typowanie

a = 2
b = "2"

concatenate(a, b) # Type Error
add(a, b) # Type Error
concatenate(str(a), b) #Returns "22"
add(a, int(b)) # Returns 4

Zauważ, że słaby język pisania może mieszać różne typy bez błędów. Silny język typu wymaga, aby typy wejściowe były typami oczekiwanymi. W mocnym język typów Typ może być konwertowany (str(a) Konwertuje liczbę całkowitą na ciąg znaków) lub cast (int(b)).

To wszystko zależy od interpretacji typowania.
 14
Author: SaulBack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-04 00:44:53

Chciałbym przyczynić się do dyskusji własnymi badaniami na ten temat, ponieważ inni komentują i przyczyniają się do tego, że czytam ich odpowiedzi i podążam za ich referencjami i znalazłem interesujące informacje. Jak sugerowano, jest prawdopodobne, że większość z nich byłaby lepiej omówiona na forum programistów, ponieważ wydaje się być bardziej teoretyczna niż praktyczna.

Z teoretycznego punktu widzenia, myślę, że artykuł Luca Cardelli i Peter Wegner nazwane na Zrozumienie typów, abstrakcji danych i polimorfizmu ma jeden z najlepszych argumentów, jakie czytałem.

Typ może być postrzegany jako zestaw ubrań (lub zbroi), które chroni podstawową nietypowaną reprezentację przed arbitralnym lub niezamierzone użycie. Zapewnia osłonę ochronną, która ukrywa reprezentacji i ogranicza sposób interakcji obiektów z innymi przedmiotami. W systemie nieprzepisanym nieprzepisane obiekty są nagie w tym podstawowa reprezentacja jest eksponowana dla wszystkich. Naruszenie systemu typu polega na usunięciu zestawu ochronnego odzież i działa bezpośrednio na nagiej reprezentacji.

To stwierdzenie wydaje się sugerować, że słabe pisanie pozwoli nam uzyskać dostęp do wewnętrznej struktury typu i manipulować nim tak ,jakby to było coś innego (inny typ). Być może, co moglibyśmy zrobić z niebezpiecznym kodem (wspomnianym przez Erica) lub z wykasowanymi wskaźnikami typu c wspomnianymi przez Konrada.

The artykuł kontynuowany...

Języki, w których wszystkie wyrażenia są zgodne z typem nazywa się języki silnie typowane. Jeśli język jest silnie wpisany jego kompilator może zagwarantować, że akceptowane przez niego programy będą wykonywane bez typu błędy. Ogólnie rzecz biorąc, powinniśmy dążyć do silnego typowania i przyjąć statyczne pisanie w miarę możliwości. Zauważ, że każdy statycznie wpisany język jest silnie pisany, ale konwersja niekoniecznie jest prawdziwa.

Jako takie, silne pisanie oznacza brak błędów typu, mogę tylko założyć, że słabe pisanie oznacza przeciwnie: prawdopodobną obecność błędów typu. W czasie wykonywania czy kompilacji? Wydaje się nieistotne.

Zabawna rzecz, zgodnie z tą definicją, język z silnymi przymusami typu, takimi jak Perl, byłby uważany za mocno wpisany, ponieważ system nie zawodzi, ale radzi sobie z typami, zmuszając je do odpowiednich i dobrze zdefiniowanych ekwiwalencji.

Z drugiej strony, czy mógłbym powiedzieć niż dodatek ClassCastException i ArrayStoreException (w Javie) oraz InvalidCastException, ArrayTypeMismatchException (w C#) wskazywałby poziom słabego pisania, przynajmniej w czasie kompilacji? Odpowiedź Erica chyba się z tym zgadza.

W drugim artykule o nazwieProgramowanie typowe podanym w jednym z odniesień podanych w jednej z odpowiedzi na to pytanie, Luca Cardelli zagłębia się w koncepcję łamania typów:

Większość języków programowania systemowego dopuszcza dowolne łamanie typów, niektóre niektóre tylko w ograniczonych częściach programu. Operacje związane z naruszeniem typu nazywa się unsound. Typ naruszenia dzielą się na kilka klas [wśród których możemy wymienić]:

Basic-value coercions: są to konwersje między liczbami całkowitymi, logicznymi, znakami, zestawami itp. Nie ma potrzeby naruszania typu tutaj, ponieważ wbudowane interfejsy mogą być dostarczane do przeprowadzenia przymus w sposób typowo dźwiękowy.

Jako takie, Typ przymusy, takie jak te dostarczane przez operatorów, można uznać za naruszenia typów, ale jeśli nie naruszają one spójności systemu typów, możemy powiedzieć, że nie prowadzą do słabego systemu typów.

Na tej podstawie ani Python, Perl, Java czy C# nie są słabo pisane.

Cardelli wspomina o dwóch typach, które bardzo dobrze uważam za przypadki naprawdę słabego typowania:

Arytmetyka adresów. W razie potrzeby powinien być wbudowany interfejs (unsound) , zapewnienie odpowiednich operacji na adresach i konwersje typu. Różne sytuacje wiążą się ze wskazówkami do sterty (bardzo niebezpieczne przy przenoszeniu kolektorów), wskaźniki do stos, wskaźniki do obszarów statycznych i wskaźniki do innych adresów miejsca. Czasami indeksowanie tablicy może zastąpić arytmetykę adresów. mapowanie pamięci. polega to na patrzeniu na obszar pamięci jako nieustrukturyzowaną tablicę, chociaż zawiera ona ustrukturyzowane dane. To jest typowe dla alokatorów pamięci i kolekcjonerów.

Tego rodzaju rzeczy możliwe w językach takich jak C (wspomniany przez Konrada) lub poprzez niebezpieczny kod w. Net (wspomniany przez Erica) naprawdę oznaczałyby słabe typowanie.

Uważam, że najlepsza jak dotąd odpowiedź należy do Erica, ponieważ definicja tych pojęć jest bardzo teoretyczna, a jeśli chodzi o konkretny język, interpretacje wszystkich tych pojęć mogą prowadzić do różnych dyskusyjnych wniosków.

 4
Author: Edwin Dalorzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-30 18:44:46

Słabe typowanie rzeczywiście oznacza, że wysoki procent typów może być pośrednio wymuszony, próbując odgadnąć, co zamierzał koder.

Silne typowanie oznacza, że typy nie są przymuszane, lub przynajmniej mniej przymuszane.

Typowanie statyczne oznacza, że typy zmiennych są określane podczas kompilacji.

Wiele osób ostatnio pomyliło "ewidentnie wpisane "z"mocno wpisane". "Ewidentnie wpisane" oznacza, że jawnie deklarujesz typy zmiennych.

Python jest w większości mocno wpisywane, chociaż można użyć prawie wszystkiego w kontekście logicznym, a wartości logiczne mogą być używane w kontekście integer, a można użyć liczby całkowitej w kontekście float. Nie jest oczywiście pisany, ponieważ nie musisz deklarować swoich typów(z wyjątkiem Cythona, który nie jest do końca Pythonem, aczkolwiek interesujący). Nie jest również zapisywany statycznie.

C i C++ są oczywiście wpisane, statycznie wpisane i nieco mocno wpisane, ponieważ deklarujesz swoje typy, typy są określone w czasie kompilacji można mieszać liczby całkowite i wskaźniki lub liczby całkowite i podwajać, a nawet rzucać wskaźnik do jednego typu do wskaźnika do innego typu.

Haskell jest ciekawym przykładem, ponieważ nie jest ewidentnie pisany, ale jest również statycznie i mocno pisany.

 4
Author: user1277476,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-18 16:53:49

Mocne słabe typowanie Nie dotyczy tylko kontinuum na temat tego, jak wiele lub jak mało wartości jest wymuszanych automatycznie przez język dla jednego typu danych do drugiego, ale jak silnie lub słabo wpisuje się rzeczywiste wartości {41]}. W Pythonie i Javie, a przede wszystkim w C#, wartości mają swoje typy ustawione w kamieniu. W Perlu nie tyle - w rzeczywistości jest tylko kilka różnych typów wartości do przechowywania w zmiennej.

Otwórzmy sprawy jeden przez jeden.


Python

W przykładzie Pythona 1 + "1", + operator wywołuje __add__ dla typu int dając mu łańcuch "1" jako argument - jednak skutkuje to NotImplemented:

>>> (1).__add__('1')
NotImplemented

Następnie interpreter próbuje __radd__ str:

>>> '1'.__radd__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'

Gdy się nie powiedzie, operator + nie powiedzie się 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 swoich argumentów automatycznie do tego samego typu, jest wskaźnikiem do tego, że Python nie jest najbardziej słabo typowanym językiem w kontinuum.

Z drugiej strony, w Pythonie 'a' * 5 jest zaimplementowany:

>>> 'a' * 5
'aaaaa'

To znaczy

>>> 'a'.__mul__(5)
'aaaaa'

Fakt, że operacja jest inna wymaga pewnego silnego typowania - jednak przeciwieństwo * wymuszanie wartości na liczbach przed mnożeniem nadal nie musi powodować słabych wartości wpisana na maszynie.


Java

Przykład Javy, String result = "1" + 1; działa tylko dlatego, że dla wygody operator + jest przeciążony dla ciągów. Operator Java + zastępuje sekwencję tworząc 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 typowania, bez rzeczywistego przymusu - StringBuilder ma metodę append(Object) to jest specjalnie używane tutaj. Dokumentacja mówi co następuje:

Dodaje reprezentacja łańcuchowa argumentu Object.

Ogólny efekt jest dokładnie taki, jak gdyby argument został przekonwertowany na string przy pomocy metody String.valueOf(Object), A znaki ten ciąg znaków został następnie dołączony do tej sekwencji znaków.

Gdzie String.valueOf wtedy

Zwraca reprezentację łańcuchową argumentu obiektu. [Zwraca] jeśli argumentem jest null, to łańcuch równy "null"; w przeciwnym razie wartość obj.toString() wynosi zwrócony.

Jest to więc przypadek absolutnie żadnego przymusu ze strony języka-delegowania wszelkich trosk samym przedmiotom.

C#

Zgodnie z odpowiedzią Jona Skeeta tutaj , operator + nie jest nawet przeciążony dla klasy string - podobnie jak Java, 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 tablice asocjacyjne skalarów, znane jako"hasze". Skalar jest pojedynczym łańcuchem znaków (o dowolnym rozmiarze, ograniczonym tylko przez dostępną pamięć), liczbą lub odniesieniem do czegoś (co zostanie omówione w perlref). Tablice zwykłe są uporządkowanymi listami skalarów indeksowanych przez liczbę, zaczynając od 0. Hashe są nieuporządkowanymi zbiorami wartości skalarnych indeksowanych przez powiązany z nimi klucz Łańcuchowy.

Perl jednak nie ma oddzielny typ danych dla numbers, booleans, strings, nulls, undefineds, referencji do innych obiektów itp. - ma tylko jeden typ dla tych wszystkich, Typ skalarny; 0 jest wartością skalarną tak samo jak "0". Zmienna skalarna , która została ustawiona jako ciąg znaków, może naprawdę zmienić się w liczbę i od tego momentu zachowuje się inaczej niż" tylko ciąg", , jeśli jest dostępna w kontekście numerycznym . Skalar może pomieścić wszystko w Perlu, jest tak samo obiektem, jak istnieje w systemie. mając na uwadze, że w Python nazwy odnoszą się tylko do obiektów, w Perlu wartości skalarne w nazwach są zmiennymi obiektami. Co więcej, system typów obiektowych jest przyklejony do tego: w Perlu są tylko 3 typy danych-Skalary, listy i skróty. Obiekt zdefiniowany przez Użytkownika w Perlu jest referencją (czyli wskaźnikiem do dowolnego z 3 poprzednich) blessed do pakietu - możesz pobrać dowolną taką wartość i pobłogosławić ją do dowolnej klasy w dowolnym momencie.

Perl pozwala nawet na zmianę klas wartości przy kaprysie - nie jest to możliwe w Pythonie gdzie aby utworzyć wartość jakiejś klasy trzeba jawnie skonstruować wartość należącą do tej klasy z object.__new__ lub podobną. W Pythonie tak naprawdę nie można zmienić istoty obiektu po jego utworzeniu, w Perlu można zrobić wiele wszystkiego:

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że być zmieniana za pomocą dowolnego odniesienia w locie. W rzeczywistości, jeśli nie

my $another = $val;

\$another nie ma klasy tożsamość, mimo że nadal będzie to błogosławione odniesienie.


TL;DR

Jest o wiele więcej o słabym pisaniu do Perla niż o automatycznych przymusach i chodzi bardziej o to, że same typy wartości nie są ustawiane w kamień, w przeciwieństwie do Pythona, który jest dynamicznie, ale bardzo silnie wpisanym językiem. To, że python daje TypeError na {[7] } jest wskazaniem, że język jest silnie pisany, mimo że przeciwnie, robi coś użytecznego, jak w Javie lub C# nie wyklucza, że są to języki silnie typowane.

 3
Author: Antti Haapala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:21

Lubię @Eric Lippert ' s answer, ale aby odpowiedzieć na pytanie - silnie wpisane języki zazwyczaj mają wyraźną wiedzę na temat typów zmiennych w każdym punkcie programu. Języki słabo typowane Nie, więc mogą próbować wykonać operację, która może nie być możliwa dla danego typu. Myślę, że najłatwiej to zobaczyć w funkcji. C++:

void func(string a) {...}

Zmienna a jest znana jako typ string i każda niezgodna operacja zostanie przechwycona w czas kompilacji.

Python:

def func(a)
  ...

Zmienną a może być cokolwiek i możemy mieć kod, który wywoła nieprawidłową metodę, która zostanie przechwycona tylko w czasie wykonywania.

 0
Author: Lubo Antonov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:15

Jak wielu innych wyraziło, całe pojęcie "mocne" vs "słabe" typowanie jest problematyczne.

Jako archetyp, Smalltalk jest bardzo mocno wpisywany - to Zawsze wywoła wyjątek, jeśli operacja między dwoma obiektami jest niezgodna. Jednak podejrzewam, że niewielu na tej liście nazwałoby Smalltalk językiem silnie wpisywanym, ponieważ jest on pisany dynamicznie.

Uważam, że pojęcie" statyczne "kontra" dynamiczne "pisanie jest bardziej użyteczne niż "mocne" kontra " słabe."A statycznie typowany język ma wszystkie typy ustalone w czasie kompilacji, a programista musi jawnie zadeklarować, czy jest inaczej.

Kontrast z językiem dynamicznie wpisywanym, w którym wpisywanie jest wykonywane w czasie wykonywania. Jest to zwykle wymóg dla języków polimorficznych, więc o tym, czy operacja między dwoma obiektami jest legalna, nie musi decydować programista z góry.

W polimorficznych, dynamicznie typowanych językach (takich jak Smalltalk i Ruby), bardziej użyteczne jest myślenie o "typie" jako " zgodności z protokołem."Jeśli obiekt przestrzega protokołu tak samo jak inny obiekt-nawet jeśli oba obiekty nie dzielą żadnego dziedziczenia, mieszania lub innego voodoo - są one uważane za ten sam "typ" przez system run-time. Bardziej poprawnie, obiekt w takich systemach jest autonomiczny i może decydować, czy sensowne jest odpowiadanie na konkretny komunikat odnoszący się do konkretnego argumentu.

Chcesz obiekt, który może mieć jakieś znaczenie odpowiedź na wiadomość " + " z argumentem obiektu opisującym Kolor Niebieski? Można to zrobić w językach dynamicznie typowanych, ale jest to ból w językach statycznie typowanych.

 0
Author: Jan Steinman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-04 18:09:58