Языки динамического типа и языки статического типа

Каковы преимущества и ограничения динамических языков типов по сравнению со статическими языками типов?

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

9 ответов

Решение

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

Эрик Мейер и Питер Дрейтон из Microsoft рассказали об этом: "Статическая типизация там, где это возможно", "Динамическая типизация при необходимости: конец холодной войны между языками программирования".

Сторонники статической типизации утверждают, что преимущества статической типизации включают более раннее обнаружение ошибок программирования (например, предотвращение добавления целого числа в логическое значение), лучшую документацию в форме сигнатур типов (например, включение числа и типов аргументов при разрешении имен), больше возможности для оптимизации компилятора (например, замена виртуальных вызовов прямыми вызовами, когда точный тип получателя известен статически), повышенная эффективность времени выполнения (например, не все значения должны содержать динамический тип), и лучший опыт разработчика во время разработки (например, знание Тип получателя, IDE может представить раскрывающееся меню всех применимых членов). Фанатики статической типизации пытаются заставить нас поверить, что "программы с хорошей типизацией не могут ошибаться". Хотя это, безусловно, звучит впечатляюще, это довольно бессмысленное утверждение. Статическая проверка типов - это абстракция поведения вашей программы во время компиляции, и, следовательно, она обязательно является только частично правильной и неполной. Это означает, что программы по-прежнему могут работать неправильно из-за свойств, которые не отслеживаются средством проверки типов, и что существуют программы, которые, хотя они и не могут работать неправильно, не могут быть проверены по типу. Стремление сделать статическую типизацию менее частичной и более полной приводит к тому, что системы типов становятся чрезмерно сложными и экзотическими, о чем свидетельствуют такие понятия, как "фантомные типы" [11] и "шаткие типы" [10]. Это похоже на попытку пробежать марафон с мячом и цепью, привязанными к вашей ноге, и с триумфом кричать, что вы почти сделали это, даже если вы выпрыгнули после первой мили.

Сторонники языков с динамической типизацией утверждают, что статическая типизация является слишком жесткой, и что мягкость динамических языков делает их идеально подходящими для прототипирования систем с изменяющимися или неизвестными требованиями или которые взаимодействуют с другими системами, которые изменяются непредсказуемо (интеграция данных и приложений). Конечно, динамически типизированные языки необходимы для работы с действительно динамичным поведением программы, таким как перехват методов, динамическая загрузка, мобильный код, отражение во время выполнения и т. Д. В статье, посвященной написанию сценариев [16], Джон Оустерхаут утверждает, что статически типизированные системы языки программирования делают код менее пригодным для повторного использования, более многословным, не более безопасным и менее выразительным, чем языки сценариев с динамической типизацией. Этот аргумент буквально опровергается многими сторонниками динамически типизированных языков сценариев. Мы утверждаем, что это заблуждение и относится к той же категории, что и утверждение, что суть декларативного программирования заключается в устранении присваивания. Или, как говорит Джон Хьюз [8], логически невозможно сделать язык более мощным, опуская функции. Отстаивая тот факт, что откладывать все проверки типов до времени выполнения - это хорошо, мы играем в страусиную тактику с тем фактом, что ошибки должны быть обнаружены как можно раньше в процессе разработки.

Системы статического типа стремятся устранить определенные ошибки статически, проверяя программу, не запуская ее, и пытаясь доказать правильность в определенных отношениях. Некоторые системы типов способны отлавливать больше ошибок, чем другие. Например, C# может устранить исключения нулевого указателя при правильном использовании, тогда как Java не имеет такой возможности. У Twelf есть система типов, которая фактически гарантирует, что доказательства прекратятся, "решая" проблему остановки.

Однако ни одна система типов не является идеальной. Чтобы устранить определенный класс ошибок, они также должны отклонить определенные совершенно допустимые программы, которые нарушают правила. Вот почему Twelf на самом деле не решает проблему остановки, он просто избегает ее, выбрасывая большое количество совершенно достоверных доказательств, которые случайно заканчиваются странным образом. Аналогично, система типов Java отвергает Clojure PersistentVector реализация за счет использования гетерогенных массивов. Он работает во время выполнения, но система типов не может это проверить.

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

