В поисках разъяснений о явных противоречиях в отношении слабо типизированных языков

164

Я думаю, что я понимаю сильную типизацию, но каждый раз, когда я ищу примеры для слабого набора текста, я нахожу примеры языков программирования, которые просто автоматически конвертировать типы.

Например, в этой статье с именем Typing: Strong vs. Weak, Static vs. Dynamic говорит, что Python строго типизирован, потому что вы получаете исключение, если вы попытаетесь:

Python

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

Однако такая вещь возможна в Java и в С#, и мы не считаем их слабо типизированными для этого.

Java

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

С#

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

В этой другой статье, названной Язык слабого типа, автор говорит, что Perl слабо типизирован просто потому, что я могу объединить строку в число и наоборот без явного преобразования.

Perl

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

Итак, тот же пример делает Perl слабо типизированным, но не Java и С#?.

Да, это путает Изображение 647

Авторы, по-видимому, подразумевают, что язык, который предотвращает применение определенных операций над значениями разных типов, строго типизирован, а наоборот означает слабо типизированный.

Поэтому в какой-то момент я почувствовал, что мне кажется, что если язык обеспечивает много автоматических преобразований или принуждения между типами (как perl), в конечном итоге может считаться слабо типизированным, тогда как другие языки, которые предоставляют только несколько преобразований, могут в конечном итоге считается строго типизированным.

Я склонен полагать, однако, что я должен ошибаться в этом вопросе, я просто не знаю, почему и как объяснить это.

Итак, мои вопросы:

  • Что это значит для того, чтобы язык был действительно слабо типизированным?
  • Не могли бы вы упомянуть о хороших примерах слабого набора текста, которые не связаны с автоматическим преобразованием/автоматическим принуждением, выполняемым языком?
  • Может ли язык быть слабо типизированным и строго типизированным одновременно?
  • 0
    Это сбивает меня с толку! Насколько я понимаю (или думаю, что понимаю), слабо типизированный язык называется «безопасным типом» и имеет неявное преобразование типов.
  • 8
    Сильная или слабая типизация - все о преобразовании типов (о чем еще это может быть?). Если вам нужен пример «очень» слабого языка, посмотрите это: destroyallsoftware.com/talks/wat .
Показать ещё 10 комментариев
Теги:

9 ответов

191
Лучший ответ

UPDATE: Этот вопрос был предметом моего блога 15 октября 2012 года. Спасибо за отличный вопрос!


Что это означает, что язык "слабо типизирован"?

Это означает, что "этот язык использует систему типов, которую я считаю неприятной". Напротив, "сильно типизированный" язык - это язык с системой типов, которую я нахожу приятным.

Термины по существу бессмысленны, и вы должны избегать их. Wikipedia перечисляет одиннадцать разных значений для "строго типизированных", некоторые из которых противоречивы. Это указывает на то, что вероятность создания путаницы высока в любом разговоре, включающем термин "строго типизированный" или "слабо типизированный".

Все, что вы можете сказать с определенной уверенностью, состоит в том, что обсуждаемый язык с "строго типизированным" имеет некоторое дополнительное ограничение в системе типов во время выполнения или времени компиляции, что отсутствует в "слабо типизированном" языке. Какое это ограничение может быть невозможно определить без дальнейшего контекста.

Вместо того, чтобы использовать "строго типизированные" и "слабо типизированные", вы должны подробно описать, какой тип безопасности вы имеете в виду. Например, С# - это статически типизированный язык и безопасный язык типа и язык, безопасный для памяти, по большей части. С# позволяет исключить все три формы "сильной" типизации. Оператор литья нарушает статическую типизацию; он говорит компилятору "Я знаю больше о типе времени выполнения этого выражения, чем вы". Если разработчик ошибается, то среда выполнения генерирует исключение для защиты безопасности типов. Если разработчик хочет нарушить безопасность типа или безопасность памяти, они могут сделать это, отключив систему безопасности типа, сделав "небезопасный" блок. В небезопасном блоке вы можете использовать волшебство указателя для обработки int как float (нарушение безопасности типа) или для записи в память, которой вы не владеете. (Нарушение безопасности памяти.)

