Стоит ли использовать статическую типизацию?

108

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

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

Это не сравнение языков, поэтому, пожалуйста, не обращайтесь к проблемам, подобным скомпилированным или интерпретированным. Стоит ли безопасность типов наносить удар по скорости разработки и гибкости? ПОЧЕМУ?

людям, которым нужен пример мнения о том, что динамическая типизация быстрее:

«Используйте динамически типизированный язык во время разработки. Он обеспечивает более быструю обратную связь, время оборота и скорость разработки». - http://blog.jayway.com/2010/04/14/static-typing-is-the-root-of-all-evil/

Morgan Herlocker
источник
15
Этот вопрос противоположен тому, какие аргументы есть в пользу слабой типизации? ,
Николь
8
@Prof Plum: могу ли я потребовать доказательства скорости и гибкости разработки? Поскольку мы говорим об определенном аспекте безопасности типа , использующем Javaили C#неокончательном, их способ обеспечить его НЕ является единственным ...
Matthieu M.
32
Благодаря усердию в строгом языке вы можете минимизировать «головные боли», а затем даже увидеть увеличение скорости из-за автозаполнения IDE, генерации кода и подсказок по коду.
Николь
9
@Prof Plum: я понимаю, я не ожидаю, что вы (или кто-то на самом деле) полностью протестировали каждый когда-либо созданный язык ^^ Проблема в том, что большинство людей, которых я видел, жаловались на какой-то определенный аспект языков программирования (Static Типизация часто приходит) Обычно жалуются на конкретную реализацию и не в состоянии ее реализовать.
Матье М.
5
@Prof Plum, все, что этот пост в блоге действительно говорит о скорости, - это лысое утверждение: «Любой, кто серьезно работал с современным динамически типизированным языком, таким как Ruby или Smalltalk, знает, что он более продуктивен». Нет реальных примеров того, как на практике это ускоряет разработку.
Carson63000

Ответы:

162

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

В динамически типизированных языках:

  • Вы все еще должны знать, работаете ли вы с массивом, целым числом, строкой, хеш-таблицей, ссылкой на функцию, словарем, объектом или чем-то еще.

  • Если это объект, вы должны знать, к какому классу он принадлежит.

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

  • На более низком уровне такие вещи, как количество битов или число подписанных и часто не подписанных, все равно должны учитываться, например, при заполнении пакета TCP.

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

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

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

user61852
источник
10
Я должен был бы оспорить немного о том, что опытные программисты не делают / представляют такие ошибки. Хорошие разработчики, которые скромны и признают возможность того, что они допускают ошибки (а опытные разработчики не всегда такие), с меньшей вероятностью будут создавать такие ошибки.
Джей Джей Джей
12
Не могу согласиться с «Я бы сказал, что вы даже не экономите много времени на печати». Вы заканчиваете тем, что документируете типы в комментариях и проверяете их в своих тестах, которые, во всяком случае, требуют большего набора текста и обслуживания (в конце концов, вы должны помнить, чтобы обновлять упомянутые комментарии всякий раз, когда ваши типы изменяются, и чаще всего вы этого не сделаете ).
Северин Козак
Мы проводим гораздо больше времени в наших типах документирования в магазине Python, чем экономим на многословном статически типизированном языке, таком как C # или Java. Стоит также отметить, что новое поколение языков, таких как Go и Rust, использует вывод типов, поэтому вы вводите «x: = new (Object)» вместо «Object x = new Object ()».
weberc2
Я согласен с вами, когда вы говорите, что динамический язык кажется более приятным, но я не знаю почему. У вас есть объяснение этому?
Родриго Руис
Да, вместо указания типа переменных вы можете использовать значения по умолчанию или модульные тесты (встроенные тесты) в Python. Также в Python иногда могут возникать странные ошибки с неправильным написанием [менее вероятно, если вы используете автозаполнение, которое часто можно использовать, хотя не всегда накануне в динамических языках], и вам нужно выяснить, представляет ли self.bread = 5 хлеб или переопределение его.
aoeu256
123

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