Субъективно мне нравится статическая типизация. Правильно реализованная (подсказка: не Java), система статических типов может оказать огромную помощь в устранении ошибок до их сбоя в производственной системе. Динамически типизированные языки, как правило, требуют больше модульного тестирования, что в лучшие времена утомительно. Кроме того, статически типизированные языки могут иметь определенные особенности, которые либо невозможны, либо небезопасны в динамических системах типов (на ум приходят неявные преобразования). Это все вопрос требований и субъективного вкуса. Я бы не стал собирать следующий Eclipse в Ruby больше, чем пытался написать скрипт резервного копирования в Assembly или исправить ядро ​​с помощью Java.

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

Последнее замечание: не беспокойтесь о производительности при сравнении статических и динамических типов. Современные JIT, такие как V8 и TraceMonkey, опасно приближаются к производительности статического языка. Кроме того, тот факт, что Java на самом деле компилируется в динамически промежуточный язык, должен быть подсказкой о том, что в большинстве случаев динамическая типизация не является огромным фактором снижения производительности, как это делают некоторые люди.

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

Статические типы являются ограничением грамматики языка. Можно сказать, что строго типизированные языки не являются контекстно-свободными. Простая истина в том, что становится неразумно выражать язык разумно в контекстно-свободных грамматиках, которые не обрабатывают все свои данные просто как битовые векторы. Системы статических типов являются частью грамматики языка, если таковые имеются, они просто ограничивают ее больше, чем могла бы сделать не зависящая от контекста грамматика, поэтому грамматические проверки происходят в два прохода над источником. Статические типы соответствуют математическому понятию теории типов, теория типов в математике просто ограничивает законность некоторых выражений. Мол, не могу сказать 3 + [4,7] в математике это из-за теории типов этого.

Таким образом, статические типы не являются способом "предотвращения ошибок" с теоретической точки зрения, они являются ограничением грамматики. Действительно, при условии, что +, 3 и интервалы имеют обычные заданные теоретические определения, если мы удалим систему типов 3 + [4,7] имеет довольно четко определенный результат, это множество. "ошибок типа времени выполнения" теоретически не существует, практическое использование системы типов состоит в том, чтобы предотвращать операции, которые для людей не имели бы смысла. Конечно, операции - это всего лишь сдвиг и манипулирование битами.

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

1: доказать, что ошибки типа будут происходить в программе
2: доказать, что они не будут происходить в программе

Может показаться, что я противоречу себе. Но что делает средство проверки типов C или Java, так это то, что оно отклоняет программу как "неграмотную", или как она называет это "ошибкой типа", если она не может преуспеть в 2. Она не может доказать, что она не произойдет, это не значит, что они не произойдут, просто это не может доказать это. Вполне возможно, что программа, у которой не будет ошибки типа, отклоняется просто потому, что она не может быть доказана компилятором. Простой пример if(1) a = 3; else a = "string"; Конечно, поскольку это всегда так, ветвь else никогда не будет выполняться в программе, и ошибки типа не должно произойти. Но он не может доказать эти случаи в общем виде, поэтому он отклонен. Это главная слабость многих статически типизированных языков: если вы защищаете себя от себя, вы также обязательно защищены в тех случаях, когда вам это не нужно.

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

Другое преимущество статической типизации состоит в том, что типы известны во время компиляции, и, таким образом, компилятор может использовать это. Если мы в Java делаем "string" + "string" или же 3 + 3, и то и другое + Токены в тексте в конце представляют собой совершенно разные операции и данные, компилятор знает, какой из них выбрать.

Теперь я собираюсь сделать очень спорное утверждение здесь, но иметь со мной: "динамическая типизация" не существует.

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

Почему у них нет типов? Поскольку каждая операция определена и разрешена для каждого операнда, что именно является "ошибкой типа времени выполнения"? Это из теоретического примера чисто побочный эффект. Если делать print("string") которая печатает строку является операцией, то так length(3) Бывший имеет побочный эффект написания string к стандартному выводу, последний просто error: function 'length' expects array as argument., вот и все. С теоретической точки зрения нет такого понятия, как динамически типизированный язык. Они нетипизированы

Хорошо, очевидное преимущество "динамически типизированного" языка - выразительная сила, система типов - не что иное, как ограничение выразительной силы. И вообще, языки с системой типов действительно будут иметь определенный результат для всех тех операций, которые недопустимы, если система типов просто игнорируется, результаты просто не будут иметь смысла для людей. Многие языки теряют свою полноту по Тьюрингу после применения системы типов.