С# накладывает ограничения типов, которые проверяются как во время компиляции, так и во время выполнения, тем самым делая его "строго типизированным" языком по сравнению с языками, которые выполняют меньше времени проверки компиляции или меньше проверяют время выполнения. С# также позволяет вам в особых обстоятельствах выполнять ограничения по этим ограничениям, делая его "слабо типизированным" языком по сравнению с языками, которые не позволяют выполнять такой конечный запуск.

Что это на самом деле? Невозможно сказать; это зависит от точки зрения докладчика и их отношения к различным языковым особенностям.

  • 1
    Но, Эрик, это подразумевает, что определение основано на вкусе и личных мнениях, а не на теории типов. Является ли «слабо типизированный» тогда просто теоретическим понятием без каких-либо существующих реализаций?
  • 14
    @edalorzo: Это основано на вкусе и личных мнениях относительно (1), какие аспекты теории типов актуальны и какие не имеют отношения, и (2) требуется ли язык для обеспечения или просто поощрения ограничений типа. Как я указывал, можно разумно сказать, что C # строго типизирован, потому что он допускает и поощряет статическую типизацию, и можно так же разумно сказать, что он слабо типизирован, потому что позволяет нарушать безопасность типов.
Показать ещё 9 комментариев
65

Как отмечали другие, термины "сильно типизированные" и "слабо типизированные" имеют так много разных значений, что нет единого ответа на ваш вопрос. Однако, поскольку вы конкретно упомянули Perl в своем вопросе, позвольте мне попытаться объяснить, в каком смысле Perl слабо типизирован.

Дело в том, что в Perl нет такой вещи, как "целочисленная переменная", "плавающая переменная", "строковая переменная" или "логическая переменная". Фактически, насколько пользователь может (обычно) сказать, нет даже целочисленных, плавающих, строковых или логических значений: все, что у вас есть, - это "скаляры", которые одновременно являются всеми этими вещами. Таким образом, вы можете, например, написать:

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

Конечно, как вы правильно заметили, все это можно рассматривать как просто принуждение типа. Но дело в том, что в Perl типы всегда принуждаются. На самом деле пользователю достаточно сложно рассказать, какой может быть внутренний "тип" переменной: в строке 2 в моем примере выше, спрашивает, является ли значение $bar строкой "9" или числом 9 в значительной степени бессмысленна, поскольку, насколько это касается Perl, это одно и то же. В самом деле, даже для скаляра Perl внутренне может быть как строка, так и числовое значение одновременно, например, случай для $foo после строки 2 выше.

Оборотная сторона всего этого заключается в том, что, поскольку переменные Perl являются нетипизированными (или, вернее, не выставляют свой внутренний тип пользователю), операторы не могут быть перегружены, чтобы делать разные вещи для разных типов аргументов; вы не можете просто сказать: "этот оператор будет делать X для чисел и Y для строк", потому что оператор не может (не укажет), какие значения имеют значения его аргументов.

Таким образом, например, Perl имеет и требует как оператор с числовым добавлением (+), так и оператор конкатенации строк (.): как вы видели выше, отлично добавлять строки ("1" + "2" == "3") или для объединения чисел (1 . 2 == 12). Точно так же операторы числового сравнения ==, !=, <, >, <=, >= и <=> сравнивают числовые значения своих аргументов, в то время как операторы сравнения строк eq, ne, lt, gt, le, ge и cmp сравнивают их лексикографически как строки. Итак, 2 < 10, но 2 gt 10 (но "02" lt 10, а "02" == 2). (Имейте в виду, что некоторые другие языки, такие как JavaScript, стараются приспособить Perl-подобную слабую типизацию, а также перегрузку оператора. Это часто приводит к уродству, например, к потере ассоциативности для +.)

(Муха в мазе здесь состоит в том, что по историческим причинам Perl 5 имеет несколько угловых случаев, таких как побитовые логические операторы, поведение которых зависит от внутреннего представления их аргументов. Обычно это считается раздражающим дизайном поскольку внутреннее представление может измениться по удивительным причинам, и поэтому предсказание того, что эти операторы делают в данной ситуации, может быть сложным.)