geekosaur
источник
37
+1! «логические ошибки чаще становятся несоответствиями типов во время компиляции, а не сбоями во время выполнения или бессмысленными результатами»: действительно хороший ответ! Когда я трачу больше времени на разработку своих типов, тогда код следует более естественно, и он часто корректен, как только компилируется. Разработка типа означает понимание домена и его операций.
Джорджио
78

Отказ от ответственности: я любитель типов;)

На ваш вопрос сложно ответить: что это за компромиссы ?

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

Однако Haskell поддерживает универсальное программирование в том смысле, что вы пишете методы, которые работают с любым типом, соответствующим определенной концепции (или интерфейсу).

Кроме того, Haskell использует вывод типа , так что вам никогда не придется объявлять тип ваших переменных. Они статически вычисляются во время компиляции, так же, как интерпретатор Python вычисляет их при запуске программы.

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


Пример краткости:

-- type
factorial :: Integer -> Integer

-- using recursion
factorial 0 = 1
factorial n = n * factorial (n - 1)

Помимо встроенной поддержки трудно получить более короткую информацию.

Пример общего программирования:

> reverse "hell­o" -- Strings are list of Char in Haskell
=> "olleh"
> reverse [1, 2, 3, 4, 5]
=> [5,4,3,2,1]

Пример вывода типа:

> :t rever­se "hell­o"
:: [Char]

который можно вычислить просто:

  • "hello"список Char(выраженный как [Char])
  • reverseприменяется к типу [A]возвращает тип[A]

Попробуйте это в вашем браузере

Matthieu M.
источник
4
Чтобы играть в защиту дьявола, один из компромиссов в пользу динамических языков (по крайней мере, во время создания прототипов) заключается в том, что объявления типа могут служить той же цели, что и некоторые модульные тесты, но также могут укреплять интерфейсы так же, как это делают модульные тесты ( хотя конечно с меньшими накладными расходами). Кроме того, статически типизированные языки без принуждения, хотя и более безопасные, требуют явного приведения типов (особенно, когда тип недостаточно универсален), что может отвлекать внимание от краткости.
TR
7
Я не знаю Хаскелла, но +1 за «на самом деле жаловались на что-то другое (многословие, боль переключения одного типа в пользу другого)»
Николь
1
@Aidan: Haskell - развивающийся язык. Haskell 98 был улучшением по сравнению с Haskell 1.4; Haskell 2010 был улучшением по сравнению с этим. Между тем, стоит отметить, что на протяжении большей части своей жизни смысл существования Haskell заключался в том, чтобы помочь исследовать системы типов; Многопараметрические классы типов являются одним из примеров того, как удалось выяснить полезное расширение системы типов. (С другой стороны, функциональные зависимости
кажутся
4
@Matthieu: WRT «Возможно, один из наиболее строго типизированных языков, которые существуют на самом деле.», Я посмотрю ваш Haskell и вырасту вас Agda и Coq . (Я допускаю, что это, вероятно, наиболее строго типизированный практически полезный язык.)
geekosaur
1
@Matthieu: помощники по проверке - это прямое применение корреспонденции Карри-Ховарда, поэтому они лежат в основе языков программирования (хотя и с довольно ограниченными стандартными библиотеками). Они находятся на переднем крае исследования зависимых типов, потому что вам нужны зависимые типы, чтобы правильно использовать соответствие «типы являются предложениями».
geekosaur
37

Мне нравятся как статически, так и динамически типизированные языки. Два главных преимущества безопасности типов для меня:

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

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

dfan
источник
Точно так же и со мной, и всякий раз, когда я хочу что-то реорганизовать (я в основном использую golang / typescript / java), да, эти 2 шага - те, которые понадобятся любому. изменить одну часть, а затем исправить все ошибки компиляции :) идеальный ответ.
Нишчал Гаутам
29

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

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

Майкл К
источник
13

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

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

Подумайте об этом: если кто-то сказал вам, что существует простой способ уменьшить количество ошибок в вашем проекте на 15% за ночь, это должно быть просто.1 Это почти всем известная серебряная пуля.

