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

простой вопрос люди: я делаю много программирования (профессионально и лично) в скомпилированных языках, таких как C++/Java и в интерпретируемых языках, таких как Python/Javascript. Я лично считаю, что мой код почти всегда более надежен, когда я программирую на статически типизированных языках. Однако почти каждый интерпретируемый язык, с которым я сталкиваюсь, использует динамическую типизацию (PHP, Perl, Python и т. д.). Я знаю, почему скомпилированные языки используют статическую типизацию (большую часть времени), но я не могу понять отвращение к статической типизации в интерпретируемом языке дизайна.

Почему крутые отключить? Является ли это частью природы интерпретируемых языков? ОП?

7 ответов


интересный вопрос. Кстати, я автор / сопровождающий phc (компилятор для PHP), и я делаю свою кандидатскую диссертацию по компиляторам для динамических языков, поэтому я надеюсь, что могу предложить некоторые идеи.

Я думаю, что здесь есть ошибочное предположение. Авторы PHP, Perl, Python, Ruby, Lua и т. д. не разрабатывали "интерпретируемые языки", они разрабатывали динамические языки и реализовывали их с помощью интерпретаторов. Они сделали это, потому что переводчиков гораздо легче писать, чем переводчиков. компиляторы.

первая реализация Java была интерпретирована, и это статически типизированный язык. Переводчики существуют для статических языков: у Haskell и OCaml есть переводчики, и раньше был популярный переводчик для C, но это было давно. Они популярны, потому что они позволяют REPL, которое может сделать развитие более легким.

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

чтобы обратиться к точкам других:

  • dlamblin говорит: "Я никогда не чувствовал, что есть что-то особенное в компиляции против интерпретации, которая предлагала динамическую над статической типизацией.- Ну, тут ты сильно ошибаешься. Сборник динамические языки очень сложны. Есть в основном eval оператор для рассмотрения, который широко используется в Javascript и Ruby. phc компилирует PHP раньше времени, но нам все еще нужен интерпретатор времени выполнения для обработки evals. eval также не может быть проанализирован статически в оптимизирующем компиляторе, хотя есть классная техника если вам не нужна разумность.

  • на ответ дамблина на Андрей Заяц: вы могли бы, конечно, выполнить статический анализ в интерпретаторе, и найти ошибки до время выполнения, что именно то, что Haskell's ghci делает. Я ожидаю, что стиль интерпретатора, используемого в функциональных языках, требует этого. дламблин, конечно, прав, говоря, что анализ не является частью интерпретации.

  • ответ Эндрю Хэйра основывается на неправильном предположении вопрошающих, и аналогично имеет вещи неправильный путь вокруг. Тем не менее, он поднимает интересный вопрос: "насколько сложен статический анализ динамических языков?". Очень сильно. В принципе, вы получите докторскую степень за описание того, как это работает, что я и делаю. Также см. предыдущий пункт.

  • самый правильный ответ до сих пор-это Иво Ветцель. Однако точки, которые он описывает, могут обрабатываться во время выполнения в компиляторе, и многие компиляторы существуют для Lisp и Scheme, которые имеют этот тип динамической привязки. Но да, ее хитрый.


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

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


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

представьте себе следующий сценарий (в Python):

import random
foo = 1

def doSomeStuffWithFoo():
    global foo
    foo = random.randint(0, 1)

def asign():
    global foo
    if foo == 1:
        return 20
    else:
        return "Test"


def toBeStaticallyAnalyzed():
    myValue = asign()

    # A "Compiler" may throw an error here because foo == 0, but at runtime foo maybe 1, so the compiler would be wrong with its assumption
    myValue += 20


doSomeStuffWithFoo() # Foo could be 1 or 0 now... or 4 ;)
toBeStaticallyAnalyzed()

Как вы можете надеяться увидеть, компилятор не будет иметь никакого смысла в этой ситуации. Остро это может предупредить вас о возможности того, что" myValue " может быть что-то еще, кроме числа. Но тогда в JavaScript это потерпит неудачу, потому что если "myValue" является строкой, 20 будет имплицитно преобразован в строку, следовательно, никакой ошибки не произойдет. Так что вы можете получить тысячи бесполезных предупреждений повсюду, и я не думаю, что это намерение компилятора.

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

