История изменений
Исправление Gentooshnik, (текущая версия) :
https://www.dreamsongs.com/Separation.html
(Некоторые пропустил)
1. Common Lisp для коммерческих лиспов своего времени - это (спасибо Unununij) как Эсперанто для европейских языков. Язык, который как можно меньше отличается от каждого из них, одновременно избавляющийся от наибольшего количества костылей.
2. Разные неймспейсы лучше читаются если ты редко используешь funcall и function (#'), но хуже, если ты используешь их часто и они превращаются в мусор, занимающий пол кода. Компромисс-с.
3. С одним неймспейсом проще попасть на коллизию имён. Особенно, учитывая что во всех лиспах (даже в «современных» свалках костылей, вроде Clojure) куча стандартных функций не содержит в названии глаголов. У меня случались трудноотлаживаемые коллизии в Scheme, хотя это, наверно, дело привычки.
4. С двумя неймспейсами невозможно без контекста узнать брать у символа значение или функцию. На самом деле профит для метапрограммирования от этого *отрицательный*. «Некоторые программисты придерживаются „основного правила лиспа“ - код наиболее ясный когда требуется минимальное знание контекста, чтобы определить его смысл.» Наличие двух неймспейсов это правило нарушает.
5. Влияние на сложность компиляторов спорное, но наличие специального неймспейса только для функций упрощает вывод типов и, т.о. улучшает оптимизацию.
6. Как видно по (2), общий неймспейс лучше подходит для функционального кода, который лучше параллелизуется. При разработке стандарта Common Lisp о многопоточности речи не было.
7. Неймспейсов на самом деле не 1 и 2, а 5 и 6 соответственно. Честно, я могу вспомнить только 4 (значение, функция, документация, список свойств), а автор все 6 не перечисляет. Но суть в том, что схлопывание двух из них не так значимо, как может показаться на первый взгляд.
8. Что сказал monk. Без гигиенических макросов общий неймспейс сделает ошибочным кучу кода, который будет работать с отдельными неймспейсами. Причина во ВНЕЗАПНЫХ коллизиях в коде, который писал пять лет назад разработчик, которого давно сбил автобус. С отдельными неймспейсами ВНЕЗАПНЫХ коллизий нет. Если они есть, то они на самом деле закономерные и автору нужно бить по рукам линейкой, чтобы аккуратнее писал макросы.
9. Следствие из (8). Без гигиенических макросов фактически приходится сделать выбор между одним неймспейсом и макросами. Разработчики Common Lisp выбрали в пользу макросов.
10. Экономия памяти. Кажется, что с двумя неймспейсами символ занимает в два раза больше памяти, чем с одним. Конечно, тогда нужно чуть больше символов, но пренебрежимо мало, точно не в два раза. На самом же деле вспоминаем, что неймспейсов на самом деле не 1 и 2, а 5 и 6. «второй» неймспейс прибавляет к размеру символа не 100%, а 20%, которые частично экономятся обратно на меньшем количестве символов. Итоговая разница пренебрежимо мала.
11. Ни одно из решений не приведёт к принципиальному ускорению кода, если компилятор однонеймспейсового лиспа достаточно умный. Если недостаточно умный, то двухнеймспейсовый компилятор сделает незначительно более быстрый код.
12. В Common Lisp есть лексические и специальные (динамические) переменные. Переменные объявленные вне функций всегда специальные, неймспейс функций же глобальный. В Scheme всё то же самое, только т.к. нет своего неймспейса для функций, они все лежат в специальных (динамических), а не глобальных переменных. Т.е. если программист случайно использует переменную с названием, совпадающим с названием уже объявленной функции, то получит специальную переменную вместо лексической. Стоит заметить, что в PLT Scheme => Racket использование специальных переменных сильно затруднили, а глобальные декларации сделали лексическими. Опять компромисс, как и с макросами. Либо удобные специальные переменные, либо один неймспейс.
(дальше автор перечисляет несколько теоретических костылей чтобы подружить специальные переменные с одним неймспейсом)
13. Следствие из (1), нужно оставить два неймспейса, т.к. иначе для портирования существующего коа на Common Lisp потребуются слишком значительные изменения кода, и ловля кучи багов из-за коллизий.
14. На момент разработки стандарта один неймспейс был новой идеей, не слишком зарекомендовавшей себя на практике. (Да и сейчас...)
15. Заключение. Есть достаточно серьёзные теоретические доводы в пользу обеих решений, но для Common Lisp главное - сохранить максимум совместимости с существующими коммерческими лиспами, улучшив и упростив там где можно, а упрощать и улучшать ещё можно много где. Поэтому решение что лучше на практике мы оставим дизайнерам будущих лиспов, которые смогут учесть ошибки и Common Lisp, и Scheme.
Исходная версия Gentooshnik, :
https://www.dreamsongs.com/Separation.html
(Некоторые пропустил)
1. Common Lisp для коммерческих лиспов своего времени - это (спасибо Unununij) как Эсперанто для европейских языков. Язык, который как можно меньше отличается от каждого из них, одновременно избавляющийся от некоторых костылей.
2. Разные неймспейсы лучше читаются если ты редко используешь funcall и function (#'), но хуже, если ты используешь их часто и они превращаются в мусор, занимающий пол кода. Компромисс-с.
3. С одним неймспейсом проще попасть на коллизию имён. Особенно, учитывая что во всех лиспах (даже в «современных» свалках костылей, вроде Clojure) куча стандартных функций не содержит в названии глаголов. У меня случались трудноотлаживаемые коллизии в Scheme, хотя это, наверно, дело привычки.
4. С двумя неймспейсами невозможно без контекста узнать брать у символа значение или функцию. На самом деле профит для метапрограммирования от этого *отрицательный*. «Некоторые программисты придерживаются „основного правила лиспа“ - код наиболее ясный когда требуется минимальное знание контекста, чтобы определить его смысл.» Наличие двух неймспейсов это правило нарушает.
5. Влияние на сложность компиляторов спорное, но наличие специального неймспейса только для функций упрощает вывод типов и, т.о. улучшает оптимизацию.
6. Как видно по (2), общий неймспейс лучше подходит для функционального кода, который лучше параллелизуется. При разработке стандарта Common Lisp о многопоточности речи не было.
7. Неймспейсов на самом деле не 1 и 2, а 5 и 6 соответственно. Честно, я могу вспомнить только 4 (значение, функция, документация, список свойств), а автор все 6 не перечисляет. Но суть в том, что схлопывание двух из них не так значимо, как может показаться на первый взгляд.
8. Что сказал monk. Без гигиенических макросов общий неймспейс сделает ошибочным кучу кода, который будет работать с отдельными неймспейсами. Причина во ВНЕЗАПНЫХ коллизиях в коде, который писал пять лет назад разработчик, которого давно сбил автобус. С отдельными неймспейсами ВНЕЗАПНЫХ коллизий нет. Если они есть, то они на самом деле закономерные и автору нужно бить по рукам линейкой, чтобы аккуратнее писал макросы.
9. Следствие из (8). Без гигиенических макросов фактически приходится сделать выбор между одним неймспейсом и макросами. Разработчики Common Lisp выбрали в пользу макросов.
10. Экономия памяти. Кажется, что с двумя неймспейсами символ занимает в два раза больше памяти, чем с одним. Конечно, тогда нужно чуть больше символов, но пренебрежимо мало, точно не в два раза. На самом же деле вспоминаем, что неймспейсов на самом деле не 1 и 2, а 5 и 6. «второй» неймспейс прибавляет к размеру символа не 100%, а 20%, которые частично экономятся обратно на меньшем количестве символов. Итоговая разница пренебрежимо мала.
11. Ни одно из решений не приведёт к принципиальному ускорению кода, если компилятор однонеймспейсового лиспа достаточно умный. Если недостаточно умный, то двухнеймспейсовый компилятор сделает незначительно более быстрый код.
12. В Common Lisp есть лексические и специальные (динамические) переменные. Переменные объявленные вне функций всегда специальные, неймспейс функций же глобальный. В Scheme всё то же самое, только т.к. нет своего неймспейса для функций, они все лежат в специальных (динамических), а не глобальных переменных. Т.е. если программист случайно использует переменную с названием, совпадающим с названием уже объявленной функции, то получит специальную переменную вместо лексической. Стоит заметить, что в PLT Scheme => Racket использование специальных переменных сильно затруднили, а глобальные декларации сделали лексическими. Опять компромисс, как и с макросами. Либо удобные специальные переменные, либо один неймспейс.
(дальше автор перечисляет несколько теоретических костылей чтобы подружить специальные переменные с одним неймспейсом)
13. Следствие из (1), нужно оставить два неймспейса, т.к. иначе для портирования существующего коа на Common Lisp потребуются слишком значительные изменения кода, и ловля кучи багов из-за коллизий.
14. На момент разработки стандарта один неймспейс был новой идеей, не слишком зарекомендовавшей себя на практике. (Да и сейчас...)
15. Заключение. Есть достаточно серьёзные теоретические доводы в пользу обеих решений, но для Common Lisp главное - сохранить максимум совместимости с существующими коммерческими лиспами, улучшив и упростив там где можно, а упрощать и улучшать ещё можно много где. Поэтому решение что лучше на практике мы оставим дизайнерам будущих лиспов, которые смогут учесть ошибки и Common Lisp, и Scheme.