Какой язык программирования генерирует наименьшее количество труднодоступных ошибок? [закрыто]


54

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

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

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

Редактировать: Полностью произвольное разъяснение трудно обнаруживаемой ошибки: Воспроизведение занимает более 15 минут или более 1 часа, чтобы найти причину и устранить ее.

Простите, если это дубликат, но я не нашел ничего по этой конкретной теме.


10
Я хотел бы увидеть некоторые исследования в этой теме! Не только «мои неофициальные данные свидетельствуют о том, что единственный язык, который я знаю, это король», но и уровень ошибок в крупных проектах и ​​так далее.
Фрэнк Шиарар

@ Честно говоря ... если бы у вас было МНОГО (а я имею в виду МНОГО) времени, вы, вероятно, могли бы добывать некоторую статистику из охло, если бы вы могли идентифицировать патчи, исправляющие ошибки из тысяч репозиториев кода.
Тим Пост

Тот, где разрешены только комментарии. Никаких других инструкций :)
Виктор Хурдугачи

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

@Winston Согласен.
Магнус Вольффелт

Ответы:


58

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

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

альтернативный текст

* Факторинг в способности использовать небезопасные конструкции.

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

Я пометил Haskell '98 как чистый, но GHC Haskell как не чистый из-за небезопасного семейства функций *. Если вы отключите unsafe *, то соответственно поднимите GHC Haskell.


8
Это великолепно!

7
Я не смог найти Common Lisp на графике: (let ((itbe '())) ... )...
duros

7
Какая? Там не было места слева от PHP?
Pestaa

7
C # позволяет безопасные указатели: проверяется вся арифметика указателей. Поэтому я считаю, что это должно быть там с Java.
Алекс тен Бринк

11
@missingfaktor: Я думаю, что C # не очень хорошо расположен. C # позволяет и продвигает последующие стили программирования. Это не должно быть измерено худшим, что это позволяет.
back2dos

20

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

  • он чисто функциональный: функции не могут иметь (непреднамеренных) побочных эффектов, и это делает многоядерное программирование проще и менее подвержено ошибкам
  • он строго типизирован: вы не можете, например, случайно смешать значения bool, char, int и float
  • он статически типизирован: многие ошибки программирования обнаруживаются во время компиляции
  • nullне является частью определения типа значения: этим вы избегаете ошибки в миллиард долларов
  • Есть много готовых функций высшего порядка, которые вы можете использовать вместо написания собственных, возможно, ошибочных, реализаций.
  • у него есть сборщик мусора: ошибки памяти практически исключены (за исключением «утечек пространства» из-за его ленивой стратегии оценки)

11
Я не буду опровергать это, но я испытываю искушение, потому что это не соответствует критериям. Предполагается, что он позволяет «среднему программисту выводить функции» с минимальным количеством ошибок, но средний программист, прямо скажем, не может создавать головы или хвосты Haskell.
Мейсон Уилер

5
Много хороших моментов, но, удаляя некоторые классы ошибок (непреднамеренные побочные эффекты, неожиданные преобразования типов), Haskell добавляет целый новый класс ошибок: утечки пространства. (Также, хотя нет null, есть undefined, который является членом каждого типа.)
j_random_hacker

5
@ Мейсон: Если вы не пишете в нем, вы не можете иметь ошибки в нем :)
Майкл К

2
Я думаю, что не существует такого понятия, как бесплатный обед - у вас могут быть легко обнаруживаемые ошибки или легко записываемый код, но не оба вместе :)
Benjol

6
@ Мейсон, что такое «средний программист»? Вопрос начинается с «какой язык программирования ...», а не «который среди C, C ++ и Java ...»;)
Agos

18

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

  • почти невозможно воспроизвести
  • может быть очень тонким

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

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


Редактировать: в Java Executorsобрабатывают еще больше сложных деталей. Вам нужно сделать так, чтобы отдельные задачи соответствовали Callableинтерфейсу.


5
++ Расовые условия. Ты можешь сказать это снова.
Майк Данлавей

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

Что насчет Эрланга?
Malfist

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

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

13

Ада разработана таким образом, чтобы как можно больше ловилось во время компиляции, а не во время выполнения. Это означает, что для компиляции программы в Ada часто требуется примерно в 10 раз больше времени, чем в Java, но в случае компиляции вы можете быть гораздо более уверены, что целые классы ошибок не проявятся, когда программа запустить.


7
+1 за то, что правильно заметил, что Ада ловит вещи в компиляторе, которые игнорируют другие языки. -1 для утверждения, что это означает, что для компиляции программы Ada требуется в 10 раз больше времени. Ада награждает программиста, ДИЗАЙНЕРА !!! его код, который ДУМАЕТ !!! о том, что он делает, прежде чем он начинает безумно печатать. Мой личный опыт, когда я занимался производственным программированием в Ada для защиты, заключался в том, что создание кода Ada для компиляции заняло не намного больше времени, чем в C / C ++ или FORTRAN, но код Ada позже столкнулся со значительно меньшими проблемами. Пратт и Уитни заметили нечто подобное.
Джон Р. Штром