Итак, ваше решение как компилятор? - Исправьте это с помощью "try: except":)


компиляторы + статические типы = эффективный машинный код
Компиляторы + динамические типы = неэффективный машинный код

рассмотрим следующий псевдокод:

function foo(a, b) {
    return a+b
}

статический язык сможет знать (путем объявления или вывода), что a и b являются целыми числами, и будет компилироваться до

%reg = addi a,b

или что-то подобное, во всяком случае.

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

%reg1 = typeof a
beq %reg1, int, a_int_case
beq %reg1, float, a_float_case
beq %reg1, string, a_string_case

label a_int_case
%reg1 = typeof b
beq %reg1, int, a_int_b_int_case
beq %reg1, float, a_int_b_float_case
beq %reg1, string, a_int_b_string_case

label a_int_b_int_case
%out = addi a,b
goto done

label a_int_b_float_case
%tmp = mkfloat a
%out = addf %tmp,b
goto done

... Etc. I can't finish

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

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

(компиляторы Just-in-time фактически имеют информацию о типе и могут компилироваться вплоть до один оператор. Они на самом деле имеют больше информации, чем системы статического типа, и теоретически могут сделать даже лучше. Все ассемблеры моделируются; любое сходство с реальным кодом,который может работать на реальной машине, является чисто случайным.)


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

Я думаю, ясно, что обе стороны смотрят друг на друга и думают: "в этом есть некоторые преимущества."В нескольких приложениях легче получить некоторую гибкость динамического типа, в то время как может быть проще поддерживать что-то статически типизированное и принудительное.

Я не согласен с Андрей Зайцев объяснение хотя. Хотя чисто интерпретируемый язык должен был бы добавить шаг предварительной обработки и, следовательно, не быть чисто интерпретирован, чтобы предупредить программиста перед выполнением статических ошибок ввода, это не исключает возникновения ошибки типа во время выполнения. Таким образом, отсутствие компиляции не означает, что может произойти проверка статического типа. Но с момента получения ошибки типа в время выполнения не так полезно, как получение его при компиляции или во время предполетной проверки, я вижу, как "преимущество" статического ввода в этой ситуации может показаться более неприятным и, таким образом, быть выброшено в пользу преимуществ динамического ввода.

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

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


динамически типизированные интерпретируемые языки дают вам больше свободы в том, как вы программируете. Это позволяет осуществлять метапрограммирование. Он позволяет создавать переменные во время выполнения. Позволяет создавать анонимные хэши и анонимные массивы в любой момент времени во время выполнения без предварительного объявления чего-либо перед рукой. Это позволяет неопределенную информацию, чтобы быть inputed в хэш, никогда не объявляя все ключи заранее. Вы можете иметь подпрограммы, созданные из неопределенный случайный ввод. Вы также можете кормить программный код, который можно запускать динамически. Интерпретируемые языки освобождают цепочки, из которых ограничивается программирование в целом. Вы ограничены тем, что вы вводите в исходный файл со статически типизированными языками. Вы можете сделать больше с помощью less на динамически типизированном языке.

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

интерпретируется языки excel в динамической среде. Если вы можете интерпретировать новый код/информацию во время выполнения, то почему бы нет. Если вы действительно хороши в динамическом программировании, вы можете создать код, который может создавать переменные и хэши, никогда не печатая все. Вы можете резко сократить количество строк, если работаете с огромным количеством данных. Вы можете использовать Дампер данных для распечатки всей информации, поскольку интерпретируемые языки обычно отслеживают тип переменных во время выполнения чтобы это было возможно. Вы не можете сделать это в barebones c++. Только C++ и C знает, что происходит во время компиляции. После этого вы сами по себе, если вы не реализуете что-то самостоятельно.

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

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

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

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


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

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

Если программист хочет, он всегда может утверждать, что переменная содержит значение данный тип (например, при назначении). Нет смысла встраивать его в язык. Конечно, это не тот тип управления, который у вас есть для скомпилированных языков.

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

с другой стороны. Знаете ли вы динамически типизированный скомпилированный (статически, а не JIT) язык?