В чем разница между языком со строгой типизацией и языком со статической типизацией?


441

Кроме того, одно подразумевает другое?


8
Обратите внимание, что почти дубликаты на stackoverflow.com/questions/2351190/…
Норман Рэмси

4
Tcl строго типизирован. У него есть только строка: P
nawfal

21
@nawfal Нет, это строго напечатано;)
geekonaut

Ответы:


543

В чем разница между языком со строгой типизацией и языком со статической типизацией?

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

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

Статический против динамического

Противоположностью статически типизированного является «динамически типизированный», что означает, что

  1. Значения, используемые во время выполнения, классифицируются по типам.
  2. Существуют ограничения на использование таких значений.
  3. Когда эти ограничения нарушаются, нарушение сообщается как ошибка (динамического) типа.

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

Сильный против слабого

Противоположностью «строго типизированного» является «слабо типизированный», что означает, что вы можете работать с системой типов. C общеизвестно слабо типизирован, потому что любой тип указателя можно преобразовать в любой другой тип указателя просто путем приведения. Паскаль должен был быть строго типизирован, но упущение в дизайне (записи вариантов без тегов) привело к появлению лазейки в системе типов, так что технически она слабо типизирована. Примеры действительно строго типизированных языков включают CLU, Standard ML и Haskell. Стандарт ML фактически подвергся нескольким ревизиям для удаления лазеек в системе типов, которые были обнаружены после широкого распространения языка.

Что на самом деле здесь происходит?

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

  • Любители часто отождествляют их со «статичным» и «динамическим».

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

  • Профессионалы не могут договориться о том, что именно означают термины.

  • В целом вы вряд ли будете информировать или просвещать свою аудиторию.

Печальная правда в том, что когда речь идет о системах типов, «сильный» и «слабый» не имеют общепризнанного технического значения. Если вы хотите обсудить относительную силу систем типов, лучше обсудить, какие именно гарантии есть, а какие нет. Например, хороший вопрос, который следует задать, заключается в следующем: «гарантированно ли каждое значение данного типа (или класса) было создано путем вызова одного из конструкторов этого типа?» В С ответ нет. В CLU, F # и Haskell это да. Для C ++ я не уверен - я хотел бы знать.

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

Одно подразумевает другое?

На педантичном уровне нет, потому что слово «сильный» ничего не значит. Но на практике люди почти всегда делают одно из двух:

  • Они (неправильно) используют «сильный» и «слабый» для обозначения «статический» и «динамический», и в этом случае они (неправильно) используют «строго типизированный» и «статически типизированный» взаимозаменяемо.

  • Они используют «сильный» и «слабый» для сравнения свойств систем статического типа. Очень редко можно услышать, как кто-то говорит о «сильной» или «слабой» динамической системе типов. За исключением FORTH, который на самом деле не имеет какой-либо системы типов, я не могу представить себе язык с динамической типизацией, где система типов может быть разрушена. По определению, эти проверки скрыты в механизме выполнения, и каждая операция проверяется на работоспособность перед выполнением.

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


3
@ Adam: Очевидно, что это не совсем правильно, чтобы за него проголосовали :) Поскольку ответ Клетуса содержит очень много заблуждений (хотя я отредактировал худшее из них), я был вынужден изложить все словами одного слога ...
Норман Рэмси,

1
Что ж, я проголосовал против вас :) Даже слово «компилировать» не совсем понятно, поскольку современные виртуальные машины работают с динамическими языками. Технически Java и C # оба компилируются дважды (JIT) и оба выполняют некоторый анализ типов. Такой язык, как Javascript, работающий в .NET vm, может быть более безопасным из-за виртуальной машины.
Адам Гент

