В чем разница между статически типизированными и динамически типизированными языками? - PullRequest
839 голосов
/ 05 октября 2009

Я много слышу, что новые языки программирования динамически типизированы, но что это на самом деле означает, когда мы говорим, что язык динамически типизирован или статически типизирован?

Ответы [ 14 ]

744 голосов
/ 05 октября 2009

Статически типизированные языки

Язык статически типизирован, если тип переменной известен во время компиляции. Для некоторых языков это означает, что вы, как программист, должны указать, к какому типу относится каждая переменная (например, Java, C, C ++); другие языки предлагают некоторую форму вывода типа , способность системы типов определять тип переменной (например, OCaml, Haskell, Scala, Kotlin)

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

Примеры: C, C ++, Java, Rust, Go, Scala

Динамически типизированные языки

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

Примеры: Perl, Ruby, Python, PHP, JavaScript

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

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

328 голосов
/ 05 октября 2009

Статически типизированные языки программирования выполняют проверку типов (т. Е. Процесс проверки и применения ограничений типов) в время компиляции , в отличие от время выполнения .

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

280 голосов
/ 06 января 2015

Вот пример, показывающий, как 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)
139 голосов
/ 30 ноября 2015

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

Например, в 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

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

Подводя итог, type описывает (или должен был описать) переменные в языке, а не в самом языке. Его можно было бы лучше использовать как язык со статически типизированными переменными против язык с динамически типизированными переменными ИМХО.

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