Доказательства представлены в статье Печатать или не печатать: количественное определение обнаруживаемых ошибок в JavaScript » Чжэн Гао, Кристиана Берда и Эрла Т. Барра. Я призываю всех прочитать это, это хорошо написанная статья, которая представляет образцовое исследование.

Трудно кратко резюмировать, насколько строго авторы выполнили свой анализ, но вот (очень грубый) план:

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

Исследователи собирали проекты с открытым исходным кодом, написанные на JavaScript, из GitHub, просматривали исправленные отчеты об ошибках и пытались свести каждую из сообщенных ошибок к коду, который будет обнаружен статической проверкой типов TypeScript или Flow. Это позволило им оценить нижнюю границу процента ошибок, которые можно исправить с помощью статической типизации.

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

По сравнению с прошлыми исследованиями это новое исследование имеет особые преимущества:

  • Существует прямое сравнение статической и динамической типизации с несколькими (если таковые имеются) смешивающими факторами, поскольку единственное различие между JavaScript и TypeScript / Flow - это типизация.
  • Они выполняют репликацию по нескольким измерениям, проверяя и TypeScript, и Flow (т. Е. Системы разных типов), и заставляя разных людей воспроизводить (ручную) аннотацию типа для исправления ошибок. И они выполняют это на большом количестве кодовых баз из разных проектов.
  • В статье измеряется прямое влияние статической типизации на исправляемые ошибки (а не на более неопределенное качество).
  • Авторы заранее определяют строгую модель того, что и как измерять. Кроме того, их описание невероятно ясно и позволяет легко анализировать недостатки (это всегда хорошо, когда исследовательская работа раскрывает себя атакам: если никакие атаки не могут помешать ее аргументам, она выходит еще сильнее). 3
  • Они выполняют надлежащий анализ мощности, чтобы их размер выборки был достаточным, а последующий статистический анализ - герметичным.
  • Они чрезмерно консервативны, чтобы исключить смешные объяснения, и измеряют только одну движущуюся часть. Кроме того, они ограничивают свой анализ ошибками, которые могут быть немедленно исправлены путем включения типов, и исключают все, что может потребовать более сложного рефакторинга для обеспечения возможности ввода. Таким образом, на самом деле, эффект, вероятно, намного больше, но, конечно, не меньше, чем они сообщили.
  • И, наконец, они не находят незначительного эффекта, но ошеломляют разницу. Несмотря на их чрезмерно консервативную процедуру, даже на нижнем уровне 95% -ного доверительного интервала они обнаруживают, что есть как минимум 10% ошибок, которые просто исчезают при минимальных проверках добавленных типов.

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


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

На самом деле были языки программирования, которые допускали как статическую, так и динамическую типизацию на разных диалектах (например, VB с Option Strict Onили Off, или статически типизированный Лисп). Тем не менее, они не очень подходили для прямого сравнения, что особенно важно, потому что не было существующих, достаточно больших баз кода, позволяющих проводить прямое сравнение. В лучшем случае мы могли бы сравнить их в «лабораторных условиях», где испытуемые случайным образом решают задачу в статически или динамически типизированном варианте языка.

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

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


1 Вдохновлен цитатой из оригинальной статьи.

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

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

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

