Информация об изменениях

Сообщение Re[4]: Чем плох Паскаль? от 14.06.2019 11:17

Изменено 14.06.2019 11:19 netch80

Re[4]: Чем плох Паскаль?
Здравствуйте, Александр Кузнецов, Вы писали:
ARK>>Я вам открою страшную тайну: все "современные" языки программирования (по крайней мере из числа более-менее использующихся на практике) имеют немало неоднозначностей в синтаксисе. А в Ц++ этих неоднозначностей столько, что даже парсинг кода не может быть выполнен без семантического анализа.

АК>Если честно, то на вскидку не могу припомнить ни одной. Либо мозг уже давно привык эти неоднозначности вполне себе однозначно разбирать, либо в командах, в которых мне приходилось работать, всегда слишком строгое соблюдение coding style было.


Есть два разных понимания "неоднозначности синтаксиса": одно — для того, кто пишет код, другое — для парсера. Частично они пересекаются, конечно.

Для того, кто пишет, важны, например, такие вещи, что в if, else, while нужно строить блок вокруг нескольких предложений, а в repeat-until — нет; что в конце main надо ставить точку после end, а у остальных — точку с запятой; что var идёт перед основным телом; что and и or почему-то приоритетнее сравнений; ну и так далее.

В моём первом ответе в тему я описывал именно такие неоднозначности; формально корректнее было бы их назвать граблями, странностями и так далее, но так как они приводят к "стоп, ой, тут надо писать иначе", то они могут сойти и за неоднозначности.

Второе — это таки что нужно делать парсеру, чтобы понять, как этот код интерпретировать. Тут Паскаль по лёгкости и однозначности разбора если не на первом месте, то близко к тому. Конечно, LISP с его LL(0)/LR(0) он не победит. Но ряд вещей в Паскале намеренно сделан в сторону облегчения разбора до уровня, когда нет никаких вариантов для отката и надо заглядывать не более чем на одну лексему: например, поэтому перед else не полагается ';', а метки для goto сделаны числами (иначе, увидев aaa, было бы ещё неясно, это aaa := 3 или aaa: bbb := 4).

А вот C++ представляет собой один из наиболее кошмарных в этом смысле примеров. Даже имея простое x *y; , вы не знаете, не проверив типы всех элементов, это объявление y как указатель на x или умножение x на y, которое имеет важные тут побочные эффекты. При том, что что такое x, может быть объявлено ниже по телу определения класса, это значит, что выбор между вариантами надо отложить.
Другой классический пример вида A B(C); точно так же откладывается до выяснения, что такое C. Подробнее, например, тут. Или вот такой пример. Или проблема с ">>", про которое заранее неизвестно, это закрытие двух шаблонов за раз или оператор сдвига (и при этом вполне может быть что-то вроде aaa<bbb<(ccc>>ddd)>>, потому что параметрами шаблона могут быть константные числа).

Но программист с этими проблемами C++ обычно не сталкивается — до тех пор, пока не обнаруживает, что A B(C); вдруг стало не тем, чем он хочет — тогда он меняет () на {} и забывает о проблеме.

Так что — определитесь, о чём вы. Если о неоднозначностях для парсинга, то вам пора таки обновить своё понимание в этой области. Если для пишущего...
вот честно говоря, написать сложную конструкцию серьёзнее, чем a (*b)()[3]; без бутылки будет трудновато. Так что C/C++ и в этом смысле ой.
Re[4]: Чем плох Паскаль?
Здравствуйте, Александр Кузнецов, Вы писали:
ARK>>Я вам открою страшную тайну: все "современные" языки программирования (по крайней мере из числа более-менее использующихся на практике) имеют немало неоднозначностей в синтаксисе. А в Ц++ этих неоднозначностей столько, что даже парсинг кода не может быть выполнен без семантического анализа.

АК>Если честно, то на вскидку не могу припомнить ни одной. Либо мозг уже давно привык эти неоднозначности вполне себе однозначно разбирать, либо в командах, в которых мне приходилось работать, всегда слишком строгое соблюдение coding style было.


Есть два разных понимания "неоднозначности синтаксиса": одно — для того, кто пишет код, другое — для парсера. Частично они пересекаются, конечно.

Для того, кто пишет, важны, например, такие вещи, что в if, else, while нужно строить блок вокруг нескольких предложений, а в repeat-until — нет; что в конце main надо ставить точку после end, а у остальных — точку с запятой; что var идёт перед основным телом; что and и or почему-то приоритетнее сравнений; ну и так далее.

В моём первом ответе в тему я описывал именно такие неоднозначности; формально корректнее было бы их назвать граблями, странностями и так далее, но так как они приводят к "стоп, ой, тут надо писать иначе", то они могут сойти и за неоднозначности.

Второе — это таки что нужно делать парсеру, чтобы понять, как этот код интерпретировать. Тут Паскаль по лёгкости и однозначности разбора если не на первом месте, то близко к тому. Конечно, LISP с его LL(0)/LR(0) он не победит. Но ряд вещей в Паскале намеренно сделан в сторону облегчения разбора до уровня, когда нет никаких вариантов для отката и надо заглядывать не более чем на одну лексему: например, поэтому перед else не полагается ';', а метки для goto сделаны числами (иначе, увидев aaa, было бы ещё неясно, это aaa := 3 или aaa: bbb := 4).

А вот C++ представляет собой один из наиболее кошмарных в этом смысле примеров. Даже имея простое x *y; , вы не знаете, не проверив типы всех элементов, это объявление y как указатель на x или умножение x на y, которое имеет важные тут побочные эффекты. При том, что что такое x, может быть объявлено ниже по телу определения класса, это значит, что выбор между вариантами надо отложить.
Другой классический пример вида A B(C); точно так же откладывается до выяснения, что такое C. Подробнее, например, тут. Или вот такой пример. Или проблема с ">>", про которое заранее неизвестно, это закрытие двух шаблонов за раз или оператор сдвига (и при этом вполне может быть что-то вроде aaa<bbb<(ccc>>ddd)>>, потому что параметрами шаблона могут быть константные числа).

Но программист с этими проблемами C++ обычно не сталкивается — до тех пор, пока не обнаруживает, что A B(C); вдруг стало не тем, чем он хочет — тогда он меняет () на {} и забывает о проблеме.

Так что — определитесь, о чём вы. Если о неоднозначностях для парсинга, то вам пора таки обновить своё понимание в этой области. Если для пишущего...
вот честно говоря, написать сложную конструкцию серьёзнее, чем a (*b)()[3]; без бутылки будет трудновато. Так что C/C++ и в этом смысле ой.