Динамически типизированные языки обычно интерпретируются, поэтому проверка типов (если есть) происходит во время выполнения, когда они используются. Это, конечно, приводит к некоторому снижению производительности и является одной из причин, по которой динамические языки (например, python, ruby, php) не масштабируются так же хорошо, как типизированные (java, c # и т. Д.). С другой стороны, статически типизированные языки имеют большую начальную стоимость: обычно вы пишете больше кода, а код сложнее. Но это окупается позже.

Хорошо, что обе стороны заимствуют свойства у другой стороны. Типизированные языки включают в себя более динамические функции, например, универсальные и динамические библиотеки в c #, а динамические языки включают в себя больше проверки типов, например, аннотации типов в python или вариант HACK PHP, которые обычно не являются ядром языка и могут использоваться на потребность.

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

38 голосов
/ 05 октября 2009

http://en.wikipedia.org/wiki/Type_system

Статическая печать

Говорят, что язык программирования использует статическая типизация при проверке типа выполняется во время компиляции как в отличие от времени выполнения. В статической типизации, типы связаны с переменными не ценности. Статически типизированные языки включают в себя Ada, C, C ++, C #, JADE, Java, Fortran, Haskell, ML, Pascal, Perl (в отношении различения скаляры, массивы, хэши и подпрограммы) и Scala. Статическая печать это ограниченная форма программы проверка (см. тип безопасности): соответственно, это позволяет многим типам ошибки, которые должны быть обнаружены в начале цикл разработки. Статический тип шашки оценивают только тип информация, которая может быть определена в время компиляции, но в состоянии проверить что проверенные условия выполняются для все возможные казни программа, которая устраняет необходимость повторять проверки типов каждый раз Программа выполнена. Выполнение программы также может быть сделано более эффективным (т.е. быстрее или занимает меньше памяти) пропуская проверки типа во время выполнения и включение других оптимизаций.

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

if <complex test> then 42 else <type error>

будет отклонено как неправильно напечатанное, потому что статический анализ не может определить что ветвь else не будет приняты. [1] Консервативное поведение статических шашек типа выгодно когда нередко оценивается как ложное: A Статическая проверка типа может определить тип ошибки в редко используемых путях кода. Без статической проверки типов, даже тесты покрытия кода со 100% кодом покрытие может быть не в состоянии найти такой ошибки типа. Тесты покрытия кода могут не удается обнаружить такие ошибки типа потому что сочетание всех мест где создаются значения и все места, где используется определенное значение должны быть приняты во внимание.

Наиболее широко используемый статически типизированный языки не являются формально безопасными. У них есть «лазейки» в спецификация языка программирования позволяя программистам писать код что обходит проверку в исполнении статической проверки типов и так что решайте более широкий круг проблем. Например, Java и большинство C-стиля Языки имеют тип Punning, и У Haskell есть такие особенности как unsafePerformIO: такие операции могут быть небезопасным во время выполнения, в том смысле, что они могут вызвать нежелательное поведение из-за неправильный ввод значений при Программа работает.

Динамический набор

Язык программирования называется динамически типизированный или просто «динамический», когда большинство проверяет его тип выполняется во время выполнения, в отличие от во время компиляции. При динамическом наборе текста типы связаны со значениями не переменные. Динамически типизированные языки включают Groovy, JavaScript, Lisp, Lua, Objective-C, Perl (по отношению к пользовательские типы, но не встроенные типы), PHP, Пролог, Python, Ruby, Smalltalk и Tcl. По сравнению со статическим типизация, динамическая типизация может быть больше гибкий (например, позволяя программам генерировать типы и функциональность на основе на данных во время выполнения), хотя на за счет меньшего количества априорных гарантий. Это потому, что динамически типизированный язык принимает и пытается выполнить некоторые программы, которые могут быть считается недействительным статическим типом шашка.

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

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

Разработка в динамически типизированном языки часто поддерживаются методы программирования, такие как блок тестирование. Тестирование является ключевой практикой в профессиональная разработка программного обеспечения, и особенно важно в динамически типизированные языки. В практика, тестирование сделано для обеспечения правильная работа программы может обнаружить гораздо более широкий диапазон ошибок, чем статические проверка типов, но, наоборот, не может поиск как всеобъемлющий для ошибки, которые как тестирование, так и статические Тип проверки может обнаружить. Тестирование может быть включено в цикл сборки программного обеспечения, в этом случае это можно рассматривать как «время компиляции» проверьте, что пользователь программы будет не нужно вручную запускать такие тесты.

Ссылки

  1. Пирс, Бенджамин (2002). Типы и языки программирования. MIT Press. ISBN 0-262-16209-1.
14 голосов
/ 12 октября 2015

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

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

Однако, если бы мы дополнили нетипизированное лямбда-исчисление примитивными числами и арифметическими операциями, мы могли бы выполнить бессмысленные операции, например, сложив вместе два лямбда-члена: (λx.x) + (λy.y). Можно утверждать, что единственная разумная вещь, которую нужно сделать - это сообщить об ошибке, когда это происходит, но чтобы это можно было сделать, каждое значение должно быть помечено индикатором, который указывает, является ли термин лямбда-термином или числом. Затем оператор сложения проверит, что оба аргумента действительно помечены как числа, и, если это не так, выдаст ошибку. Обратите внимание, что эти теги являются , а не типами, поскольку типы - это свойства программ, а не значений, создаваемых этими программами.

Однотипированный язык, который делает это, называется динамически типизированным.

Такие языки, как JavaScript, Python и Ruby, являются однотипными. Опять же, оператор typeof в JavaScript и функция type в Python имеют вводящие в заблуждение имена; они возвращают теги, связанные с операндами, а не их типы. Точно так же, dynamic_cast в C ++ и instanceof в Java делают , а не делают проверки типов.

5 голосов
/ 09 декабря 2017

Скомпилировано и интерпретировано

«Когда переводится исходный код»

  • Исходный код : Оригинальный код (обычно вводимый человеком в компьютер)
  • Перевод : Преобразование исходного кода в то, что может прочитать компьютер (то есть машинный код)
  • Время выполнения : период, когда программа выполняет команды (после компиляции, если скомпилирована)
  • Скомпилированный язык : код, переведенный до выполнения
  • Устный перевод : код, переведенный на лету, во время исполнения

Typing

«При проверке типов»

5 + '3' является примером ошибки типа в строго типизированных языках, таких как Go и Python, потому что они не допускают "приведение типа" -> возможность значения изменить тип в определенных контекстах, таких как слияние двух типов. Слабо типизированные языки, такие как JavaScript, не будут выдавать ошибку типа (приводит к '53').

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

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

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


Пример Python

Динамический, Интерпретированный

def silly(a):
    if a > 0:
        print 'Hi'
    else:
        print 5 + '3'

silly(2)

Поскольку Python интерпретируется и динамически типизируется, он только транслирует и проверяет код, на котором он выполняется. Блок else никогда не выполняется, поэтому 5 + '3' даже не просматривается!

Что, если он был напечатан статически?

Ошибка типа будет выдана еще до запуска кода. Он по-прежнему выполняет проверку типов перед выполнением, даже если он интерпретируется.

Что, если он был скомпилирован?

Блок else будет переведен / просмотрен до выполнения, но поскольку он динамически типизирован, он не выдаст ошибку! Динамически типизированные языки не проверяют типы до выполнения, и эта строка никогда не выполняется.


Go Пример

Статический, скомпилированный

package main

import ("fmt"
)

func silly(a int) {
  if (a > 0) {
      fmt.Println("Hi")
  } else {
      fmt.Println("3" + 5)
  }
}

func main() {
  silly(2)
}

Типы проверяются перед запуском (статические), и ошибка типа немедленно обнаруживается! Типы будут по-прежнему проверяться перед выполнением, если это будет интерпретировано, с тем же результатом. Если бы он был динамическим, он не выдавал бы никаких ошибок, даже если код был бы просмотрен во время компиляции.


Performance

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

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

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

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


Больше различий

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

num = 2
num = '3' // ERROR

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

5 голосов
/ 27 июля 2016

Статически типизированные языки проверяют тип во время компиляции, и тип НЕ может измениться. (Не смущайтесь комментариями приведения типов, создается новая переменная / ссылка).

Проверка типа динамически типизированных языков во время выполнения и тип переменной МОЖЕТ быть изменен во время выполнения.

4 голосов
/ 01 октября 2017

Статически типизированные языки : каждая переменная и выражение уже известны во время компиляции.

(int a; a может принимать только значения целого типа во время выполнения)

Примеры: C, C ++, Java

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

(var a; a может принимать любые значения во время выполнения)

Примеры: Ruby, Python.

4 голосов
/ 29 ноября 2016

Сладкие и простые определения, но подходящие по необходимости: Статически типизированные языки связывают тип с переменной для всей области видимости (Seg: SCALA) Динамически типизированные языки связывают тип с фактическим значением, на которое ссылается переменная.

...