Очевидным недостатком является тот факт, что могут происходить операции, которые приводят к результатам, которые не имеют смысла для людей. Чтобы защититься от этого, динамически типизированные языки обычно переопределяют эти операции, вместо того, чтобы давать этот бессмысленный результат, они переопределяют его на наличие побочного эффекта выписывания ошибки и, возможно, остановки программы в целом. Это вовсе не "ошибка", фактически, языковая спецификация обычно подразумевает это, это такое же поведение языка, как и печать строки с теоретической точки зрения. Таким образом, системы типов заставляют программиста рассуждать о потоке кода, чтобы убедиться, что этого не происходит. Или, действительно, причина, по которой это происходит, также может быть полезна в некоторых моментах для отладки, показывая, что это вовсе не "ошибка", а четко определенное свойство языка. По сути, единственный остаток "динамической типизации", который есть в большинстве языков, защищает от деления на ноль. Вот что такое динамическая типизация: нет типов, нет больше типов, чем тот, что ноль отличается от всех других чисел. То, что люди называют "типом", - это просто еще одно свойство элемента данных, например длина массива или первый символ строки. И многие динамически типизированные языки также позволяют записывать такие вещи, как "error: the first character of this string should be a 'z'",

Другое дело, что динамически типизированные языки имеют тип, доступный во время выполнения, и обычно могут проверять его, справляться с ним и принимать решения. Конечно, в теории это ничем не отличается от доступа к первому символу массива и просмотра, что это такое. Фактически, вы можете создать свой собственный динамический C, просто используйте только один тип, например long long int, и используйте его первые 8 бит для хранения вашего "type" и соответственно написания функций, которые проверяют его и выполняют операции с плавающей запятой или целочисленным сложением. У вас есть статически типизированный язык с одним типом или динамический язык.

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

Как я уже отмечал, "статически типизированный" в общем случае означает случай 2, виновный до тех пор, пока не доказано невиновность. Но некоторые языки, которые вообще не выводят свою систему типов из теории типов, используют правило 1: Невинный до тех пор, пока его вина не доказана, что может быть идеальным гибридом. Так что, может быть, Typed Racket для вас.

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

Возможно, самое большое "преимущество" динамической типизации - это более мелкая кривая обучения. Нет системы типов для изучения и нетривиального синтаксиса для угловых случаев, таких как ограничения типов. Это делает динамическую типизацию доступной для гораздо большего числа людей и выполнимой для многих людей, для которых сложные системы статического типа недоступны. Следовательно, динамическая типизация завоевала популярность в контексте образования (например, Scheme/Python в MIT) и предметно-ориентированных языках для непрограммистов (например, Mathematica). Динамические языки также завоевали популярность в нишах, где они практически не конкурируют (например, Javascript).

Наиболее сжатые языки с динамической типизацией (например, Perl, APL, J, K, Mathematica) являются предметно-ориентированными и могут быть значительно более краткими, чем наиболее сжатые языки общего назначения со статической типизацией (например, OCaml) в нишах, для которых они были разработаны.,

Основными недостатками динамической типизации являются:

  • Ошибки типа во время выполнения.

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

  • Нет проверенной компилятором документации.

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

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

Из Artima's Typing: сильная и слабая, статическая и динамическая статья:

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

слабая типизация означает, что вы можете смешивать типы без явного преобразования

В статье Паскаля Костанзы " Динамическая и статическая типизация - анализ на основе шаблонов" (PDF) он утверждает, что в некоторых случаях статическая типизация более подвержена ошибкам, чем динамическая типизация. Некоторые статически типизированные языки вынуждают вас вручную эмулировать динамическую типизацию, чтобы сделать "правильную вещь". Это обсуждается в Lambda the Ultimate.

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

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

В статических и динамических языках есть много разных вещей. Для меня главное отличие в том, что в динамических языках переменные не имеют фиксированных типов; вместо этого типы привязаны к значениям. Из-за этого точный код, который выполняется, не определен до времени выполнения.

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

Это все о правильном инструменте для работы. Ни один не лучше в 100% случаев. Обе системы были созданы человеком и имеют недостатки. Извините, но мы сосем и делаем идеальные вещи.

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

Статическая типизация: языки, такие как Java и Scala, имеют статическую типизацию.

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

например int x; х = 10;

System.out.println (х);

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

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

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

Другие вопросы по тегам