Конрад Рудольф
источник
3
Я знаю, что это поздний ответ на этот вопрос, но я полагаю, что новое доказательство (которое я объясняю здесь) меняет полную дискуссию о статической динамике.
Конрад Рудольф
2
Это, конечно, интересно, но мне интересно, насколько это относится к конкретной системе типов javascript. Система типов Python (особенно python3) намного строже с гораздо меньшими неявными преобразованиями.
Питер Грин
@PeterGreen Да, это, без сомнения, правда. Возможно, нам повезло, и подсказки Python по типам приведут к аналогичному анализу в будущем (хотя я сомневаюсь в этом, поскольку выраженная цель в PEP484 и PEP526 - не реализовывать статическую типизацию).
Конрад Рудольф
1
Просто читая реферат, я уже могу сказать, что методология в корне ошибочна. Вы не можете использовать кодовую базу, написанную с использованием одной дисциплины, а затем просто добавить типы, чтобы оправдать аргументы в совершенно другой дисциплине. Код, написанный как статическая дисциплина, принципиально отличается от динамической дисциплины, вы не должны писать Java на Python, точно так же, как вы не должны писать Python на Java. Даже машинопись и яваскрипт - это принципиально разные языки, несмотря на внешнее сходство.
Ли Райан
2
@LieRyan Если что-то делает анализ слишком консервативным, как отмечено в моем описании и в других местах. Это никоим образом не делает анализ недействительным. Ваша оценка в 1%, честно говоря, смешная. Это полностью выключено, ваша интуиция подводит вас. Аналогично, ваша характеристика проблем со статической типизацией типична для практиков динамической типизации, у которых не было реального опыта современной статической типизации (то есть не только Java).
Конрад Рудольф
12

Стоит ли безопасность типов наносить удар по скорости разработки и гибкости?

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

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

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

Я могу честно сказать, я прыгаю между JavaScript и C # много. Теперь знание и работа на обоих языках в некоторой степени влияет на другой, но на самом деле код, который я пишу в каждом, выглядит совершенно иначе, чем в другом. Они требуют другого подхода, потому что они принципиально разные. Что я обнаружил, так это то, что если вы обнаружите, что думаете: «Черт, это намного сложнее сделать на языке X», то ваш подход, вероятно, немного не в порядке. Вот пример, люди говорят о «питонском» способе ведения дел. Это означает, что язык Python работает так, чтобы облегчить проблему. Делать это другим способом, как правило, сложнее и более громоздко. Вы должны преодолеть горстку знания того, как язык работает, чтобы действительно он работал для вас. Это'

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

Недавно был задан похожий вопрос: динамические и статически типизированные языки для веб-сайтов.

Чтобы переформулировать суть моего ответа:

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

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

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

Безопасность типов - это функция (это то, что многие якобы языки высокого уровня не понимают правильно), чтобы помочь вам предотвратить выстрел в себя .
И о любом успешном динамически типизированном языке было бы просто лучше, если бы у вас была возможность проверить тип кода по желанию.
Например, мне, безусловно, понравилось экспериментировать с Ruby, но это было главным образом потому, что Ruby полностью объектно-ориентирован, что полностью ортогонально наличию системы типов времени компиляции.

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

Пример кода haXe:

class Car {
    public function new();
    public function wroom() trace('wroooooooom!')
}
class Duck {
    public function new();
    public function quack(at) trace('quackquack, ' + at + '!')
}

function letQuack(o) o.quack();
letQuack(new Car());
letQuack(new Duck());

Это приведет к ошибке времени компиляции:

Car should be { quack : Void -> Unknown<0> }
Car has no field quack
For function argument 'o'
Duck should be { quack : Void -> Unknown<0> }
Invalid type for field quack :
to : String -> Void should be Void -> Unknown<0>
For function argument 'o'

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

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

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

оборота back2dos
источник
В python doctests просто копируется и вставляется из repl / shell, как источник документации и последующей проверки. docs.python.org/3/library/doctest.html
aoeu256
5

По какой-то причине я больше не делаю ошибок, связанных с типом объекта, который часто больше. В таких языках, как C #, я более склонен делать ошибки, связанные с приведением во время выполнения, чем с ошибкой безопасности типа, определяемой компилятором, которая, я допускаю, обычно вызвана случайной необходимостью обходить статичность статически типизированный язык. Когда я пишу ruby, код довольно сильно намекает на тип объекта, а наличие REPL означает, что я уже экспериментально проверил, что требуемый метод / атрибуты существуют, или у меня будет модульный тест, который выполняет в основном то же самое, поэтому я также редко сталкиваюсь с проблемами безопасности типов в ruby.

Но это не значит, что статически типизированные системы не могут быть лучше, чем они есть.

