Ответы:
В чем разница между языком со строгой типизацией и языком со статической типизацией?
Статически типизированный язык имеет систему типов, которая проверяется во время компиляции реализацией (компилятором или интерпретатором). Проверка типа отклоняет некоторые программы, и программы, которые проходят проверку, обычно имеют некоторые гарантии; например, компилятор гарантирует не использовать целочисленные арифметические инструкции для чисел с плавающей точкой.
Нет реального соглашения о том, что означает «строго типизированный», хотя наиболее широко используемое определение в профессиональной литературе заключается в том, что в «строго типизированном» языке программист не может обойти ограничения, налагаемые системой типов. , Этот термин почти всегда используется для описания статически типизированных языков.
Противоположностью статически типизированного является «динамически типизированный», что означает, что
Например, Lua , динамически типизированный язык, среди прочих, имеет строковый тип, числовой тип и логический тип. В Lua каждое значение принадлежит ровно одному типу, но это не является обязательным требованием для всех языков с динамической типизацией. В Lua допустимо объединять две строки, но нельзя объединять строку и логическое значение.
Противоположностью «строго типизированного» является «слабо типизированный», что означает, что вы можете работать с системой типов. C общеизвестно слабо типизирован, потому что любой тип указателя можно преобразовать в любой другой тип указателя просто путем приведения. Паскаль должен был быть строго типизирован, но упущение в дизайне (записи вариантов без тегов) привело к появлению лазейки в системе типов, так что технически она слабо типизирована. Примеры действительно строго типизированных языков включают CLU, Standard ML и Haskell. Стандарт ML фактически подвергся нескольким ревизиям для удаления лазеек в системе типов, которые были обнаружены после широкого распространения языка.
В целом, оказывается, что не очень полезно говорить о «сильных» и «слабых». Наличие в системе типов лазейки менее важно, чем точное число и характер лазеек, насколько вероятно их появление на практике, и каковы последствия использования лазейки. На практике лучше избегать терминов «сильный» и «слабый» в целом , потому что
Любители часто отождествляют их со «статичным» и «динамическим».
Очевидно, что "слабая типизация" используется некоторыми людьми, чтобы говорить об относительном преобладании или отсутствии неявных преобразований.
Профессионалы не могут договориться о том, что именно означают термины.
В целом вы вряд ли будете информировать или просвещать свою аудиторию.
Печальная правда в том, что когда речь идет о системах типов, «сильный» и «слабый» не имеют общепризнанного технического значения. Если вы хотите обсудить относительную силу систем типов, лучше обсудить, какие именно гарантии есть, а какие нет. Например, хороший вопрос, который следует задать, заключается в следующем: «гарантированно ли каждое значение данного типа (или класса) было создано путем вызова одного из конструкторов этого типа?» В С ответ нет. В CLU, F # и Haskell это да. Для C ++ я не уверен - я хотел бы знать.
Напротив, статическая типизация означает, что программы проверяются перед выполнением , и программа может быть отклонена до ее запуска. Динамическая типизация означает, что типы значений проверяются во время выполнения, а плохо напечатанная операция может привести к остановке программы или иным образом сигнализировать об ошибке во время выполнения. Основной причиной статической типизации является исключение программ, которые могут иметь такие «ошибки динамического типа».
Одно подразумевает другое?
На педантичном уровне нет, потому что слово «сильный» ничего не значит. Но на практике люди почти всегда делают одно из двух:
Они (неправильно) используют «сильный» и «слабый» для обозначения «статический» и «динамический», и в этом случае они (неправильно) используют «строго типизированный» и «статически типизированный» взаимозаменяемо.
Они используют «сильный» и «слабый» для сравнения свойств систем статического типа. Очень редко можно услышать, как кто-то говорит о «сильной» или «слабой» динамической системе типов. За исключением FORTH, который на самом деле не имеет какой-либо системы типов, я не могу представить себе язык с динамической типизацией, где система типов может быть разрушена. По определению, эти проверки скрыты в механизме выполнения, и каждая операция проверяется на работоспособность перед выполнением.
В любом случае, если человек называет язык «строго типизированным», он, скорее всего, будет говорить о статически типизированном языке.
Это часто неправильно понимают, поэтому позвольте мне прояснить это.
Статическая типизация - это место, где тип связан с переменной . Типы проверяются во время компиляции.
Динамическая типизация - это место, где тип связан со значением . Типы проверяются во время выполнения.
Так в Java например:
String s = "abcd";
s
будет "навсегда" String
. В течение своей жизни он может указывать на разные String
s (поскольку 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 (возможно, удивительно, если вы не знакомы с ним) - нет.
Дело в том, что статическая / динамическая ось не зависит от сильной / слабой оси. Люди путают их, вероятно, отчасти потому, что сильная и слабая типизация не только менее четко определены, но и нет единого мнения о том, что именно подразумевается под сильной и слабой. По этой причине сильная / слабая типизация является скорее оттенком серого, нежели черного или белого.
Итак, чтобы ответить на ваш вопрос: еще один способ взглянуть на это, который в основном правильный, - это сказать, что статическая типизация - это безопасность типов во время компиляции, а строгая типизация - безопасность типов во время выполнения.
Причина этого в том, что переменные в статически типизированном языке имеют тип, который должен быть объявлен и может быть проверен во время компиляции. В языке со строгим типом есть значения, которые имеют тип во время выполнения, и программисту трудно подорвать систему типов без динамической проверки.
Но важно понимать, что язык может быть статическим / сильным, статическим / слабым, динамическим / сильным или динамическим / слабым.
"abc" + 123
это ошибка времени выполнения , а не ошибка компиляции в ruby. Если бы это была ошибка компиляции, ruby был бы статически напечатан.
Оба полюса на двух разных осях:
Строго типизированный означает, что не будет автоматически преобразован из одного типа в другой. Слабо типизировано наоборот: Perl может использовать строку, как "123"
в числовом контексте, автоматически конвертируя ее в int 123
. Сильно типизированный язык, такой как python, этого не сделает.
Статически типизированный означает, что компилятор вычисляет тип каждой переменной во время компиляции. Динамически типизированные языки только определяют типы переменных во время выполнения.
Строго типизированный означает, что между преобразованиями между типами существуют ограничения. Статически типизированный означает, что типы не являются динамическими - вы не можете изменить тип переменной после ее создания.
Принуждение данных не обязательно означает слабо типизированный, потому что иногда его синтаксический сахар:
Приведенный выше пример слабой типизации Java из-за
String s = "abc" + 123;
Не является слабо типизированным примером, потому что его действительно делают:
String s = "abc" + new Integer(123).toString()
Приведение данных также не является слабо типизированным, если вы создаете новый объект. Java - очень плохой пример слабо типизированного (и любой язык с хорошим отражением, скорее всего, не будет слабо типизированным). Поскольку среда выполнения языка всегда знает, что это за тип (исключение могут быть нативные типы).
Это не похоже на C. C является одним из лучших примеров слабо типизированных. Среда выполнения не имеет представления, является ли 4 байта целым числом, структурой, указателем или 4 символами.
Время выполнения языка действительно определяет, является ли его слабо типизированный в противном случае его действительно справедливым мнением.
РЕДАКТИРОВАТЬ: После дальнейших размышлений это не обязательно верно, поскольку среда выполнения не обязательно должна иметь все типы, реализованные в системе времени выполнения, чтобы быть строго типизированной системой. Haskell и ML имеют такой полный статический анализ, что могут потенциально пропускать информацию о типах из среды выполнения.
Ответ уже дан выше. Попытка провести различие между концепцией «сильный против недели» и «статический против динамики».
Сильно типизированный: не будет автоматически преобразован из одного типа в другой
В Go или Python, как в строго типизированных языках, «2» + 8 вызовет ошибку типа, поскольку они не допускают «приведение типа».
Слабо (слабо) типизированный: будет автоматически преобразован в один тип в другой: слабо типизированные языки, такие как JavaScript или Perl, не будут выдавать ошибку, и в этом случае JavaScript выдаст «28», а perl - 10.
Пример Perl:
my $a = "2" + 8;
print $a,"\n";
Сохраните его в main.pl и запустите, perl main.pl
и вы получите вывод 10.
В программировании программист определяет статическую типизацию и динамическую типизацию относительно точки, в которой проверяются типы переменных. Статические типизированные языки - это языки, в которых проверка типов выполняется во время компиляции, тогда как динамические типизированные языки - это языки, в которых проверка типов выполняется во время выполнения.
Что это значит?
В 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
Одно не подразумевает другого. Для статически типизируемого языка это означает, что типы всех переменных известны или выводятся во время компиляции.
Сильно типизированный язык не позволяет использовать один тип , как другой. C - это слабо типизированный язык и хороший пример того, что строго типизированные языки не позволяют. В C вы можете передать элемент данных неправильного типа, и он не будет жаловаться. В строго типизированных языках вы не можете.
Строгая типизация, вероятно, означает, что переменные имеют четко определенный тип и что существуют строгие правила объединения переменных разных типов в выражениях. Например, если A - целое число, а B - число с плавающей точкой, то строгое правило относительно A + B может заключаться в том, что A приводится к числу с плавающей точкой, а результат возвращается как число с плавающей точкой. Если A является целым числом, а B является строкой, то строгое правило может заключаться в том, что A + B недопустимо.
Статическая типизация, вероятно, означает, что типы назначаются во время компиляции (или ее эквивалент для некомпилированных языков) и не могут изменяться во время выполнения программы.
Обратите внимание, что эти классификации не являются взаимоисключающими, и я бы ожидал, что они часто встречаются вместе. Многие строго типизированные языки также статически типизированы.
И обратите внимание, что когда я использую слово «вероятно», это происходит потому, что нет общепринятых определений этих терминов. Как вы уже видели из ответов до сих пор.