Я часто слышу, что новые языки программирования динамически типизированы, но что это на самом деле означает, когда мы говорим, что язык динамически типизирован или статически типизирован?
Я часто слышу, что новые языки программирования динамически типизированы, но что это на самом деле означает, когда мы говорим, что язык динамически типизирован или статически типизирован?
Ответы:
Язык статически типизирован, если тип переменной известен во время компиляции. Для некоторых языков это означает, что вы как программист должны указать тип каждой переменной (например, Java, C, C ++); другие языки предлагают некоторую форму вывода типов , способность системы типов определять тип переменной (например, OCaml, Haskell, Scala, Kotlin)
Основным преимуществом здесь является то, что компилятор может выполнять все виды проверок, и поэтому многие тривиальные ошибки обнаруживаются на очень ранней стадии.
Примеры: C, C ++, Java, Rust, Go, Scala
Язык динамически типизируется, если тип связан со значениями времени выполнения, а не с именованными переменными / полями / и т. Д. Это означает, что вы, как программист, можете писать немного быстрее, потому что вам не нужно каждый раз указывать типы (если только не используется статически типизированный язык с выводом типа ).
Примеры: Perl, Ruby, Python, PHP, JavaScript
У большинства языков сценариев есть эта возможность, так как в любом случае нет никакого компилятора, который бы выполнял статическую проверку типов, но вы можете найти ошибку, вызванную неверным толкованием интерпретатором типа переменной. К счастью, сценарии имеют тенденцию быть маленькими, поэтому ошибки не так много мест, чтобы скрыть.
Большинство динамически типизированных языков позволяют предоставлять информацию о типах, но не требуют ее. Один язык, который в настоящее время разрабатывается, Rascal , использует гибридный подход, позволяющий динамическую типизацию внутри функций, но обеспечивающий статическую типизацию для сигнатуры функции.
Статически типизированные языки программирования выполняют проверку типов (то есть процесс проверки и применения ограничений типов) во время компиляции, а не во время выполнения .
Динамически типизированные языки программирования выполняют проверку типов во время выполнения, а не во время компиляции .
Примеры статически типизированных языков: - Java, C, C ++
Примеры динамически типизированных языков: - Perl, Ruby, Python, PHP, JavaScript
Вот пример, показывающий, как Python (динамически типизированный) и Go (статически типизированный) обрабатывают ошибку типа:
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
Python выполняет проверку типов во время выполнения, и поэтому:
silly(2)
Работает отлично и выдает ожидаемый результат Hi
. Ошибка возникает только в случае попадания в проблемную строку:
silly(-1)
Производит
TypeError: unsupported operand type(s) for +: 'int' and 'str'
потому что соответствующая строка была фактически выполнена.
Go с другой стороны выполняет проверку типов во время компиляции:
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
Выше не скомпилируется, со следующей ошибкой:
invalid operation: "3" + 5 (mismatched types string and int)
runhaskell
Например, Haskell можно интерпретировать как
Проще говоря, так: в статически типизированном языке типы переменных являются статическими , то есть, если вы установите переменную для типа, вы не сможете ее изменить. Это связано с тем, что типизация связана с переменной, а не со значением, к которому она относится.
Например в Java:
String str = "Hello"; //variable str statically typed as string
str = 5; //would throw an error since str is supposed to be a string only
Где, с другой стороны: в динамически типизированном языке типы переменных являются динамическими , то есть после того, как вы установите переменную в тип, вы МОЖЕТЕ изменить ее. Это связано с тем, что типизация связана со значением, которое она принимает, а не с самой переменной.
Например в Python:
str = "Hello" # variable str is linked to a string value
str = 5 # now it is linked to an integer value; perfectly OK
Таким образом, лучше всего рассматривать переменные в динамически типизированных языках как просто общие указатели на типизированные значения.
Подводя итог, тип описывает (или должен был описать) переменные в языке, а не сам язык. Он мог бы быть лучше использован в качестве языка со статически типизированными переменными по сравнению с языком с динамически типизированными переменными IMHO.
Языки со статической типизацией, как правило, являются компилируемыми языками, поэтому компиляторы проверяют типы (правильно понимаете, так как типы не могут быть изменены позднее во время выполнения).
Динамически типизированные языки обычно интерпретируются, поэтому проверка типов (если есть) происходит во время выполнения, когда они используются. Это, конечно, приводит к некоторому снижению производительности и является одной из причин, по которой динамические языки (например, python, ruby, php) не так хорошо масштабируются, как типизированные (java, c # и т. Д.). С другой стороны, статически типизированные языки имеют большую начальную стоимость: обычно вы пишете больше кода, а код сложнее. Но это окупается позже.
Хорошо, что обе стороны заимствуют черты у другой стороны. Типизированные языки включают в себя больше динамических функций, например, универсальные и динамические библиотеки в c #, а динамические языки включают в себя больше проверки типов, например, аннотации типов в python или вариант HACK PHP, которые обычно не являются ядром языка и могут использоваться на требование.
Когда дело доходит до выбора технологии, ни одна из сторон не имеет внутреннего превосходства над другой. Это просто вопрос предпочтения, хотите ли вы получить больше контроля или гибкость. просто выберите правильный инструмент для работы и убедитесь, что вы видите, что доступно с точки зрения противоположности, прежде чем рассматривать вопрос о переключателе.
http://en.wikipedia.org/wiki/Type_system
Статическая печать
Говорят, что язык программирования использует статическую типизацию, когда проверка типов выполняется во время компиляции, а не во время выполнения. В статической типизации типы связаны с переменными, а не со значениями. Статически типизированные языки включают в себя Ada, C, C ++, C #, JADE, Java, Fortran, Haskell, ML, Pascal, Perl (в отношении различения скаляров, массивов, хэшей и подпрограмм) и Scala. Статическая типизация является ограниченной формой верификации программы (см. Безопасность типов): соответственно, она позволяет обнаруживать многие ошибки типов на ранних этапах цикла разработки. Средство проверки статического типа оценивает только информацию о типе, которая может быть определена во время компиляции, но может проверить, что проверенные условия выполняются для всех возможных исполнений программы, что устраняет необходимость повторять проверки типов при каждом запуске программы. Выполнение программы также можно сделать более эффективным (т. Е. Быстрее или с меньшим объемом памяти), исключив проверки типов во время выполнения и включив другие оптимизации.
Поскольку они оценивают информацию о типе во время компиляции и поэтому не имеют информации о типе, которая доступна только во время выполнения, статические средства проверки типов являются консервативными. Они будут отклонять некоторые программы, которые могут хорошо себя вести во время выполнения, но которые не могут быть статически определены для правильной типизации. Например, даже если выражение всегда оценивается как true во время выполнения, программа, содержащая код
if <complex test> then 42 else <type error>
будет отклонен как неправильно напечатанный, потому что статический анализ не может определить, что ветвь else не будет взята. [1] Консервативное поведение статических контроллеров типов выгодно, если нередко оценивается как ложное: статический контролер типов может обнаруживать ошибки типов в редко используемых путях кода. Без статической проверки типов даже тесты покрытия кода со 100% покрытием кода могут не обнаружить такие ошибки типа. Тесты покрытия кода могут не обнаружить такие ошибки типа, поскольку необходимо учитывать комбинацию всех мест, где создаются значения, и всех мест, где используется определенное значение.
Наиболее широко используемые статически типизированные языки не являются формально безопасными. Они имеют «лазейки» в спецификации языка программирования, позволяющие программистам писать код, который обходит проверку, выполняемую статической проверкой типов, и таким образом решает более широкий круг проблем. Например, Java и большинство языков в стиле C имеют типизацию типов, а Haskell имеет такие функции, как unsafePerformIO: такие операции могут быть небезопасными во время выполнения, поскольку они могут вызывать нежелательное поведение из-за неправильного ввода значений во время выполнения программы.
Динамическая печать
Язык программирования называется динамически типизированным или просто «динамическим», когда большая часть его проверки типов выполняется во время выполнения, а не во время компиляции. В динамической типизации типы связаны со значениями, а не переменными. Динамически типизированные языки включают Groovy, JavaScript, Lisp, Lua, Objective-C, Perl (относительно пользовательских типов, но не встроенных типов), PHP, Prolog, Python, Ruby, Smalltalk и Tcl. По сравнению со статической типизацией динамическая типизация может быть более гибкой (например, позволяя программам генерировать типы и функциональные возможности на основе данных времени выполнения), хотя за счет меньшего количества априорных гарантий. Это связано с тем, что динамически типизированный язык принимает и пытается выполнить некоторые программы, которые могут быть признаны недействительными с помощью средства проверки статического типа.
Динамическая типизация может привести к ошибкам типа во время выполнения, то есть во время выполнения значение может иметь непредвиденный тип, и для этого типа применяется несущественная операция. Эта операция может произойти намного позже места, где была допущена ошибка программирования, то есть места, где неправильный тип данных был передан в место, которое он не должен иметь. Это затрудняет поиск ошибки.
Динамически типизированные языковые системы, по сравнению с их статически типизированными кузенами, выполняют меньше проверок исходного кода во время компиляции (но проверяют, например, что программа синтаксически верна). Проверка во время выполнения потенциально может быть более сложной, поскольку они могут использовать динамическую информацию, а также любую информацию, которая присутствовала во время компиляции. С другой стороны, проверки во время выполнения подтверждают только то, что условия выполняются при конкретном выполнении программы, и эти проверки повторяются для каждого выполнения программы.
Разработка на динамически типизированных языках часто поддерживается практиками программирования, такими как модульное тестирование. Тестирование является ключевой практикой в профессиональной разработке программного обеспечения и особенно важно для языков с динамической типизацией. На практике тестирование, выполненное для обеспечения правильной работы программы, может обнаружить гораздо более широкий диапазон ошибок, чем статическая проверка типов, но, наоборот, не может выполнить поиск всесторонне ошибок, которые могут обнаружить как тестирование, так и статическая проверка типов. Тестирование может быть включено в цикл сборки программного обеспечения, и в этом случае его можно рассматривать как проверку «времени компиляции», при которой пользователю программы не нужно будет запускать такие тесты вручную.
Ссылки
- Пирс, Бенджамин (2002). Типы и языки программирования. MIT Press. ISBN 0-262-16209-1.
myObject[remoteDataName]
. Тогда нет никакого способа узнать, какое свойство он выберет, или даже если это вообще допустимое свойство.
Терминология «динамически типизированная», к сожалению, вводит в заблуждение. Все языки статически типизированы, а типы являются свойствами выражений (а не значений, как некоторые думают). Однако некоторые языки имеют только один тип. Это так называемые однотипные языки. Одним из примеров такого языка является нетипизированное лямбда-исчисление.
В нетипизированном лямбда-исчислении все термины являются лямбда-терминами, и единственная операция, которая может быть выполнена над одним термином, - это применение его к другому термину. Следовательно, все операции всегда приводят либо к бесконечной рекурсии, либо к лямбда-члену, но никогда не сигнализируют об ошибке.
Тем не менее, мы были для усиления нетипизированной лямбды - исчисления с примитивными числами и арифметическими операциями, то мы могли бы выполнить бессмысленные операции, например , добавив два члена лямбды вместе: (λx.x) + (λy.y)
. Можно утверждать, что единственная разумная вещь, которую нужно сделать - это сообщить об ошибке, когда это происходит, но чтобы это можно было сделать, каждое значение должно быть помечено индикатором, который указывает, является ли термин лямбда-термином или числом. Затем оператор сложения проверит, что оба аргумента действительно помечены как числа, и, если это не так, сигнализирует об ошибке. Обратите внимание, что эти теги не являются типами, потому что типы - это свойства программ, а не значений, создаваемых этими программами.
Однотипированный язык, который делает это, называется динамически типизированным.
Такие языки, как JavaScript, Python и Ruby, являются однотипными. Опять же, typeof
оператор в JavaScript и type
функция в Python имеют вводящие в заблуждение имена; они возвращают теги, связанные с операндами, а не их типы. Точно так же dynamic_cast
в C ++ и instanceof
в Java не делайте проверки типов.
«Когда исходный код переведен»
«Когда типы проверяются»
5 + '3'
является примером ошибки типа в строго типизированных языках, таких как Go и Python, потому что они не допускают «приведение типов» -> возможность значения менять тип в определенных контекстах, таких как объединение двух типов. Языки со слабой типизацией , такие как JavaScript, не будут вызывать ошибку типа (приводит к '53'
).
Определения «Static & Compiled» и «Dynamic & Interpreted» очень похожи ... но помните, что это «когда проверяются типы» и «когда переводится исходный код».
Вы получите одинаковые ошибки типа независимо от того, скомпилирован или интерпретирован язык ! Вы должны разделить эти термины концептуально.
Динамический, Интерпретированный
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
silly(2)
Поскольку Python интерпретируется и динамически типизируется, он только переводит и проверяет код, на котором он выполняется. else
Блок никогда не выполняется, поэтому 5 + '3'
никогда даже не смотрел на!
Что, если он был статически напечатан?
Ошибка типа будет выдана еще до запуска кода. Он по-прежнему выполняет проверку типов перед выполнением, даже если он интерпретируется.
Что если он был скомпилирован?
else
Блок будет переведен / посмотрел на перед во время выполнения, а потому , что это динамически типизированных он не выдаст ошибку! Динамически типизированные языки не проверяют типы до выполнения, и эта строка никогда не выполняется.
Статический, скомпилированный
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
Типы проверяются перед запуском (статические), и ошибка типа немедленно обнаруживается! Типы будут по-прежнему проверяться перед выполнением, если это будет интерпретировано, с тем же результатом. Если бы он был динамическим, он не выдавал бы никаких ошибок, даже если код был бы просмотрен во время компиляции.
Скомпилированный язык будет иметь лучшую производительность во время выполнения, если он статически типизирован (по сравнению с динамическим); знание типов позволяет оптимизировать машинный код.
Языки со статической типизацией имеют лучшую производительность во время выполнения по своей природе из-за того, что нет необходимости динамически проверять типы во время выполнения (проверяется перед запуском).
Точно так же скомпилированные языки быстрее во время выполнения, поскольку код уже был переведен, вместо того, чтобы нуждаться в «интерпретации» / переводе на лету.
Обратите внимание, что как скомпилированный, так и статически типизированный языки будут иметь задержку перед запуском для перевода и проверки типов, соответственно.
Статическая типизация отлавливает ошибки на ранних этапах, а не обнаруживает их во время выполнения (особенно полезно для длинных программ). Он более «строгий» в том смысле, что он не допускает ошибок типов в вашей программе и часто предотвращает изменение типов переменных, что дополнительно защищает от непреднамеренных ошибок.
num = 2
num = '3' // ERROR
Динамическая типизация более гибкая, что некоторые ценят. Обычно это позволяет переменным изменять типы, что может привести к непредвиденным ошибкам.
Статически типизированные языки : каждая переменная и выражение уже известны во время компиляции.
(во int a;
время выполнения может принимать только целочисленные значения)
Примеры: C, C ++, Java
Динамически типизированные языки : переменные могут получать различные значения во время выполнения, и их тип определяется во время выполнения.
( var a;
может принимать любые значения во время выполнения)
Примеры: Ruby, Python.
Статически типизированные языки проверяют тип во время компиляции, и тип НЕ может измениться. (Не будьте милыми с комментариями приведения типов, создается новая переменная / ссылка).
Динамически типизированные языки проверяют тип во время выполнения и тип переменной МОЖЕТ быть изменен во время выполнения.
Простые и понятные определения, но соответствующие потребности: языки со статической типизацией связывают тип с переменной для всей своей области (Seg: SCALA) Языки с динамической типизацией связывают тип с фактическим значением, на которое ссылается переменная.
Языки со статической типизацией, такие как C ++, Java, и языки с динамической типизацией, такие как Python, отличаются только с точки зрения исполнения типа переменной. Статически типизированные языки имеют статический тип данных для переменной, здесь тип данных проверяется во время компиляции, поэтому отладка намного проще ... тогда как динамически типизированные языки не делают того же, проверяется тип данных, который выполняет программу и, следовательно, отладка немного сложна.
Более того, они имеют очень небольшую разницу и могут быть связаны со строго типизированными и слабо типизированными языками. Строго типизированный язык не позволяет использовать один тип в качестве другого, например. C и C ++ ... тогда как слабо типизированные языки позволяют eg.python
Статически Типизированный
Типы проверяются перед выполнением, поэтому ошибки могут быть обнаружены ранее.
Примеры = с ++
Динамически Типизированный
Типы проверяются во время выполнения.
Примеры = Питон
Языки со статической типизацией (компилятор разрешает вызовы методов и компилирует ссылки):
Динамически типизированные языки (решения, принимаемые в запущенной программе):
динамически типизированный язык помогает быстро создавать прототипы концепций алгоритма, не задумываясь о том, какие типы переменных необходимо использовать (что необходимо в статически типизированных языках ).
Статическая типизация: языки, такие как Java и Scala, имеют статическую типизацию.
Переменные должны быть определены и инициализированы, прежде чем они будут использованы в коде.
например int x; х = 10;
System.out.println (х);
Динамическая типизация: Perl - язык динамической типизации.
Переменные не нужно инициализировать перед использованием в коде.
у = 10; используйте эту переменную в более поздней части кода
$
), array ( @
) и hash ( %
). Тип переменной в Perl известен во время компиляции и остается неизменным до конца жизни переменных.