В статически типизированных языках система типов также имеет большое значение. Например, с чем-то вроде монады Some в функциональных языках (типа <Some>: = yes x | no) вы получаете проверки во время компиляции, которые по существу предотвращают страшную исключительную ситуацию NullReferenceException, распространенную в большинстве систем типов; при выполнении кода сопоставления с образцом вы получаете ошибки времени компиляции, говорящие вам, что вы не смогли обработать нулевое условие (если вы используете этот механизм для объявления типа). Вы также уменьшаете подобные типы ошибок, когда используете такие вещи, как оператор конвейера |> в F #.

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

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

оборота JasonTrue
источник
5

По-разному.

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

Стоит ли это снижение вероятности неудачи, зависит от стоимости.

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

hotpaw2
источник
3
Ваш сценарий быстрого прототипирования намекает на то, что он ошибочен в статье Пола Худака об исследовании военно-морского флота США, в котором требовалось разработать AEGIS-подобную симуляцию на разных языках, одним из которых был Haskell. Он соответствует почти всем вашим критериям: это было быстрое создание прототипа, требования, которые были плохо определены, и стоимость отказа была почти нулевой (это был крайне неформальный эксперимент). Haskell стал победителем в категории evey: время разработки, превышение требований, необходимость в меньшем количестве LOC и создание единственного рабочего примера среди всех участников!
Андрес Ф.
2
Бумага: Haskell vs ..., Эксперимент в Производительности Прототипирования Программного обеспечения - Пол Худак и Марк П. Джонс . В нем описаны результаты эксперимента, заказанного ARPA и ВМС США.
Андрес Ф.
Разве победителем не был Реляционный Лисп? Чувак, хотелось бы, чтобы были видео, показывающие, как люди кодируют вещи на Лиспе со всеми этими странными мощными расширениями, такими как Shen (логически-реляционная структура, которая позволяет вам давать зависимые типы коду и код типа смешивания и сопоставления с кодом не-типа ), фреймворки супер-CLOS с предикатной отправкой и т. д.
aoeu256
4

Было написано много очень сложных систем на Лиспе, и я не слышал, чтобы Лиспер жаловался на то, что им нужна статическая типизация. Когда я работал с ним, я не помню каких-либо проблем, которые сильно замедлили бы работу статической системы типов (и вы можете указывать типы статически в Common Lisp).

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

Дэвид Торнли
источник
4

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

  • Статические типы дают более раннюю обратную связь о том, отвечает ли код требованиям, которые могут быть выражены системой типов, в обмен на задержку обратной связи из-за создания чего-то минимально функционального (например, обратной связи с клиентами или тестов более высокого уровня).
  • Знание того, что код отвечает определенным требованиям, может облегчить рефакторинг и отладку, но также увеличивает накладные расходы на изменение интерфейсов и изменение требований.
  • В частности, если в статически типизированном языке отсутствует принуждение, он обеспечивает дополнительную защиту от кода, используемого в данных, что может привести к ошибкам (уменьшая потребность в условных выражениях и утверждениях), но чрезмерно ограничительные ограничения требуют от пользователя написания большего количества кода, чтобы массировать свои данные в приемлемая форма (например, явное приведение типов).
  • Явные аннотации типов могут помочь в понимании при чтении кода или могут загромождать код избыточной или ненужной информацией.
  • В зависимости от реализации, это может отвлечь от краткости. Это зависит от таких вещей, как, являются ли аннотации типов необходимыми или предполагаемыми, насколько хорошо система типов может выражать универсальные типы / интерфейсы, синтаксис и намерены ли вы проверить ограничения, которые могут быть выражены системой типов (т. Е. этот же тест, скорее, более краткий как языковая функция, чем как модульный тест, но вы, возможно, не намеревались его тестировать).
  • Кроме того (но это не относится к TDD), статические типы могут помочь в оптимизации времени компиляции за счет необходимости проверки типов (и времени для их проверки и выполнения оптимизаций), а также можно улучшить оптимизацию, если данные ограничены типами. эта карта хорошо подходит для оборудования. Это облегчает разработку кода с требованиями к производительности, но может вызвать проблемы для кода, который не соответствует этим ограничениям (согласно пункту 3).

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