2
Я так запутался сейчас! Хорошо, дорогие великие гладиаторы арены, может ли такая бедная душа, как я, пойти со следующим простым пониманием? 1.Static: значения связаны с типом во время компиляции, а не во время выполнения. 2. Динамические: значения ассоциируются с типом во время выполнения, поэтому тип значения может изменяться во время выполнения ~, поэтому более подвержен проблемам, связанным с приведением типа во время выполнения. 3. Сильный / слабый: забудь об этом! Это не технические термины, а просто плохая номенклатура. Это зависит от того, о каком контексте говорят. Могу ли я продолжать свою жизнь с этим простым пониманием? :(
Саураб Патил

msgstr "гарантировано, что каждое значение данного типа (или класса) было создано путем вызова одного из конструкторов этого типа?" В С ответ нет. Может ли кто-нибудь привести пример ситуации, когда это происходит в C? Я полагаю, это включает в себя приведение указателей на структуры?
corazza

Сильная и слабая типизация: такой классификации нет.
Рауль

248

Это часто неправильно понимают, поэтому позвольте мне прояснить это.

Статическая / Динамическая Печать

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

Динамическая типизация - это место, где тип связан со значением . Типы проверяются во время выполнения.

Так в Java например:

String s = "abcd";

sбудет "навсегда" String. В течение своей жизни он может указывать на разные Strings (поскольку sэто ссылка на Java). Может иметь nullзначение, но никогда не будет ссылаться на Integerили List. Это статическая типизация.

В PHP:

$s = "abcd";          // $s is a string
$s = 123;             // $s is now an integer
$s = array(1, 2, 3);  // $s is now an array
$s = new DOMDocument; // $s is an instance of the DOMDocument class

Это динамическая типизация.

Сильный / слабый набор текста

(Изменить оповещение!)

Строгая типизация - это фраза без общепринятого значения. Большинство программистов, которые используют этот термин для обозначения чего-то иного, чем статическая типизация, используют его, чтобы подразумевать, что существует компиляция типов, которая обеспечивается компилятором. Например, CLU имеет систему строгого типа, которая не позволяет клиентскому коду создавать значение абстрактного типа, за исключением использования конструкторов, предоставляемых этим типом. C имеет довольно сильную систему типов, но она может быть «подорвана» до некоторой степени, потому что программа всегда может привести значение одного типа указателя к значению другого типа указателя. Так, например, в C вы можете взять значение, возвращаемое malloc()и весело преобразовать его FILE*, и компилятор не будет пытаться вас остановить или даже предупредить, что вы делаете что-то хитрое.

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

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

Оригинал этого ответа связывал слабую типизацию с неявным преобразованием (иногда также называемое «неявное продвижение»). Например, в Java:

String s = "abc" + 123; // "abc123";

Этот код является примером неявного продвижения: 123 неявно преобразуется в строку перед конкатенацией "abc". Можно утверждать, что компилятор Java переписывает этот код как:

String s = "abc" + new Integer(123).toString();

Рассмотрим классическую проблему PHP «начинается с»:

if (strpos('abcdef', 'abc') == false) {
  // not found
}

Ошибка здесь в том, что strpos()возвращает индекс совпадения, будучи 0. 0 приведен в логическое значение falseи, таким образом, условие на самом деле истинно. Решение состоит в том, чтобы использовать ===вместо того, ==чтобы избежать неявного преобразования.

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

Сравните это с Ruby:

val = "abc" + 123

что является ошибкой во время выполнения, потому что в Ruby объект 123 неявным образом не конвертируется только потому, что он передается +методу. В Ruby программист должен сделать преобразование явным:

val = "abc" + 123.to_s

Сравнение PHP и Ruby - хорошая иллюстрация здесь. Оба языка являются динамически типизированными языками, но PHP имеет много неявных преобразований, а Ruby (возможно, удивительно, если вы не знакомы с ним) - нет.

Статический / Динамический против Сильный / Слабый

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

Итак, чтобы ответить на ваш вопрос: еще один способ взглянуть на это, который в основном правильный, - это сказать, что статическая типизация - это безопасность типов во время компиляции, а строгая типизация - безопасность типов во время выполнения.

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

Но важно понимать, что язык может быть статическим / сильным, статическим / слабым, динамическим / сильным или динамическим / слабым.


Вместо того чтобы говорить, что $ s является целым числом или строкой, было бы лучше, если бы вы сказали, что тип связан с «abcd» или 1234, а не с переменной $ s.
Шринивас Редди Татиарти,

Отличный ответ с понятными примерами. Тем не менее, я думаю, что это не полностью устраняет путаницу в отношении того, ПОЧЕМУ люди спрашивают о сильной / статической как пара близких понятий. Например, формулировка OP "статическая типизация подразумевает строгую типизацию?" Ваш ответ подчеркивает их независимость. Чтобы продолжить разъяснение того, почему сильные часто соединяются со статикой, предыдущий ответ Нормана Рэмси очень хорош: stackoverflow.com/questions/376611/…
JasDev

1
"abc" + 123это ошибка времени выполнения , а не ошибка компиляции в ruby. Если бы это была ошибка компиляции, ruby ​​был бы статически напечатан.
sepp2k

Примеры слабой типизации нужно улучшить (см. Мой ответ), но в остальном хорошее форматирование.
Адам Гент

В моем мнении: «сильный против слабого типа» это: Сильный: «c» + True = ошибка времени выполнения или ошибка времени компиляции. Слабый: «c» + True = «b» или «d», потому что все обрабатывается как необработанные байты. Сильные: C #, Ruby, C ++ Слабые: Assembly, C (из-за неявных указателей на пустоту)
Джонатан Аллен

17

Оба полюса на двух разных осях:

  • строго типизированный против слабо типизированный
  • статически типизированный против динамически типизированного

Строго типизированный означает, что не будет автоматически преобразован из одного типа в другой. Слабо типизировано наоборот: Perl может использовать строку, как "123"в числовом контексте, автоматически конвертируя ее в int 123. Сильно типизированный язык, такой как python, этого не сделает.

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


6
Я должен не согласиться. Строго типизированный язык - это язык, который знает, что это за типы во время выполнения. Слабо типизированный язык - это язык, который не любит ассемблер. Ваш пример на третьей оси, "неявные против явных преобразований".
Джонатан Аллен

1
На самом деле нормально, я согласен с Джонатаном, но вам не нужно иметь типы, доступные во время выполнения, чтобы иметь строгую типизацию, если вы выполняете статический анализ и не разрешаете приведение типов. (см. мой отредактированный ответ).
Адам Гент

1
Python является примером динамически типизированного и строго типизированного языка
MaRoBet

13

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


Чтобы продемонстрировать это: в строго типизированном языке вы не можете сравнить «5» == 5 и заставить его быть верным: строки не являются целыми числами. Если мне не изменяет память, большинство современных языков сценариев строго типизированы. Tcl / Tk, однако, слабо типизирован - все может рассматриваться как строка.
Маленькие столики Бобби

Бобби, на слабо типизированном языке «5» == 5 читается как 0x35 == 0x05. Или, другими словами, все обрабатывается как необработанные байты.
Джонатан Аллен

Я должен не согласиться с вами обоими. Возьми Луа; Вы можете сравнить «5» == 5, и он вернет false, однако быстрое преобразование можно выполнить,
нажав

12

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

Приведенный выше пример слабой типизации Java из-за

String s = "abc" + 123;

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

String s = "abc" + new Integer(123).toString()

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

Это не похоже на C. C является одним из лучших примеров слабо типизированных. Среда выполнения не имеет представления, является ли 4 байта целым числом, структурой, указателем или 4 символами.

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

РЕДАКТИРОВАТЬ: После дальнейших размышлений это не обязательно верно, поскольку среда выполнения не обязательно должна иметь все типы, реализованные в системе времени выполнения, чтобы быть строго типизированной системой. Haskell и ML имеют такой полный статический анализ, что могут потенциально пропускать информацию о типах из среды выполнения.


B, вероятно, лучший, хотя и немного менее известный пример.
Том Хотин - tackline

Javascript также довольно слабый тип, потому что типов очень мало, и потому что вы не можете создавать новые типы.
Адам Гент

10

Ответ уже дан выше. Попытка провести различие между концепцией «сильный против недели» и «статический против динамики».

Что Сильно Типизировано VS Слабый Тип?

Сильно типизированный: не будет автоматически преобразован из одного типа в другой

В Go или Python, как в строго типизированных языках, «2» + 8 вызовет ошибку типа, поскольку они не допускают «приведение типа».

Слабо (слабо) типизированный: будет автоматически преобразован в один тип в другой: слабо типизированные языки, такие как JavaScript или Perl, не будут выдавать ошибку, и в этом случае JavaScript выдаст «28», а perl - 10.

Пример Perl:

my $a = "2" + 8;
print $a,"\n";

Сохраните его в main.pl и запустите, perl main.plи вы получите вывод 10.

Что такое статический VS динамический тип?

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

  • Статический: типы проверены перед выполнением
  • Динамический: типы проверяются на лету, во время выполнения

Что это значит?

В Go он проверяет набранный до выполнения (статическая проверка). Это означает, что он не только переводит и проверяет код, который он выполняет, но и сканирует весь код, и ошибка типа будет выдана еще до того, как код будет запущен. Например,

package main

import "fmt"

func foo(a int) {
    if (a > 0) {
        fmt.Println("I am feeling lucky (maybe).")
    } else {
        fmt.Println("2" + 8)
    }
}

func main() {
    foo(2)
}

Сохраните этот файл в main.go и запустите его, вы получите сообщение об ошибке компиляции.

go run main.go
# command-line-arguments
./main.go:9:25: cannot convert "2" (type untyped string) to type int
./main.go:9:25: invalid operation: "2" + 8 (mismatched types string and int)

Но этот случай не подходит для Python. Например, следующий блок кода будет выполнен для первого вызова foo (2) и завершится ошибкой для второго вызова foo (0). Это потому, что Python динамически типизирован, он только переводит и проверяет код, на котором он выполняется. Блок else никогда не выполняется для foo (2), поэтому «2» + 8 даже никогда не просматривается, и при вызове foo (0) он попытается выполнить этот блок и потерпел неудачу.

def foo(a):
    if a > 0:
        print 'I am feeling lucky.'
    else:
        print "2" + 8
foo(2)
foo(0)

Вы увидите следующий вывод

python main.py
I am feeling lucky.
Traceback (most recent call last):
  File "pyth.py", line 7, in <module>
    foo(0)
  File "pyth.py", line 5, in foo
    print "2" + 8
TypeError: cannot concatenate 'str' and 'int' objects

8

Одно не подразумевает другого. Для статически типизируемого языка это означает, что типы всех переменных известны или выводятся во время компиляции.

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


7

Строгая типизация, вероятно, означает, что переменные имеют четко определенный тип и что существуют строгие правила объединения переменных разных типов в выражениях. Например, если A - целое число, а B - число с плавающей точкой, то строгое правило относительно A + B может заключаться в том, что A приводится к числу с плавающей точкой, а результат возвращается как число с плавающей точкой. Если A является целым числом, а B является строкой, то строгое правило может заключаться в том, что A + B недопустимо.

Статическая типизация, вероятно, означает, что типы назначаются во время компиляции (или ее эквивалент для некомпилированных языков) и не могут изменяться во время выполнения программы.

Обратите внимание, что эти классификации не являются взаимоисключающими, и я бы ожидал, что они часто встречаются вместе. Многие строго типизированные языки также статически типизированы.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.