Все, что сказано, можно утверждать, что Perl имеет сильные типы; они просто не такие типы, которые вы могли бы ожидать. В частности, в дополнение к описанному выше "скалярному" типу, Perl также имеет два структурированных типа: "массив" и "хэш". Они очень отличаются от скаляров, вплоть до того, что переменные Perl имеют разные sigils, указывающие их тип ($ для скаляров, @ для массивов, % для хеши) 1. Существуют правила принуждения между этими типами, поэтому вы можете писать, например. %foo = @bar, но многие из них довольно сбиты: например, $foo = @bar присваивает длину массива @bar $foo, а не его содержимое. (Кроме того, есть несколько других странных типов, таких как typeglobs и ручки ввода-вывода, которые вы часто не видите.)

Кроме того, небольшая щель в этом приятном дизайне - это наличие ссылочных типов, которые являются особым видом скаляров (и которые можно отличить от обычных скаляров, используя оператор ref). Можно использовать ссылки как обычные скаляры, но их строковые/числовые значения не особенно полезны, и они, как правило, теряют свою специальную ссылку, если вы изменяете их с помощью обычных скалярных операций. Кроме того, любая переменная Perl 2 может быть bless ed для класса, превращая ее в объект этого класса; система класса OO в Perl несколько ортогональна описанной выше системе примитивного типа (или без нее), хотя она также "слаба" в смысле следования утиной типизации, Общее мнение состоит в том, что если вы обнаружите, что проверяете класс объекта в Perl, вы делаете что-то неправильно.


1Фактически, сигила обозначает тип доступного значения, так что, например, первый скаляр в массиве @foo обозначается $foo[0]. Подробнее см. perlfaq4.

2 Объекты в Perl (обычно) доступны через ссылки на них, но то, что на самом деле получает bless ed, является (возможно, анонимной) переменной, на которую ссылаются. Однако благословение действительно является свойством переменной, а не ее значения, так, например, что присвоение фактической благословенной переменной другому просто дает вам мелкую, беспрепятственную копию. Подробнее см. perlobj.

  • 11
    +1 За отличную лекцию по Perl. Хотел бы я, чтобы тебя голосовали не раз. Ваше объяснение слабой типизации Perl - лучшее, что я читал.
19

В дополнение к тому, что сказал Эрик, рассмотрим следующий код C:

void f(void* x);

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

В отличие от языков, таких как Python, С#, Java или еще чего-то, приведенное выше слабо типизировано, потому что мы теряем информацию о типе. Эрик правильно указал, что в С# мы можем обойти компилятор путем кастинга, эффективно говоря ему "Я знаю больше о типе этой переменной, чем вы".

Но даже тогда среда выполнения все равно проверит тип! Если приведение недействительно, система времени выполнения поймает его и выдаст исключение.

С стиранием типа этого не происходит - информация о типе отбрасывается. Приведение к void* в C делает именно это. В этом отношении вышеизложенное принципиально отличается от декларации метода С#, например void f(Object x).

