Каковы преимущества безопасности системы типов?

47

В JavaScript: Хорошие части Дугласа Крокфорда он упоминает в своей главе о наследовании:

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

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

Каковы преимущества безопасности системы типов? Что отличает систему типов, которая позволяет обеспечить эти преимущества безопасности?

MistakesWereMade
источник
Я не уверен, что системы типов дают какие-либо преимущества для не скомпилированного языка, но, как долгосрочный пользователь скомпилированных языков, я обнаружил, что скомпилированные языки с тщательной проверкой типов эффективны в предотвращении многих видов неоднозначного, неопределенного или неполного кода от пройти этап «компиляции». Я думаю, вы могли бы сказать, что подсказки типов и система Lint ценны для веб-сценариев (JavaScript), и если это так, я уверен, что мы увидим их достаточно. Дарт кто-нибудь? Динамические языки, такие как Python, кажутся не хуже из-за отсутствия статической системы типов.
Уоррен Р
1
Сегодня мы понимаем, что типирование должно быть поведенческим, а не структурным. К сожалению, большинство современных языков программирования не имеют возможности утверждать поведение типа ( см. Этот вопрос для хорошего чтения). Это делает систему типов довольно бесполезной в большинстве случаев, особенно потому, что простые ошибки типов, ответы на которые упоминаются здесь, могут быть обнаружены умным линтером, который проверяет общие проблемы.
Бенджамин Грюнбаум
4
@BenjaminGruenbaum То, что вы описываете, уже существует в таких языках, как OCaml, статически. Это называется структурная типизация, на самом деле она довольно старая, номинальная типизация новее.
Jozefg
2
@BenjaminGruenbaum: ... Что !? Это очевидно не неразрешимо в статически типизированных языках, иначе написание компилятора для этих языков было бы невозможно.
BlueRaja - Дэнни Пфлюгофт
6
@BenjaminGruenbaum: Ваши комментарии являются ценными, и что работа интересна, но не подкрепляет ваше заявление , что «это , как правило , неразрешимо в статических языках , как Java тоже», так как это свидетельствует о том , что она является разрешимой в C #, и оставляет открытый вопрос о том, неразрешимо ли это в Java. (И в любом случае, IME, когда компилятор для статически типизированного языка не может решить, что что-то правильно напечатано, он отклоняет его (или не может его скомпилировать), поэтому неразрешимость - это скорее раздражение, а не дыра в типе. безопасность.)
ruakh

Ответы:

82

Системы типов предотвращают ошибки

Тип системы устраняет нелегальные программы. Рассмотрим следующий код Python.

 a = 'foo'
 b = True
 c = a / b

В Python эта программа не работает; это исключение. На таких языках, как Java, C #, Haskell , что угодно, это даже не легальная программа. Вы полностью избегаете этих ошибок, потому что они просто невозможны в наборе программ ввода.

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

 Definition divide x (y : {x : integer | x /= 0}) = x / y

Теперь система типов гарантирует отсутствие ошибок деления на 0.

Какие ошибки

Вот краткий список того, что системы типов ошибок могут предотвратить

  1. Ошибки вне диапазона
  2. SQL-инъекция
  3. Обобщая 2, много вопросов безопасности (для чего проверка на зараженность в Perl )
  4. Внеочередные ошибки (забыл вызвать init)
  5. Принудительное использование подмножества значений (например, только целые числа больше 0)
  6. Гнусные котята (Да, это была шутка)
  7. Ошибки с потерей точности
  8. Ошибки программной транзакционной памяти (STM) (это требует чистоты, которая также требует типов)
  9. Обобщая 8, контролируя побочные эффекты
  10. Инварианты над структурами данных (сбалансировано ли двоичное дерево?)
  11. Забыть исключение или выбросить неправильное

И помните, это также во время компиляции . Не нужно писать тесты со 100% покрытием кода, чтобы просто проверять ошибки типов, компилятор сделает это за вас :)

Пример: типизированное лямбда-исчисление

Хорошо, давайте рассмотрим простейшую из всех систем типов, просто типизированное лямбда-исчисление .

В основном есть два типа,

Type = Unit | Type -> Type

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

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

Обход в динамические типы

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

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

TLDR

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

