Является ли мое понимание систем типов правильными?

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

Статическое/динамическое различие кажется довольно четким:

  • Статически типизированные langauges присваивают каждой переменной, полю и параметру тип, а компилятор предотвращает назначение между несовместимыми типами. Примеры: C, Java, Pascal.
  • Динамически типизированные языки рассматривают переменные как универсальные бункеры, которые могут содержать все, что угодно - типы проверяются (если вообще) только во время выполнения, когда вы фактически выполняете операции над значениями, а не когда вы их назначаете, Примеры: Smalltalk, Python, JavaScript.
  • Вывод типа позволяет статически типизированным языкам выглядеть (и иметь некоторые из преимуществ) динамически типизированных, вызывая типы из контекста, так что вам не нужно объявлять их больше всего время - но в отличие от динамических языков, вы не можете используйте переменную, чтобы сначала сохранить строку, а затем назначить ей целое число. Примеры: Haskell, Scala

Я гораздо менее уверен в сильном/слабом различии, и я подозреваю, что он не очень четко определен:

  • Сильно типизированные языки присваивают каждому значению времени выполнения тип и разрешают только операции, которые определены для этого типа, в противном случае существует явная ошибка типа.
  • На слабо типизированных языках нет проверок типа времени выполнения - если вы попытаетесь выполнить операцию над значением, которое оно не поддерживает, результаты непредсказуемы. Это может на самом деле сделать что-то полезное, но, скорее всего, вы получите поврежденные данные, сбой или некоторая недокопимая вторичная ошибка.
  • Кажется, что существует как минимум два разных типа слабо типизированных языков (или, возможно, континуум):
    • В C и ассемблере значения представляют собой в основном ведра бит, поэтому все возможно, и если вы получите компилятор для разыменования первых 4 байтов строки с нулевым завершением, вам лучше надеяться, что она приведет куда-нибудь, где не будет юридической машины код.
    • PHP и JavaScript также обычно считаются слабо типизированными, но не считают значения непрозрачными ведрами; однако они будут выполнять неявные преобразования типов.
  • Но эти неявные преобразования, по-видимому, применяются в основном к переменным string/integer/float - действительно ли это требует классификации как слабо типизированной? Или есть другие проблемы, когда эта система типов языков может обмануть ошибки?

Ответ 1

Я гораздо менее уверен в сильном/слабом различии, и я подозреваю, что он не очень четко определен.

Вы правы: это не так.

Это то, что Бенджамин К. Пирс, автор языков типов и программирования, а также языки и языки программирования и программирования, должен сказать:

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

Luca Cardelli, в своей статье Typeful Programming, определяет это как отсутствие необработанных ошибок типа времени выполнения. Тони Хоар называет это то же свойство "безопасность". Другие документы называют "безопасностью типа" или просто "безопасностью".

Mark-Jason Dominus написал об этом несколько лет назад в группе comp.lang.perl.moderated, в обсуждение того, был ли Perl строго типизирован. В этом заявлении он утверждает, что всего за несколько часов исследований он смог найти 8 разных, иногда противоречивых определений, в основном из уважаемых источников, таких как учебники в колледже или рецензируемые статьи. В частности, эти тексты содержали примеры, которые призваны помочь студентам различать сильно и слабо типизированные языки, и в соответствии с этими примерами C строго типизирован, C слабо типизирован, С++ строго типизирован, С++ слабо типизирован, Lisp строго типизирован, Lisp слабо типизирован, Perl строго типизирован, Perl слабо типизирован. (Это устраняет путаницу?)

Единственное определение, которое я видел последовательно, следующее:

  • строго типизирован: мой язык программирования
  • слабо типизированный: ваш язык программирования

Ответ 2

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

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

Хотя я думаю, что вы понимаете концепцию, ваши пули не дают понять, что вывод типа - это просто частный случай статического ввода. В большинстве языков с типом вывода аннотации типов являются необязательными, но не обязательно во всех контекстах. (Пример: подписи в ML.) Продвинутые системы статического типа часто дают вам компромисс между аннотациями и выводами; например, в Haskell вы можете вводить полиморфные функции более высокого ранга (для всех слева от стрелки), но только с аннотациями. Итак, если вы хотите добавить аннотацию, вы можете заставить компилятор принять программу, которая будет отклонена без аннотации. Я думаю, что это волна будущего в выводе типа.

Идеи "сильного" и "слабого" набора текста я бы охарактеризовал как не полезный, потому что у них нет универсально согласованного технического смысла. Сильная типизация обычно означает, что в системе типов нет лазеек, тогда как слабая типизация означает, что система типов может быть подорвана (аннулирование каких-либо гарантий). Термины часто используются неправильно для обозначения статической и динамической типизации. Чтобы увидеть разницу, подумайте о C: язык проверяется типом во время компиляции (статическая типизация), но есть много лазеек; вы можете в значительной степени отличить значение любого типа к другому типу того же размера - mdash, в частности, вы можете свободно использовать типы указателей. Паскаль был языком, который был предназначен для строго типизированного, но лихо имел непредвиденную лазейку: вариантную запись без тега.

Реализации сильно типизированных языков часто приобретают лазейки с течением времени, обычно так, что часть системы времени выполнения может быть реализована на языке высокого уровня. Например, Objective Caml имеет функцию под названием Obj.magic, которая имеет эффект времени выполнения, просто возвращающий свой аргумент, но во время компиляции он преобразует значение любого типа в один из любого другого типа. Моим любимым примером является Modula-3, дизайнеры которого назвали конструкцию литья LOOPHOLE.

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

Ответ 3

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

В таких языках, как TCL и Bourne Shell, основным типом значения является строка. Доступны числовые операторы, которые неявно принудительно вводят входные значения из строкового представления и значений результата в строковое представление. Их можно рассматривать как примеры динамических, слабо типизированных языков.

Форт может быть примером статического, слабо типизированного языка. Язык не выполняет никакой проверки типа, и основной стек может содержать взаимозаменяемые указатели, целые числа, строки (обычно представляемые как две ячейки, начало и длина). Непоследовательное использование операторов может привести к интересному или неуказанному поведению. Типичные реализации Forth предоставляют отдельный стек для чисел с плавающей запятой.

Ответ 4

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

Ответ 5

Кажется, что существует как минимум два разных типа слабо типизированных языков (или, возможно, континуум):

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

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

Ответ 6

Я считаю, что сильный/слабый является понятием неявного преобразования, и хорошим примером является добавление строки и числа. На строго типизированном языке преобразование не произойдет (по крайней мере, на всех языках, о которых я могу думать), и вы получите сообщение об ошибке. Слабо типизированные языки, такие как VB (с Option Explicit Off), и Javascript попытается применить один из операндов к другому типу.

В VB.Net с опцией Strict Off:

    Dim A As String = "5"
    Dim B As Integer = 5
    Trace.WriteLine(A + B) 'returns 10

С опцией Strict On (превращение VB в строго типизированный язык) вы получите ошибку компилятора.

В Javascript:

    var A = '5';
    var B = 5;
    alert(A + B);//returns 55

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

Ответ 7

Хм, тоже не знаю, но я хотел упомянуть С++ и его неявные конверсии (неявные конструкторы). Это может быть также пример слабого набора текста.

Ответ 8

Я согласен с другими, которые говорят: "Здесь, похоже, нет жесткого и быстрого определения". Мой ответ, как правило, основан на том, сколько веревок язык дает вам типы WRT. Если вы можете в значительной степени подделывать все, что захотите, то это слабо. Если это действительно не позволяет вам попасть в неприятности, даже если вы этого захотите, это сильно.

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