Т.Р.
источник
3

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

Мейсон Уилер
источник
4
Языки со строгой типизацией, такие как Java и C #, выполняют десериализацию автоматически с помощью Reflection.
Матье М.
3

Морган, у меня есть интересная идея для вас: статическая + динамическая типизация. Вы упомянули Python, C # и Java. Знали ли вы, что есть несколько довольно хороших портов Python для .NET и Java? В обоих случаях порты позволяют использовать библиотеки этих платформ и / или взаимодействовать с существующим кодом. Это дает вам несколько возможностей:

  1. Храните устаревший код в статическом, негибком языке. Используйте Python для новых вещей.
  2. Используйте Python для создания прототипа новых вещей на зрелых платформах. Перекодируйте компоненты, которые вы хотите сохранить, на более зрелом языке.
  3. Используйте динамический язык для частей, которые вы часто меняете.
  4. Возможно, используйте динамический язык, чтобы поиграть с такими идеями, как изменение запущенного кода.
  5. Делайте все на динамическом языке, кроме критических частей, где вы используете строго типизированный язык.

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

(Примечание: ответ уже сказал это, но я также хочу еще раз подчеркнуть, что динамическая типизация! = Нет / слабая типизация. Многие динамические системы типов используют строгую типизацию изнутри. Я думаю о том, что делает динамику типов такой, что тип переменных определяется во время выполнения, не нуждается в аннотации типа и / или может изменяться во время выполнения.

Ник П
источник
2

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

прецизионный самописец
источник
это субъективный контроль качества, поэтому я в порядке.
Морган Херлокер
1
Кто-нибудь хочет объяснить отрицательные голоса?
фунтовые
Не могу помочь с объяснением, но я дал вам +1, я думаю, что это полезный вклад. Одним из ключевых опасений динамической типизации является то, что вы будете вносить изменения где-то и ломать что-то где-то еще из-за допущений, которые были бы применены компилятором в статически типизированном языке. Тяжелое покрытие юнит-тестом защитит вас здесь.
Carson63000
5
Я не понизил голос, так как вы высказали правильное мнение, хотя не обиделись, но ваш пост выглядит как фанат TDD, поэтому, вероятно, и отрицательные.
Карл Билефельдт
@Karl, не обижайся, это был настоящий вопрос. Я могу быть непростительно за TDD, я признаю
pdr
2

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

Моя последняя работа была в основном разработка Python. Я работал в крупной международной веб-хостинговой компании, и у нас были команды разработчиков в США, Канаде и Южной Корее. Пользовательский веб-фреймворк Python для клиентского приложения, позволяющий пользователям управлять своими доменными именами и учетными записями веб-хостинга. Backend: все тоже питон. Веб-сервис Python для общения с отдельными серверами, например, для предоставления нового веб-хостинга, создания нового блога, создания записей DNS в нашей системе обслуживания имен; и т. д. и т. д. В моей нынешней работе клиентские приложения все наши в Java; наш основной продукт представляет собой смесь Java и Flash. Пользовательский веб-фреймворк Java для наших старых приложений, калитка для наших новых внутренних инструментов.

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

LGriffel
источник
2

Стоит ли безопасность типов наносить удар по скорости разработки и гибкости? ПОЧЕМУ?

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

В разработке программного обеспечения всегда будут некоторые головные боли из-за:

  • Врожденная сложность того, что вы пытаетесь достичь

  • Присущие людям ошибки, особенно если учесть, что мы делаем больше ошибок, когда пытаемся сделать что-то более сложное

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

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

Иордания
источник
1

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

Я был разработчиком в течение долгого времени. Начиная с c ++, c #, затем перешел на javascript (фронтенд и бэкэнд через node.js). С тех пор, как я начал разрабатывать в javascript, моя продуктивность взлетела до предела, и я фактически усугубился, используя языки на основе типов. Я также против компиляции, я хочу, чтобы все было во время выполнения. Интерпретируемые языки - это действительно то место, где я нашел свою любовь к программированию.

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

Вот пример. Я просто использовал Swift (новый язык Apple), надеясь, что он на самом деле соответствует его названию день назад, и попытался сделать: var n = 1/2 не сработало. Я был как, что здесь происходит. и затем, к сожалению, понял, что я должен сделать var n: Float = 1/2. Это напомнило мне, насколько я ненавижу системы типов и насколько они бесполезны.

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

Разработчики любят говорить, что слабо типизированные языки не подходят для больших проектов. Но я бы сказал, что все наоборот. Строго типизированные языки ужасны для больших проектов. И если вы говорите, что javascript не работает для больших проектов, попросите компанию Uber более чем на 40 миллиардов, которая запускает весь свой бэкэнд на node.js / javascript или Facebook, который начинал с PHP.

Что касается языков со статической типизацией, это не годится для быстрых сегодняшних итераций. Вот простой пример: у вас есть 10 разработчиков, работающих над проектом .net с сервером непрерывной интеграции, один разработчик сообщает об ошибке, и вся сборка нарушается, даже если 10 разработчиков работают над разными вещами, все они теперь остановлены и ждут для оскорбительного разработчика, чтобы исправить свою ошибку. Разговор об эффективном да? Тип системы / статические языки взаимозависимы и делают ваш код взаимозависимым. Однако файлы сценариев никогда не являются взаимозависимыми. Если есть проблема с одним из сценариев, который не останавливает производство, все проблемы, которые вы увидите, остаются на этапе выполнения. И время выполнения никогда не останавливается. Это никогда не ломается. Это может привести к неправильному выводу, но это не так

оборота user19718
источник
1
Много «я», не так много аргументов. И, между прочим, «ошибка» сборки не имеет ничего общего со статической или динамической. Если у вас есть модульные тесты, и один из них провален, «ваша сборка повреждена» и, надеюсь, не будет развернута в производство, пока это не будет исправлено
nafg
Что заставило вас думать, что я намекаю на такую ​​вещь?
nafg
Ваша производительность в javascript не взлетела, потому что в javascript не было типов. Ваша производительность взлетела до небес, потому что C ++ и C # - тяжелые языки. Типы Javascript + на самом деле сделают вашу производительность еще выше. Никто не говорил, что javascript невозможен для больших проектов. Javascript на больших проектах, безусловно, выполнимо. Однако это не идеально. Модульные тесты занимают место проверки типов, также модульные тесты имеют ограниченное покрытие типов, в то время как проверка типов имеет 100% покрытие.
Брайан Йе
1
@BrianYeh c ++ и c # - тяжелые языки, потому что они сосредоточены вокруг типов. Я только начал использовать responsejs на своей работе, и моя производительность снова упала из-за непрерывного использования типов и компонентов. если вам нравятся типы и юнит-тесты, хорошо для вас. не все мы разделяем этот стиль программирования.
1
У @foreyez реагий нет типов. Вы, вероятно, имеете в виду поток. Модульные тесты занимают место проверки типов, поэтому, если у вас нет проверки типов, вам нужно больше модульных тестов. Модульные тесты и типы являются противостоящими силами. Ваша производительность снижается - иллюзия. Любая ошибка типа, которую вы ловите на языке с безопасным типом, является в противном случае необученной ошибкой на языке с динамической типизацией Это только кажется быстрее. Безопасный язык типа заставляет вас решать эти ошибки заранее.
Брайан Йе
0

ДА.

Я работал в приложениях PHP, где типы не такие «сильные», как в Java или C #. Обычно я заканчивал «моделирование типов», потому что, чтобы избежать плохих автоматических преобразований или проверки данных.

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

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

umlcat
источник
0

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

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

Еще одна более тонкая проблема - несовершенная замещаемость.

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

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

Двумя наиболее распространенными типами в программировании являются числа и строки. Во многих динамических языках они являются несовершенными заменителями друг друга. Например, javascript или php, если вы предоставляете число, в котором ожидается строка, или наоборот, ваша программа запускается без сообщения об ошибке, но может вести себя не совсем корректно.

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

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


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

Питер Грин
источник