Постепенная типизация: «Почти каждый язык со статической системой типов также имеет динамическую систему типов»

20

Это требование по Aleks Бромфилд гласит:

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

Это действительная претензия? Я понимаю, что с классами Reflection или Loading во время выполнения Java выглядит примерно так - но можно ли распространить эту идею «постепенной типизации» на большое количество языков?

Hawkeye
источник
Я не специалист по языку, но немногие, кто сразу вспоминает, что я не верю, имеют динамические типы (изначально я не говорю, что вы не можете что-то совместить в них) - Fortran, Ada, Pascal, Cobol
mattnz
4
Я эксперт по языку, и я не уверен, на что претендует этот парень. «static» и «dynamic» являются неправильными и обычно указывают время проверки / анализа типа (во время компиляции или во время выполнения). Некоторые языки согласовывают оба (например, запрещая операции с неподдерживаемыми типами во время компиляции и вызывая исключения, такие как ClassCastException во время выполнения), и это может быть то, что он имеет в виду. Если это так, это правда, что C обычно не выполняет проверку типа во время выполнения. Сказать язык не имеет "динамической системы типов", не имеет смысла.
Тьяго Сильва

Ответы:

37

Оригинальный твитер здесь. :)

Прежде всего, я несколько удивлен / шокирован тем, что мой твит воспринимается так серьезно! Если бы я знал, что это будет широко распространено, я бы потратил бы больше 30 секунд на его написание!

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

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

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

Это неплохая вещь. Это просто наблюдение, что есть много интересных свойств, которые мы бы хотели, чтобы наши языки применяли, и что мы не знаем, как проверять статически. И это напоминание о том, что различия, такие как «статические типы» и «динамические типы», далеко не так очевидны, как некоторые люди могут поверить. :)

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

Алекс Бромфилд
источник
9
«Это просто наблюдение, что есть много интересных свойств, которые мы бы хотели, чтобы наши языки обеспечивали, и что мы не знаем, как проверять статически». - Ну, дело не только в том, что мы не знаем, как это сделать. «Ли эта программа привал для этого входа» является интересным свойством , что мы не просто не знаю , как проверить, но на самом деле мы делаем знать это невозможно проверить.
Йорг Миттаг
«Другие примеры включают арифметическое переполнение, проверку границ массива и проверку нуля». Просто обратите внимание, что, хотя есть несколько языков, которые проверяют эти свойства в системе типов, даже в большинстве языков с динамической типизацией они обычно являются признаком значений , а не типов. («Нулевая» проверка - общая черта систем статического типа.)
porglezomp
Там является динамический тип системы , и статический тип системы . Даже если ни один из них не применяется принудительно, они все еще там, описывая, что правильно и что является ошибкой. Язык / реализация может или не может проверить любой из них. Кстати, статическая и динамическая система типов должна быть согласованной, но это не так по определению .
Элазар
Каждый язык имеет динамическую систему типов, которая представляет собой набор правил, запрещающих выполнение определенных операций.
Элазар
7

Ну да. Вы можете иметь сумки с имуществом на любом статически типизированном языке. Синтаксис будет ужасным, и в то же время вы получите все недостатки динамически типизированной системы. Таким образом, в действительности нет никаких преимуществ, если компилятор не позволяет использовать более приятный синтаксис, как dynamicэто делает C # with .

Кроме того, вы можете сделать это довольно легко в C тоже.

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

Упоминание рефлексии не рассказывает всей истории, потому что рефлексия не позволяет вам изменить существующую структуру данных. Вы не можете добавить новое поле в класс или структуру в C, C ++, Java или C #. В динамических языках добавление новых полей или атрибутов в существующие классы не только возможно, но на самом деле довольно распространено.

Например, посмотрите на Cython , компилятор Python-to-C. Он создает статический C-код, но система типов по-прежнему сохраняет свою динамическую природу. C - статически типизированный язык, но он может поддерживать динамическую типизацию из Python.

Euphoric
источник
Технически, вы можете сделать это в C # начиная с версии 4 ExpandoObject, хотя это очень многообещающий процесс, во многом в отличие от JavaScript или Ruby. Тем не менее, вы сделали очень важный вывод: «Утиная печать» (что на самом деле имеют в виду 99% разработчиков, когда говорят «динамически печатать») и рефлексия - это совсем не одно и то же.
Aaronaught
Могу ли я также добавить, что в Python нет настоящей утки. У него просто есть несколько хуков, чтобы вы могли «реализовать свой собственный» (есть магический метод, который может возвращаться True, чтобы сказать «этот сумасшедший объект является экземпляром класса, который я определяю»). Насколько я понимаю, у OCaml есть эта особенность, но я на самом деле не знаю.
vlad-ardelean
6

Динамические языки являются статическими языками . То, что обычно называют «динамической типизацией», на самом деле представляет собой особый случай статической типизации - случай, когда вы ограничиваете себя только одним типом. В качестве мысленного эксперимента представьте, что вы пишете программу на Java или C #, используя только Objectпеременные / поля / параметры, и преобразуете код непосредственно перед вызовом любого метода. Было бы точнее называть такие языки, как Python или Javascript, «единой формой». (Это утверждение, вероятно, смущает / беспокоит многих людей, учитывая, что такая программа на Java или C # будет использовать много подтипов, но это потому, что средний язык ООП объединяет типы и классы. Для получения более подробной информации прочтите сообщение в блоге.)