jozefg
источник
25
+1 за компиляцию как эквивалент написания множества тестов.
Дэн Нили,
3
@DanNeely Это просто для иллюстрации того, что в динамическом языке вам нужно использовать все части кода, чтобы отловить ошибки, которые система типов проверяет бесплатно. А в зависимо типизированном языке вы можете полностью заменить тесты типами. Много раз вам нужно доказать дополнительные теоремы правильности, хотя
jozefg
3
Если ваша система типов доказала, что ваша программа должна завершиться, это (вероятно) сделано, доказав, что она вычисляет примитивно-рекурсивную функцию. Полагаю, это круто, но гораздо менее интересный класс сложности, чем тот, который может решить настоящая Машина Тьюринга. (Это не значит, что промежуточные значения не велики; функция Аккермана примитивно-рекурсивна…)
Донал Феллоуз
5
@DonalFellows Функция Аккермана не является примитивно-рекурсивной, хотя она является полностью вычислимой функцией.
Таймон
4
@sacundim Точно, такие языки, как agda, допускают необязательную проверку целостности, а в тех редких случаях, когда вам нужна произвольная рекурсия, вы можете задать хороший вопрос, это довольно удобная система.
Jozefg
17

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

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

MSalters
источник
15

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

Например, в JavaScript и Python следующая проблема будет часто обнаруживаться только во время выполнения - и в зависимости от качества / редкости тестирования условия могут фактически перейти в рабочую среду:

if (someRareCondition)
     a = 1
else
     a = {1, 2, 3}

// 10 lines below
k = a.length

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