1
@ john r strohm, насколько я понимаю, он говорит не о времени, которое требуется компилятору для компиляции кода, а о времени, чтобы сделать код компилируемым.
Malfist

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

@Ptolemy, если лодки могут быть названы в честь женщин (за исключением, по-видимому, для американских перевозчиков), то языки программирования тоже могут. Скорее

1
Как только я преодолел кривую обучения, я довольно быстро начал писать код на Аде - после того, как потратил много времени на обдумывание дизайна. Ада, безусловно, НЕ язык хакера. Сейчас я работаю на Java, и некоторые вещи, которые я вижу в моих текущих проектах, на самом деле заставляют меня немного скучать по Аде (никогда не думал, что скажу это).
Джеймс Адам

7

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

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

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

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

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

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


Ручная блокировка может показаться «простым в использовании механизмом синхронизации», но на самом деле она «проста в использовании, но вас ждет веселое время, когда вы будете искать этот тупик». И, конечно же, вы можете выполнять параллелизм на основе Actor на нескольких языках.
Фрэнк Шиарар

Фрэнк: по крайней мере, блокировка достаточно проста, так что каждый может сделать это, не тратя дней, выясняя, какой API использовать и т. Д.
user281377

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

@ Дэвид: Я понимаю вашу точку зрения, но во многих случаях простое решение - это действительно все, что нужно. Например, рассмотрим сервлет, используемый только небольшим количеством пользователей, которые должны использовать общий ресурс (например, соединение с базой данных). Без синхронизации условия гонки случаются время от времени; но это не совсем ракетостроение, чтобы поместить все операции доступа к базе данных в блок synchronized (connection) {}.
user281377

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

7

Поскольку Excel является наиболее широко используемым DSL, я пойду с Excel. (исключая VBA конечно)

Это отвечает всем требованиям:

  • Это всегда легко воспроизвести (вот таблица - она ​​не работает)
  • Найти ошибку очень просто, так как она полностью «функциональна» - начните с неправильной ячейки и проследите все ее зависимости.

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

+1 Немного дерзкий, так как Excel - это данные, а не язык. Рассмешил меня :)
recursion.ninja

2
@awashburn - о, я не знаю. Я думаю, что это квалифицируется как язык. Каждая ячейка является «переменной». Каждая переменная декларативно устанавливается в виде литерала (например, 123или ABC) или функции ( =SUM(A2:A5)). Затем Excel оценивает все переменные, выясняя, в каком порядке разрешать зависимости и т. Д. Это, конечно, не только данные.
Скотт Уитлок

2
Я отказываюсь от своего утверждения, оказывается, что Excel завершен по Тьюрингу ... Я узнал кое-что совершенно тревожное ...
recursion.ninja

1
«... настоящий [Lisp] мастер понимает, что все данные - это код». Возможно, это относится и к Excel, как ни странно. blogs.msdn.com/b/sriram/archive/2006/01/15/lisp-is-sin.aspx
Джеймс Мишра

7

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

Я считаю, что есть несколько аспектов языковых возможностей, которые влияют на вероятность ошибок:

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

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

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

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

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

  • Поддержка параллелизма - проблемы с параллелизмом особенно трудно обнаружить и отладить, поэтому это так важно. Все, что требует ручной блокировки, в конечном итоге обречено на провал (и это включает в себя практически каждый объектно-ориентированный подход к параллелизму). Лучший язык, который я знаю в этом отношении, - это Clojure - у него есть уникальный подход к управлению параллелизмом, который сочетает программную транзакционную память с неизменяемыми структурами данных, чтобы получить новую, надежную и составную среду параллелизма. См. Http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey для получения дополнительной информации


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

1
Лучший ответ на данный момент! Я думаю, что это подтверждается следующими двумя анализами частоты ошибок: deliberate-software.com/safety-rank-part-2 и macbeth.cs.ucdavis.edu/lang_study.pdf . Они оба показывают, что чем чище, функциональнее, выразительнее и безопаснее язык, тем меньше в нем ошибок. Точно так же они оба показывают, что Clojure и Ruby избегают правила безопасности, вероятно, указывая, что интерактивность оказывает такое же влияние, как вы указали.
Дидье А.

@DidierA. к сожалению, ссылка на ucdavis не работает (без архива wbm) - я думаю, что вы получили ее со страницы Прем Деванбу, которая теперь указывает на обновленную ссылку:
широкомасштабное

5

Чем менее мощный язык, тем меньше у него возможностей стрелять ногой.

Языки высокого уровня, такие как Java и C #, будут вызывать меньше ошибок, чем языки низкого уровня, такие как C ++.

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


4
+1 за «Чем менее силен язык, тем меньше у него возможностей дать вам возможность выстрелить собственной ногой».
Майкл К

Диаграмма отсутствующего фактора, по-видимому, говорит о том, что C # и C ++ находятся на равных основаниях, поскольку возможность застрелиться там идет и поднимает Java выше этого уровня. Хотя я не согласен с этой частью таблицы. Вы вынуждены пройти через обручи, чтобы сделать C # стрельбу.
Джесси С. Slicer

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

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

7
@missingfaktor, это потому, что это побочный эффект, чтобы выстрелить себе в ногу.

3

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

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

  • Строгая типизация и строгий компилятор, который ловит много распространенных ошибок.
  • Интуитивно понятный синтаксис, не допускающий распространенных ошибок. («Последняя ошибка в мире» if (alert = RED) {LaunchNukes;}, например, не будет компилироваться.)
  • Хорошо разработанная объектная модель, которая устраняет многие распространенные ошибки ООП C ++.
  • Проверка границ и проверка диапазона встроены в язык, что значительно снижает вероятность проблем с безопасностью.
  • Вероятно, это самый быстрый компилятор, известный человеку, который увеличивает вашу производительность и затрудняет потерю мышления во время ожидания сборки.
  • Отладчик Отладчик Visual Studio хочет быть похожим, когда он вырастет.
  • Отслеживание утечек встроено непосредственно в диспетчер памяти, что упрощает поиск и устранение утечек памяти.
  • Большая, зрелая стандартная библиотека, предоставляющая готовые и предварительно протестированные способы выполнения типичных задач без необходимости создания собственных, возможно, ошибочных реализаций.
  • Поставляется с полезными инструментами, такими как мощная система регистрации и профилировщик, чтобы упростить отслеживание проблем.
  • Сильная поддержка сообществом распространенных проблем, которых нет в стандартной библиотеке, включая мощную стороннюю библиотеку параллелизма .

Я жокей из Delphi с далекого прошлого, но он ушел от своих корней из Паскаля, когда позволил мне настраивать что-либо на что-то еще, например, C / C ++:var I: Integer; Pointer(I)^ := $00;
Джесси С. Слайсер

1
@Jesse: Возможно, но я вижу это как необходимую уступку прагматизму. Керниган сделал много хороших замечаний, когда написал, почему Паскаль не мой любимый язык программирования. Typecasts необходимы, чтобы сделать много важных вещей низкого уровня. Но одной из сильных сторон Delphi является то, как его библиотеки инкапсулируют низкоуровневые детали и делают ненужными большинство небезопасных указателей и типов.
Мейсон Уилер

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

1
@Jesse: Разве оригинальная версия Паскаля Wirth не допускала вариант записи? IIRC в конечном итоге стали настолько широко использоваться, чтобы подорвать строгую типизацию, что Borland и другие решили просто ввести типы типов, чтобы сделать их проще, потому что все все равно это делали.
Мейсон Уилер

en.wikipedia.org/wiki/Pascal_(programming_language)#Divisions and en.wikipedia.org/wiki/Pascal_(programming_language)#Criticism, а также pascal-central.com/ppl/chapter3.html, кажется, указывают на то, что это было частью первый стандарт в 1983 году. Я вижу некоторые ссылки Вирта, которые датируются 1974 годом, поэтому я бы сказал, что да, это так. Я думаю, что проблемной частью было позволить подорвать его как таковой (то есть варианты полей, занимающих ту же память, как союзы в C). Если бы они просто использовались в качестве механизма видимости, а макет памяти предназначался для надмножества, он был бы напечатан сильнее.
Джесси С. Slicer

2

Одна вещь, которую нужно принять во внимание, - это поворот во времени.

Последние пять лет я в основном занимался разработкой веб-приложений на Java (JSF, Seam и т. Д.). Недавно я получил новую работу, и мы используем Perl (с Catalyst и Moose).

Я гораздо более продуктивен в Perl, чем в Java.

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

Я предполагаю, что количество ошибок в моем Perl-коде более или менее совпадает с количеством ошибок в моем Java-коде, оно может быть даже выше. Но я считаю, что найти и исправить эти ошибки проще и быстрее.


1

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


1
"работать вокруг износа оборудования по мере его старения" ...?
j_random_hacker

Я читал, что некоторые ОС Unix, работающие на критически важных компьютерах, проверяют работоспособность процессора, оперативной памяти и другого оборудования. serverfault.com/questions/56192/… обсуждает это до некоторой глубины. Если некоторые линии в модуле ОЗУ со временем становятся неисправными, эти неисправные модули не будут использоваться ОС и не будут сообщать о них в общей доступной физической памяти. Такие вещи могут быть выполнены и на другом оборудовании.
vpit3833

Это интересная новость, но я не понимаю, насколько она здесь уместна. Также ничто в вашей ссылке не упоминает эти самовосстанавливающиеся ОС Unix - это просто говорит о способах стресс-тестирования аппаратного обеспечения ПК.
j_random_hacker

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

1

Вместо того, чтобы говорить о языках, что говорить о языковых особенностях

  • Java заставляет вас думать об исключениях (throws ...), и вы должны либо опубликовать, либо обработать эти исключения. Действительно ли это мешает мне забыть ошибки, или я использую больше исключений, полученных из SystemException, которые не нуждаются в такой обработке?
  • насчет «дизайна по контракту» (http://en.wikipedia.org/wiki/Design_by_contract), который заставляет меня задуматься о предварительных и постусловиях. Я прочитал, что теперь возможно с C # -4.0.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.