Обратите внимание, что даже C имеет «динамическую» типизацию - вы можете привести любой указатель к указателю void(и, если мне не charизменяет память ) и обратно. И обратите внимание, также, что там нет проверки во время выполнения; если вы ошибаетесь, наслаждайтесь своим неопределенным поведением!

Doval
источник
Но актерский состав сделан статически. Я не вижу, как это пример динамической типизации.
Оса
@osa Только потому, что код говорит, String foo = (String) barчто это не означает, что barэто на самом деле String. Вы можете точно знать это только во время выполнения, поэтому я не вижу, как приведение происходит «статически».
Довал
Я не согласен с этим. По крайней мере, в Javascript вы можете добавлять новые методы и свойства к объектам во время выполнения. В C # вам нужно явно использовать dynamicобъект для этого. Если вы попытаетесь добавить свойство к object... ну, вы не сможете.
Артуро Торрес Санчес
3

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

void horribleJava(List untypedList) {
  for (Object o : untypedList)
    ((SpecificType) o).frobnicate();
}

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

void goodJava(List<SpecificType> typedList) {
  for (SpecificType o : typedList) {
    o.forbnicate();
  }
}

В C значения (и, в частности, указатели) не сохраняют свой тип во время выполнения - каждый указатель эквивалентен a void *. Вместо этого переменные и выражения имеют тип. Чтобы добиться динамической типизации, вы должны носить информацию о типе самостоятельно (например, как поле в структуре).

Амон
источник
1
Я не думаю, что бросок считается динамической типизацией в каком-либо действительно практическом смысле. Он все еще требует знания типа во время компиляции, он просто откладывает фактическую проверку до времени выполнения. Вы не можете вызвать frobnicateметод здесь без предварительного знания о SpecificType.
Aaronaught
2
@Aaronaught Но это динамическая типизация , как только мы отложили проверку типа до времени выполнения. Обратите внимание, что оба моих примера используют номинативную типизацию, которая требует определенного имени типа. Вы думаете о структурном наборе текста , например о типе утки, который требует наличия какого-либо метода. Оси структурные и номинативные и статические и динамические типизации ортогональны друг другу (Java является номинативной и в основном статической; ML и Go являются структурными и статическими; Perl, Python и Ruby (в основном) являются структурными и динамическими).
am
Как я уже говорил в своем последнем комментарии, это теоретическое различие, которое никому из программистов, которого я когда-либо встречал, на самом деле не волнует. Вы можете абразивно утверждать, что люди используют неправильную терминологию (и на самом деле кажется, что оригинальный твитер был предназначен именно для такого рода измышлений), но для людей, которые на самом деле находятся в траншеях, динамическая типизация = типизированная утка. На самом деле это определение настолько распространено, что такие языки, как C #, фактически его кодифицировали (то есть с dynamicключевым словом). Приравнивание статического к времени компиляции и динамического к времени выполнения в основном просто мутит воду.
Aaronaught
@Aaronaught: если кто-то приводит к интерфейсу, и если классы, которые реализуют метод с намеченным значением, последовательно реализуют один и тот же интерфейс, то можно сказать, что по существу это будет типизацией утки во время выполнения. Хотя некоторые могут утверждать, что для «утиной типизации» следует использовать только имя метода, я думаю, что было бы более целесообразно рассматривать «реальное» имя метода как имя интерфейса плюс имя метода. В противном случае, должен [1,2].Add([3,4])уступить [1,2,3,4], [1,2,[3,4]]или [4,6]?
суперкат
@supercat: Ничего из вышеперечисленного не должно произойти, потому что Addв массиве нет метода, принимающего массив, потому что такой метод был бы неоднозначным. Утиная печать не освобождает вас от написания понятных типов и функций.
Aaronaught
2

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

Я полагаю, что текст ссылается на то, что даже если типы проверяются статически, они также проверяются во время выполнения, то есть динамически. Вы правильно упомянули Java Reflection; отражение происходит только во время выполнения, и среда выполнения Java (JVM) фактически выполняет проверку типов при использовании отражения, что в основном означает динамическую проверку типов.

m3th0dman
источник
Тогда это не правильно. В C ++, Pascal, Fortran - в любых скомпилированных языках - типы проверяются только статически, а не динамически (если вы не используете dynamic_cast). Вы можете использовать указатели для записи произвольных вещей в память, и никто не будет знать типы. Таким образом, статическая типизация означает ТОЛЬКО ПРОВЕРКА СТАТИЧЕСКИ, тогда как динамическая типизация означает ТОЛЬКО ПРОВЕРКУ ПРИ РАБОТЕ.
Оса
-1

Исключение неверно: C также имеет важную динамическую систему типов. Он просто не проверяет это («C строго типизирован, слабо проверен»). Например, обработка структуры как double( reinternpret_cast-стиля) приводит к неопределенному поведению - ошибка динамического типа.

Элазар
источник
(Для тех, кто проголосовал против - комментарий @Thiago Silva говорит об одном и том же)
Elazar