Евгений
источник
5
И умный линтер в среде IDE, такой как WebStorm JavaScript, может сказать: «Возможна неопределенная ссылка на a.length для числа a». Это не дано нам, имея явную систему типов.
Бенджамин Грюнбаум
4
1. Статически не сильно 2. @BenjaminGruenbaum Да, но это можно сделать, преследуя график заданий в фоновом режиме, думая об этом, как о мини-переводчике, пытающейся выяснить, куда идут дела. Гораздо сложнее, чем когда типы дают вам это бесплатно
jozefg
6
@BenjaminGruenbaum: не путайте неявное / явное с сильным / слабым. Например, в Haskell есть невероятно сильная система типов, которая стыдит большинство других языков, но благодаря определенным решениям, принятым при проектировании языка, он также способен к почти полностью универсальному выводу типов, что делает его строго неявным типизированным языком с поддержкой явной типизации. (Это вы должны использовать, потому что вывод типов может быть
выведен
6
«Строго типизированный язык заставит вас явно указать, что a является массивом». Это неправильно. Python строго типизирован и не требует этого. Даже в статически и строго типизированных языках этого не требуется, если они поддерживают вывод типов (а в настоящее время большинство основных языков поддерживают, по крайней мере, частично).
Конрад Рудольф
1
@BenjaminGruenbaum: Ах, достаточно справедливо. Тем не менее, будут случаи, когда ни один JS-статический анализатор не сможет выполнить те же проверки типов, которые предоставляет язык со строгой типизацией, и решить, что в общем случае требуется решить проблему остановки. Haskell пришлось принять несколько дизайнерских решений, чтобы достичь почти 100% -ного вывода типа, а C # / Scala не может вывести все. Конечно, в этих случаях это не имеет значения, потому что вы можете просто явно указывать типы - в Javascript это означает, что даже самый лучший статический анализатор больше не сможет проверять ваш код.
Фоши
5

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

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

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

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

GlenPeterson
источник
Это продает динамическую типизацию коротко, не говоря уже о ее основных преимуществах (упомянутые удобны относительно неважно). Также кажется, что в модульных тестах есть что-то странное - да, их сложно делать и они имеют цену, и это относится и к статически типизированным языкам. Что это пытается сказать? В нем также не упоминаются ограничения (конструктивно) существующих систем типов, как в том, что они могут выражать, так и в том, какие ошибки они могут отлавливать.
@MattFenwick Каковы основные преимущества динамического набора текста?
ГленПетерсон
Типичные системы статического типа отклоняют многие хорошо типизированные программы. ( альтернатива ) (Кстати, моя критика была направлена ​​только на 3-й и 4-й абзацы.)
4

Введение

Безопасность типов может быть достигнута с использованием статически типизированных (скомпилированных, статических проверок типов) и / или языков выполнения (оцененных, динамических проверок типов). Согласно Википедии, система ... сильного типа описывается как система, в которой нет возможности неконтролируемой ошибки типа времени выполнения (Эд Лука Карделли). Другими словами, отсутствие непроверенных ошибок времени выполнения называется безопасностью или безопасностью типов ... »

Безопасность - статическая проверка типа

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

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

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

Есть преимущество в использовании статически типизированных языков для эффективности и скорости выполнения. Преимущества среды выполнения заключаются в отсутствии необходимости определять типы во время выполнения.

Безопасность - проверка типа во время выполнения

Erlang, например, является декларативным языком, динамически проверяемым типом языка, который работает на виртуальной машине. Erlang-код может быть скомпилирован байтово. Erlang считается, пожалуй, самым важным критическим, отказоустойчивым языком, доступным, и сообщается, что Erlang имеет надежность девять 9 (99,999999% или не более 31,5 мсек в год).

Некоторые языки, такие как Common Lisp, не имеют статической типизации, но при желании можно объявить типы, что может помочь повысить скорость и эффективность. Также следует отметить, что многие из наиболее широко используемых интерпретируемых языков, таких как Python, находятся под циклом оценки и написаны на статически типизированных языках, таких как C или C ++. И Commom Lisp, и Python считаются безопасными по определению выше.

AsymLabs
источник
2
Я возражаю против "сильно типизированных". Вы имеете в виду статически типизированный. Сильно тип не несет в себе почти никакого смысла, он обычно говорит: «Мне нравится эта система типов»
jozefg
@ jozefg Хорошая мысль. Я исправлю этот пост.
AsymLabs
3
Также бесполезно говорить интерпретируемый язык ... о реализации языка да, но не о самом языке. Любой язык может быть интерпретирован или скомпилирован. И даже после редактирования вы используете термины сильная и слабая типизация.
Esailija
3
@jozefg: я всегда думал, что строго типизированный означает, что каждое значение имеет фиксированный тип (например, целое число, строка и т. д.), тогда как слабо типизированный означает, что значение может быть приведено к значению другого типа, если это считается удобным сделать так. Например, в Python (строго типизированный) 1 + "1"выдает исключение, тогда как в PHP (слабо типизированный) 1 + "1"выдает 2(строка "1"автоматически преобразуется в целое число 1).
Джорджио
1
@Giorgio с таким определением, например, Java не является строго типизированным. Но во многих случаях это утверждается. В этих словах просто нет смысла. У сильного / слабого набора гораздо более точное определение, как «мне нравится / не нравится этот язык», как говорит jozefg.
Esailija
1

преимущества безопасности системы типов теряются.

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

Каковы преимущества безопасности системы типов? Что отличает систему типов, которая позволяет обеспечить эти преимущества безопасности?

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

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

Самый базовый вид спецификации - это гарантия поведения ввода / вывода функций и достоверности внутренней части тела функции. Рассмотрим заголовок функции

f : (Int,Int) -> String

Хорошая система типов гарантирует, что f применяется только к объектам, которые при вычислении выдают пару Int, и гарантирует, что f всегда будет создавать строку.

Некоторые операторы в языке, такие как блоки if-then, не имеют поведения ввода / вывода; здесь система типов гарантирует, что каждое объявление или оператор в блоке является действительным; то есть применяет операции к объектам правильного вида. Эти гарантии являются составными.

Кроме того, это дает своего рода условие безопасности памяти. Цитата, с которой вы имеете дело, касается кастинга. В некоторых случаях приведение в порядке, например приведение 32-разрядного Int к 64-разрядному Int. Однако, как правило, происходит сбой системы типов.

Рассмотреть возможность

Foo x = new Foo(3,4,5,6);
f((Int)x,(Int)x);

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

Одна вещь, которая могла бы создать другую и лучшую систему типов, - это исключить приведение (A) x, где x перед случаем относится к типу B, если только B не является подтипом (или подобъектом) A. Идеи теории подтипов использовались в безопасности. чтобы исключить возможность целочисленных переполнений / недопустимых атак.

Резюме

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

Джонатан Галлахер
источник
1

Одно из преимуществ, которое еще не упомянуто для системы типов, заключается в том, что многие программы читаются больше, чем написаны, и во многих случаях система типов может позволять указывать много информации кратким и простым способом. переваривается кем-то читающим код В то время как типы параметров не заменяют описательные комментарии, большинству людей будет проще читать: "int Distance;" или жеDistance As Int32чем читать "Расстояние должно быть целым числом +/- 2147483647"; Передача дроби может привести к противоречивым результатам. "Кроме того, типы параметров могут помочь сократить разрыв между тем, что происходит с конкретной реализацией API, и тем, на что имеют право полагаться вызывающие абоненты. Например, если конкретная реализация API Javascript использует его параметры таким образом , который будет принуждать любые строки в числовой форме, может быть неясно , будут ли абоненты могут рассчитывать на такое поведение, или если другие варианты реализации неисправности API могли бы , если даны строки. Имея метод параметр которого определяется как DoubleWould дать понять, что любые строковые значения должны быть вызваны вызывающей стороной перед передачей, имея метод с перегрузкой, который принимает, Doubleи другой, который принимаетString было бы несколько яснее, что вызывающим, держащим строки, будет разрешено передавать их как таковые.

Supercat
источник
0

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

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

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

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

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

naasking
источник