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


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

16 715

16 ответов:

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

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

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

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

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

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

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

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

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

Вот пример того, как 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)

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

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

Статическая типизация

Говорят, что язык программирования использует статическая типизация при проверке типа выполняется во время компиляции как в отличие от времени выполнения. В статической типизации, типы связаны с переменными не ценности. Статически типизированные языки включают Ада, Си, Си++, C#, Джейд, Ява, Фортран, Хаскелл, мл, Паскаль, Перл (в отношении различения скаляры, массивы, хэши и подпрограммы) и Scala. Статическая типизация это ограниченная форма программы проверка (см. Безопасность типа): соответственно, он позволяет многим типам ошибки, которые будут пойманы в начале цикл разработки. Статический тип шашки оценивают только тип информация, которую можно определить по адресу время компиляции, но способны проверить что проверенные условия сохраняют силу для все возможные варианты исполнения программа, которая избавляет от необходимости повторяйте проверку типов каждый раз, когда программа выполнена. Программа исполнение может быть также сделано более эффективным (т. е. быстрее или принимая уменьшенную память) путем пропуск проверок типа среды выполнения и включение других оптимизаций.

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

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

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

Наиболее широко используемые статически типизированные языки формально не являются типобезопасными. У них есть "лазейки" в системе спецификация языка программирования возможность программистам писать код это обходит проверку выполняется с помощью статического средства проверки типов и так что решайте более широкий круг проблем. Например, Java и большинство C-style языки имеют тип каламбура, и Хаскелл имеет такие особенности, как unsafePerformIO: такие операции могут быть небезопасными во время выполнения, в том, что они могут причина нежелательного поведения Из-за неправильный ввод значений, когда запуск программы.

Динамическая типизация

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

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

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

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

Ссылки

  1. Пирс, Бенджамин (2002). Типы и языки программирования. MIT Press. ИСБН 0-262-16209-1.

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

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

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

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

Динамически типизированные языки проверка типа во время выполнения и тип переменной может быть изменен во время выполнения.

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

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

"при переводе исходного кода"

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

Ввод текста

"когда проверяются типы"

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

  • Static : типы, проверенные перед выполнением
  • Dynamic: типы проверяются на лету, во время выполнения

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

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


Пример Python

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

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
Динамическая типизация является более гибкой, что некоторые ценят. Он обычно позволяет переменным изменять типы, что может привести к неожиданным ошибкам.
    В статически типизированном языке переменная ассоциируется с типом, который известен во время компиляции, и этот тип остается неизменным на протяжении всего выполнения программы. Аналогично, переменной может быть присвоено только то значение, которое является экземпляром известного / указанного типа.
  • в динамически типизированном языке переменная не имеет типа, и ее значение во время выполнения может иметь любую форму и вид.

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

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

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

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

Например в Java:

String str = "Hello";  //statically typed as string
str = 5;               //would throw an error since java is statically typed

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

Например в Python:

str = "Hello" # it is a string
str = 5       # now it is an integer; perfectly OK

С другой стороны, сильная/слабая типизация в языке связана с неявными преобразованиями типов (частично взятыми из ответа @Dario):

Например в Python:

str = 5 + "hello" 
# would throw an error since it does not want to cast one type to the other implicitly. 

Тогда как в PHP:

$str = 5 + "hello"; // equals 5 because "hello" is implicitly casted to 0 
// PHP is weakly typed, thus is a very forgiving language.

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

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

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

Например: C, C++, Java

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

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

Например: Ruby, Python.

Статически типизированные языки, такие как C++, Java и динамически типизированные языки, такие как Python, различаются только в плане выполнения типа переменной. статически типизированные языки имеют статический тип данных для переменной, здесь тип данных проверяется во время компиляции, поэтому отладка намного проще...в то время какдинамически типизированные языки не делают то же самое, проверяется тип данных, который выполняет программу и, следовательно, отладка немного затруднена.

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

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

В статически типизированном языке каждое имя переменной связывается как 1.to тип (во время компиляции, посредством объявления данных) 2.to объект. Привязка к объекту необязательна - если имя не привязано к объекту, имя считается нулевым. В языке с динамической типизацией каждое имя переменной (если оно не равно null) привязано только к объекту.

Имена привязываются к объектам во время выполнения с помощью операторов присваивания, и можно привязать a наименование объектов различных типов во время выполнения программы.

Статическая Типизация: Такие языки, как Java и Scala, являются статическими типизированными.

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

Например. int x; x = 10;

Система.из.println (x);

Динамическая Типизация: Perl-это динамический типизированный язык.

Переменные

Не обязательно инициализировать до их использования в коде.

Y=10; используйте эту переменную в более поздней части кода