(Технически, С# также позволяет стирать стихи через небезопасный код или сортировать.)

Это так же слабо типизировано, как и получается. Все остальное - это просто вопрос статической или динамической проверки типа, то есть времени, когда проверяется тип.

  • 1
    +1 Хороший вопрос, вы теперь заставили меня думать о стирании типов как о функции, которая также может подразумевать «слабую типизацию». В Java также есть стирание типов, и во время выполнения система типов позволит вам нарушать ограничения, которые компилятор никогда не утвердит. Пример на C отлично иллюстрирует это.
  • 1
    Согласитесь, есть слои с луком или адом. Это кажется более существенным определением слабости типа.
Показать ещё 7 комментариев
14

Прекрасный пример из статьи в Википедии "Сильная печать" :

В целом сильная типизация подразумевает, что язык программирования налагает серьезные ограничения на перемешивание, которое разрешено иметь.

Слабый ввод

a = 2
b = "2"

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

Сильная печать

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

Обратите внимание, что слабый язык ввода может смешивать разные типы без ошибок. Сильный тип языка требует, чтобы типы ввода были ожидаемыми типами. На сильном типе можно преобразовать тип (str(a) преобразует целое число в строку) или cast (int(b)).

Все это зависит от интерпретации ввода.

  • 2
    Но это приводит к противоречивым примерам, приведенным в вопросе. Язык со строгой типизацией может включать в себя неявное принуждение, которое означает, что любой (или оба) из двух ваших примеров «Ошибка типа» автоматически преобразуются в релевантные из вторых двух примеров, но, как правило, этот язык остается строго типизированным.
  • 3
    Правда. Я думаю, вы могли бы сказать, что есть разные степени строгой типизации и слабой типизации. Неявное преобразование может означать, что язык менее строго типизирован, чем язык, который не выполняет неявное преобразование.
4

Слабая типизация действительно означает, что высокий процент типов может быть неявно принудительным, пытаясь угадать, что предполагал кодер.

Сильная типизация означает, что типы не принуждаются или, по крайней мере, меньше принуждаются.

Статическая типизация означает, что типы ваших переменных определяются во время компиляции.

В последнее время многие люди путают "явно типизированные" с "строго типизированными". "Manifestly typed" означает, что вы явно объявляете типы переменных.

Python в основном строго типизирован, хотя вы можете использовать почти все в булевом контексте, а логические значения можно использовать в целочисленном контексте, и вы можете использовать целое число в контексте с плавающей точкой. Это явно не типизировано, потому что вам не нужно объявлять ваши типы (за исключением Cython, который не является полностью python, хотя и интересным). Он также не статически типизирован.

C и С++ явно типизированы, статически типизированы и несколько сильно набраны, поскольку вы объявляете свои типы, типы определяются во время компиляции, и вы можете смешивать целые числа и указатели, целые числа и двойные числа или даже указывать указатель на один тип в указатель на другой тип.

Haskell - интересный пример, потому что он явно не типизирован, но также статически и строго типизирован.

  • 0
    +1 Потому что мне нравится придуманный термин «явно типизированный», который классифицирует языки, такие как Java и C #, где вы должны явно объявить типы и отличить их от других языков статического типа, таких как Haskell и Scala, где вывод типов играет важную роль, и это обычно как вы говорите, сбивает с толку людей и заставляет их верить, что эти языки динамически типизированы.
4

Я хотел бы внести свой вклад в дискуссию с моими собственными исследованиями по этому вопросу, поскольку другие комментируют и вносят свой вклад. Я читал их ответы и следил за их рекомендациями, и я нашел интересную информацию. Как было предложено, вероятно, что большая часть этого вопроса будет лучше обсуждена на форуме программистов, поскольку она представляется более теоретической, чем практической.

С теоретической точки зрения, я думаю, статья Луки Карделли и Питера Вегнера, названная "О понятиях понимания, абстракции данных и полиморфизмах" , имеет один из лучшие аргументы, которые я прочитал.

Тип можно рассматривать как набор одежды (или костюм доспехов), который защищает базовое нетипизированное представление от произвольного или непреднамеренное использование. Он обеспечивает защитное покрытие, которое скрывает базовое представление и ограничивает способ взаимодействия объектов с другими объектами. В нетипизированной системе нетипизированные объекты голые в том, что основное представление открыто для всех. Нарушение системы типов предполагает удаление защитного набора одежду и работу непосредственно на обнаженном представлении.

Это утверждение, по-видимому, предполагает, что слабое типирование позволит нам получить доступ к внутренней структуре типа и манипулировать им, как если бы оно было чем-то другим (другим типом). Возможно, что мы можем сделать с небезопасным кодом (упомянутым Эриком) или с c-стираемыми указателями, упомянутыми Конрадом.

Статья продолжается...

Языки, в которых все выражения согласованы по типу, называются строго типизированные языки. Если язык строго типизирован, его компилятор может гарантировать, что программы, которые он принимает, будут выполняться без типа ошибки. В общем, мы должны стремиться к сильному набору текста и принимать статическая типизация, когда это возможно. Обратите внимание, что каждый статически типизированный язык строго типизирован, но обратное не обязательно верно.

Таким образом, сильная типизация означает отсутствие ошибок типа, я могу только предположить, что слабая типизация означает обратное: вероятное наличие ошибок типа. Во время выполнения или времени компиляции? Здесь неважно.

Смешная вещь, согласно этому определению, язык с сильными типами принуждения, такой как Perl, будет считаться строго типизированным, потому что система не терпит неудачу, но она имеет дело с типами, принуждая их к соответствующим и четко определенным эквивалентам.

С другой стороны, могу ли я сказать, что учетные данные ClassCastException и ArrayStoreException (в Java) и InvalidCastException, ArrayTypeMismatchException (в С#) означают уровень слабо типизации, по крайней мере, при компиляции время? Ответ Эрика, похоже, согласен с этим.

Во второй статье, названной Typeful Programming, приведенной в одной из ссылок, приведенной в одном из ответов в этом вопросе, Лука Карделли вникает в понятие нарушения типа:

Большинство языков системного программирования допускают нарушения произвольного типа, некоторые без разбора, некоторые - только в ограниченных частях программы. Операции, связанные с нарушениями типа, называются несостоятельными. Тип нарушения относятся к нескольким классам [среди которых мы можем упомянуть]:

Усилия с базовыми значениями. Сюда входят преобразования между целыми числами, булевыми символами, символами, наборами и т.д. Нет необходимости в нарушениях типа здесь, поскольку встроенные интерфейсы могут быть предоставлены для выполнения принуждения по типу звука.

Таким образом, типы принуждения, подобные операторам, могут рассматриваться как нарушения типов, но если они не нарушают согласованность системы типов, мы можем сказать, что они не приводят к слабо типизированной системе.

Исходя из этого ни Python, ни Perl, ни Java, ни С# не набраны.

Карделли упоминает две винилы типа, которые я очень хорошо рассматриваю случаи действительно слабого набора текста:

Арифметика адресов. При необходимости должен быть встроенный (необорудованный) интерфейс, обеспечивающий адекватные операции по адресам и тип преобразования. Различные ситуации включают указатели на куча (очень опасная с перемещающимися коллекторами), указатели на стек, указатели на статические области и указатели на другой адрес пространства. Иногда индексирование массива может заменить арифметику адресов. Отображение памяти. Это предполагает просмотр области памяти как неструктурированного массива, хотя он содержит структурированные данные. Это типичные для распределителей памяти и коллекционеров.

Такие вещи, которые возможны на таких языках, как C (упомянутый Конрадом) или через небезопасный код в .Net(упомянутый Эриком), действительно означают слабое типирование.

Я считаю, что лучшим ответом до сих пор является Эрик, потому что определение этих понятий очень теоретично, и когда речь заходит о конкретном языке, интерпретации всех этих понятий могут привести к различным спорным выводам.

3

Сильное <= > слабое типирование - это не только континуум, на сколько или сколько значений автоматически зацикливается на языке для одного типа данных для другого, но насколько сильно или слабо фактические значения. В Python и Java, и в основном в С#, значения имеют свои типы, установленные в камне. В 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 методом String.valueOf(Object), а символы эта строка была добавлена ​​к этой последовательности символов.

Где String.valueOf, затем

Возвращает строковое представление аргумента Object. [Возвращает], если аргумент null, тогда строка равна "null"; в противном случае возвращается значение obj.toString().

Таким образом, это случай абсолютно никакого принуждения языком - делегирование каждой проблемы самим объектам.


С#

В соответствии с Jon Skeet ответ здесь оператор + даже не перегружен для класса string - сродни Java, это просто удобство, созданное компилятор, благодаря как статической, так и сильной типизации.


Perl

Как объясняет perldata,

Perl имеет три встроенных типа данных: скаляры, массивы скаляров и ассоциативные массивы скаляров, известные как "хэши". Скаляр представляет собой одну строку (любого размера, ограниченную только доступной памятью), номер или ссылку на что-то (что будет обсуждаться в perlref). Обычными массивами являются упорядоченные списки скаляров, индексированных по числу, начиная с 0. Хеши - это неупорядоченные коллекции скалярных значений, индексированные их связанным строковым ключом.

Однако у Perl нет отдельного типа данных для чисел, булевых, строк, нулей, undefined s, ссылок на другие объекты и т.д. - у него есть только один тип для всех - скалярный; 0 - скалярное значение, равное "0". Скалярная переменная, которая была установлена ​​как строка, может действительно измениться на число, и оттуда ведут себя иначе, чем "просто строка", если к ней обращаются в числовом контексте. Скаляр может содержать что-либо в Perl, это как объект, который существует в системе. тогда как в Python имена просто ссылаются на объекты, в Perl скалярные значения в именах являются переменными объектами. Кроме того, система объектно-ориентированного типа приклеена поверх этого: всего лишь 3 типа данных в perl-скалярах, списках и хешах. Пользовательский объект в Perl является ссылкой (то есть указателем на любой из трех предыдущих) bless ed для пакета - вы можете взять любое такое значение и благословить его любому классу в любой момент, когда захотите.

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 или С#, не исключает, что они являются строго типизированными языками.

  • 0
    Это полностью запутано. То, что переменные Perl 5 не имеют типов, не имеет никакого отношения к значениям , которые всегда имеют тип.
  • 0
    @JimBalter, да, значение имеет тип в том смысле, что оно является строкой или числом, и оно может вести себя по-разному в некотором контексте в зависимости от того, содержит ли скалярная переменная строку или число; но значение, содержащееся в переменной, может изменить тип, просто получая доступ к переменной, и поскольку само значение находится в переменной, сами значения можно считать изменяемыми между типами.
Показать ещё 3 комментария
0

Как и многие другие, все понятие "сильного" и "слабого" набора текста проблематично.

Как архетип, Smalltalk очень сильно типизирован - он всегда будет создавать исключение, если операция между двумя объектами несовместима. Тем не менее, я подозреваю, что немногие в этом списке будут называть Smalltalk строго типизированным языком, потому что он динамически типизирован.

Я нахожу понятие "статического" и "динамического" ввода более полезным, чем "сильное" и "слабое". Статически типизированный язык имеет все типы, определенные во время компиляции, и программист должен явно объявить, если в противном случае.

Контраст с динамически типизированным языком, где ввод выполняется во время выполнения. Это типично требование для полиморфных языков, так что решения о том, является ли операция между двумя объектами законной, не должны заранее решаться программистом.

В полиморфных, динамически типизированных языках (таких как Smalltalk и Ruby) более полезно думать о "типе" как о "соответствии протоколу". Если объект подчиняется протоколу так же, как и другой объект, даже если оба объекта не имеют общего наследования или микшинов или другого вуду - они считаются одним и тем же "типом" системы времени выполнения. Вернее, объект в таких системах является автономным и может решить, имеет ли смысл отвечать на любое конкретное сообщение, ссылаясь на какой-либо конкретный аргумент.

Хотите объект, который может внести существенный ответ на сообщение "+" с аргументом объекта, который описывает синий цвет? Вы можете сделать это на языках с динамическим вводом, но это боль в статически типизированных языках.

  • 2
    Я думаю, что концепция динамической и статической типизации не обсуждается. Хотя я должен сказать, что я не верю, что полиморфизм в любом случае ограничен в языках статического типа. В конечном счете, система типов проверяет, применима ли данная операция к заданным операндам во время выполнения или во время компиляции. Кроме того, другие формы полиморфизма, такие как параметрические функции и классы, позволяют комбинировать типы в языках статического типа способами, которые вы описали как очень трудные по сравнению с динамически типизированными, еще более приятными, если предоставляется вывод типов.
0

Мне нравится @Eric Lippert answer, но для решения вопроса - строго типизированные языки обычно имеют явное знание типов переменных в каждой точке программы. В слабо типизированных языках нет, поэтому они могут попытаться выполнить операцию, которая может быть недоступна для определенного типа. Он считает, что самый простой способ увидеть это в функции. С++:

void func(string a) {...}

Известно, что переменная a имеет строку типа и любая несовместимая операция будет обнаружена во время компиляции.

Python:

def func(a)
  ...

Переменная a может быть любой, и у нас может быть код, который вызывает недопустимый метод, который будет попадать только во время выполнения.

  • 12
    Я думаю, вы можете путать динамическую типизацию с статической типизацией с сильной типизацией и слабой типизацией. В обеих версиях вашего кода системы типов времени выполнения прекрасно знают, что a является строкой. Просто в первом случае компилятор может вам сказать, во втором - нет. Но это не делает ни один из этих языков слабо типизированным.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню