Я не планирую писать компилятор в ближайшем будущем; Тем не менее, я весьма заинтересован в технологиях компиляции и в том, как сделать это лучше.
Начиная с компилируемых языков, большинство компиляторов имеют два уровня ошибок: предупреждения и ошибки, первый из которых состоит в большинстве случаев нефатальных ошибок, которые вы должны исправить, и ошибки, указывающие большую часть времени, что невозможно произвести машинный (или байтовый) код с входа.
Хотя это довольно слабое определение. В некоторых языках, таких как Java, от некоторых предупреждений просто невозможно избавиться без использования @SuppressWarning
директивы. Кроме того, Java рассматривает некоторые нефатальные проблемы как ошибки (например, недоступный код в Java вызывает ошибку по причине, которую я хотел бы знать).
C # не имеет таких же проблем, но у него есть несколько. Кажется, что компиляция происходит в несколько проходов, и сбой прохода будет препятствовать выполнению дальнейших проходов. Из-за этого количество ошибок, которое вы получаете при сбое сборки, часто сильно недооценивается. При одном запуске может появиться две ошибки, но как только вы исправите их, возможно, вы получите 26 новых.
Переход на C и C ++ просто показывает плохую комбинацию диагностических недостатков компиляции в Java и C # (хотя было бы точнее сказать, что Java и C # просто пошли своим путем с половиной проблем каждый). Некоторые предупреждения действительно должны быть ошибками (например, когда не все пути кода возвращают значение), и все же они являются предупреждениями, потому что, я полагаю, в то время, когда они писали стандарт, технология компилятора не была достаточно хороша, чтобы делать подобные проверки обязательны. В том же духе, компиляторы часто проверяют больше, чем говорит стандарт, но все же используют «стандартный» уровень ошибки предупреждения для дополнительных выводов. И часто компиляторы не сообщают обо всех ошибках, которые они могут найти сразу; может потребоваться несколько компиляций, чтобы избавиться от всех из них. Не говоря уже о загадочных ошибках, которые любят компиляторы C ++,
Теперь, добавив, что многие системы сборки можно настраивать так, чтобы они сообщали о сбоях, когда компиляторы выдают предупреждения, мы просто получаем странное сочетание: не все ошибки являются фатальными, но некоторые предупреждения должны; не все предупреждения заслуживают внимания, но некоторые явно подавляются без дальнейшего упоминания об их существовании; и иногда все предупреждения становятся ошибками.
Некомпилированные языки все еще имеют свою долю дерьмовых сообщений об ошибках. О опечатках в Python не сообщается до тех пор, пока код на самом деле не запущен, и вы никогда не сможете по-настоящему выбросить более одной ошибки за раз, потому что скрипт перестанет выполняться после того, как встретит одну.
PHP, со своей стороны, имеет кучу более или менее значительных уровней ошибок и исключений. Об ошибках разбора сообщается по одному, предупреждения часто настолько плохи, что должны прервать ваш скрипт (но не по умолчанию), уведомления действительно часто показывают серьезные проблемы с логикой, некоторые ошибки на самом деле не настолько плохи, чтобы остановить ваш скрипт, но все же и, как обычно, с PHP, есть некоторые действительно странные вещи (почему, черт возьми, нам нужен уровень ошибок для фатальных ошибок, которые на самом деле не фатальны?, E_RECOVERABLE_E_ERROR
я говорю с вами).
Мне кажется, что каждая реализация отчетов об ошибках компилятора, о которой я могу думать, нарушена. Что является настоящим позором, поскольку все хорошие программисты настаивают на том, как важно правильно исправлять ошибки, и в то же время не могут получить для этого свои собственные инструменты.
Как вы думаете, должен быть правильный способ сообщить об ошибках компилятора?
Ответы:
Похоже, ваш вопрос на самом деле не о том, как мы сообщаем об ошибках компилятора, а о классификации проблем и о том, что с ними делать.
Если мы начнем с предположения, что на данный момент дихотомия предупреждение / ошибка верна, давайте посмотрим, насколько хорошо мы можем на этом основываться. Некоторые идеи:
Разные «уровни» предупреждения. Многие компиляторы как-то реализуют это (например, GCC имеет много переключателей для точной настройки того, о чем он будет предупреждать), но это требует работы - например, сообщения о серьезности сообщаемого предупреждения и возможности устанавливать предупреждения ошибки "только для предупреждений выше указанной серьезности.
Разумная классификация ошибок и предупреждений. Об ошибке следует сообщать только в том случае, если код не соответствует спецификации и, следовательно, не может быть скомпилирован. Недоступные операторы, хотя, вероятно, и являются ошибкой кодирования, должны быть предупреждением , а не ошибкой - код все еще «действителен», и существуют допустимые случаи, в которых нужно компилировать с недоступным кодом (например, быстрые изменения для отладки) ,
Теперь о чем я не согласен с вами:
Прилагать дополнительные усилия, чтобы сообщить о каждой проблеме. Если есть ошибка, это нарушает сборку. Сборка сломана. Сборка не будет работать, пока эта ошибка не будет исправлена. Следовательно, лучше сразу сообщать об этой ошибке, чем «продолжать», чтобы попытаться идентифицировать все остальное «не так» с кодом. Особенно, когда многие из этих вещей, вероятно, вызваны первоначальной ошибкой.
Ваш конкретный пример предупреждения, которое должно быть ошибкой. Да, это, вероятно, ошибка программиста. Нет, это не должно нарушать сборку. Если я знаю, что входные данные для функции таковы, что она всегда будет возвращать значение, я смогу запустить сборку и выполнить несколько тестов без необходимости добавлять эти дополнительные проверки. Да, это должно быть предупреждение. И чертовски серьезный. Но он не должен нарушать саму сборку, если не компилируется с предупреждениями-ошибками.
Мысли?
источник
Одна из проблем, которую вы затронули, - неполное сообщение об ошибках - например, сообщение о 2 ошибках, и когда вы их исправляете, вы получаете кучу больше.
Это (в значительной степени) компромисс со стороны автора компилятора. В зависимости от того, какая ошибка вы сделали, это очень легко для компилятора , чтобы начать неправильно понимать , что вы делаете достаточно плохо , что он начинает ошибок отчетов , которые имеют очень мало общего с реальностью. Например, рассмотрим простую опечатку, в которой
itn x;
вместо чего-то естьint x;
. Если вы не сделали что-то еще, что может что-тоitn
значить, это будет сообщено как ошибка. Это хорошо, насколько это возможно, но теперь посмотрим, что произойдет дальше - компилятор смотрит на большое количество кода, который пытается использоватьx
в качестве переменной. Должен ли он A) остановиться и позволить вам это исправить, или B) извергнуть 2000 ошибокerror: "x": undeclared identifier
или что-то в этом порядке? Рассмотрим другую возможность:Это еще одна довольно очевидная опечатка - очевидно, она должна быть
{
вместо а[
. Компилятор может довольно легко сказать вам эту часть - но должен ли он затем сообщать об ошибке, например,x=1;
что-то вродеerror: statement only allowed inside a function
?Обратите внимание, что это даже довольно тривиальные проблемы - их гораздо легче найти (особенно, как большинство из нас знает, когда вы переходите на шаблоны C ++). Суть в том, что создатель компилятора обычно застревает в попытках найти компромисс между сообщением о ложных ошибках (т. Е. Сообщением о чем-либо как об ошибке, даже если это нормально) и невозможностью сообщить о реальных ошибках. Есть несколько практических правил, которым следует следовать, чтобы не пойти слишком далеко в обоих направлениях, но почти ни одно из них не близко к идеальному.
Еще одна проблема, которую вы упомянули, была Java и
@SupressWarning
. Это очень отличается от вышеупомянутого - это было бы довольно тривиально исправить. Единственная причина, по которой это не исправлено, заключается в том, что это не соответствует базовому «характеру» Java - то есть, по их мнению, «это не ошибка, а особенность». Несмотря на то, что обычно это шутка, в этом случае вовлеченные люди настолько заблуждаются, что действительно верят, что это правда.Проблема, которую вы упоминаете в C и C ++ с путями кода, которые не возвращают значение, на самом деле не учитывает примитивные компиляторы. Это позволяет десятилетиями существовать код , некоторые из которых никто не хочет исправлять, трогать или даже читать. Он древний и уродливый, но работает, и никто не хочет ничего, кроме как продолжать работать. Что бы там ни было, языковые комитеты в значительной степени застряли на поддержании такой обратной совместимости, поэтому они продолжают разрешать вещи, которые никому не нравятся - но некоторые люди (по крайней мере, думают, что они) нужны.
источник
csc
сдается.