LINUX.ORG.RU

Vim или Emacs? А LISP в 2021?

 , ,


1

2

https://www.youtube.com/watch?v=8Q9YjXgK38I&t=42s

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

А ведь Crashbandicoot была годной игрой…

Что выбрать? Vim или Emacs?
Изучать в 2021 году Lisp? Если изучать, какой? Практика?
А не засмеют сотрудики?

Времени в сутках маловато, на всё не хватает.


Ответ на: комментарий от byko3y

Так а замыкания как обрабатываются?

Также. Если замыкание (let ... (lambda () ... (f ...))) и f обновилось, то будет вызываться новая версия. Если обновился код, формирующий замыкание, то естественно текущее значение уже заполненных переменных автоматически не поменяется. Это, в общем, ко всем значениям относится. Также как если в ОС поправишь rc.local, то автоматически значения переменных окружения и запущенные программы не изменятся.

Ты мне предлагаешь руками писать метод для миграции с одной версии кода на другой?

Если предполагается, что для новой версии нужны новые данные, то конечно. Также как в любом линуксовом пакете, который при работе создаёт какие-либо файлы, если код для миграции данных этих файлов для новой версии. Но это лучше, чем идея: вот новая версия ОС, отформатируйте диск и установите.

monk ★★★★★ ()
Ответ на: комментарий от monk

Это не сериализатор — это компонент для работы с файлами.

Нет слов. Ну пусть будет
компонент_для_работы_с_файлами(obj, file)
во всех моих рассуждениях выше

И что? Компонент, умеющий работать с файлами, дергает универсальный сериализатор — это правильное построение управления, «Normal Control», конкретное управляет общим. Универсальный сериализатор, дергающий специальные функции работы с файлом — это плохая организация владения. Именно для плохой организации управления возникает необходимость универсальному алгоритму давать подсказки для конкретных случаев.

byko3y ★★★ ()
Ответ на: комментарий от monk

В файлы писать тоже не умеет?

Честно говоря, не знаю как там это идеоматично делать.

Всё равно надо читать в документации, что write изменяет размер файла, а close прекращает к нему доступ

Это поведение, которому в коде соответствуют явные вызовы функций. Все мои претензии к динамическому связыванию заключались в неявном управлении.

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

Например. Причём сортировка достаточно тривиальный алгоритм. А если чтение рекурсивной структуры типа XML с кучей параметров чтения? Тоже в каждый рекурсивный вызов все параметры переписывать?

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

byko3y ★★★ ()
Ответ на: комментарий от monk

Если замыкание (let ... (lambda () ... (f ...))) и f обновилось, то будет вызываться новая версия. Если обновился код, формирующий замыкание, то естественно текущее значение уже заполненных переменных автоматически не поменяется. Это, в общем, ко всем значениям относится

Я вижу от такого подхода очень много проблем по мере роста сложности. Мой опыт с REPL у Vue говорит, что слишком часто не обновляется то состояние, которое хотелось бы обновить. В принципе, возможно написать код так, чтобы он безупречно выдерживал обновление, но это ОЧЕНЬ СЛОЖНО, если у тебя statefull код (а у меня он именно такой).

Зачем мне тогда твой лисп? Писать stateless hello world-ы и радоваться тому, как они красиво обновляются «на горячую»? У того же питона тоже есть горячая перезагрузка, и у нее точно такая же проблема — если есть состояние, то приложуха после перезагрузки будет глючить. Тестировать и отлаживать перезагрузку? Зачем? Мне заняться больше нечем?

Если предполагается, что для новой версии нужны новые данные, то конечно. Также как в любом линуксовом пакете, который при работе создаёт какие-либо файлы, если код для миграции данных этих файлов для новой версии. Но это лучше, чем идея: вот новая версия ОС, отформатируйте диск и установите

Для справки — постгрес не умеет откатывать БД на предыдущую версию. Не все так просто, миграционные скрипты могут корректно отработать миграции в прямом направлении, но шанс успеха миграции в обратном направлении крайне мал.

byko3y ★★★ ()
Ответ на: комментарий от byko3y

Ты правишь код на удаленном сервере

Иногда надо дебажить что-то

В чем прикол? Поправить конфиги можно и в Nano.

В том что nano ужасно неудобный и ничего не умеет, а вим збс

Aswed ★★★★★ ()
Ответ на: комментарий от byko3y

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

Aswed ★★★★★ ()
Ответ на: комментарий от byko3y

Все мои претензии к динамическому связыванию заключались в неявном управлении.

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

write(stdout, obj, eol=UNIX, buffer=1024, buffered_by=LINE)

а при динамическом просто

write(obj)

где-то выше в блоке определены параметры буферизации и поток по-умолчанию.

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

Вот. Это почти динамические переменные. Почти, потому что у тебя все экземпляры парсера будут работать с одним и тем же замыканием. А если замыкание возвращать из конструктора парсера, то будет практически один-в-один. Разве что динамическими переменными проще несколько однотипных парсеров создавать, не надо каждый раз явно перечислять все параметры.

monk ★★★★★ ()
Ответ на: комментарий от byko3y

В принципе, возможно написать код так, чтобы он безупречно выдерживал обновление, но это ОЧЕНЬ СЛОЖНО, если у тебя statefull код

По-хорошему, надо после обновления перезапускать функции, которые в процессе работы создают данные. Как в UNIX после обновления службы перезапускаются. Именно обновление на ходу делали в Erlang. Поэтому там циклы только через рекурсию, чтобы на очередной итерации можно было заменить функцию. Но это телекоммуникации.

В Common Lisp подход был примерно как в UNIX: если ты обновил httpd, не надо перезагружать всю ОС.

Не все так просто, миграционные скрипты могут корректно отработать миграции в прямом направлении, но шанс успеха миграции в обратном направлении крайне мал.

В Common Lisp также. Метод update-instance-for-redefined-class в обновлённом пакете должен знать про формат предыдущей версии для правильного перехода.

monk ★★★★★ ()
Ответ на: комментарий от monk

При динамическом связывании неявного управления нет. Вся разница, что при явном указании ты пишешь
write(stdout, obj, eol=UNIX, buffer=1024, buffered_by=LINE)
а при динамическом просто
write(obj)
где-то выше в блоке определены параметры буферизации и поток по-умолчанию

Вот в этом и проблема — «где-то выше». А может быть и ниже, а может быть в другом файле. Лексическое связывание гарантирует, что параметр объявлен выше в этом блоке. Если у нас есть глобальные параметры по умолчанию, то они глобальны и неизменны — внешний вызыватель не поменяет их неожиданно для нас.

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

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

Вот. Это почти динамические переменные. Почти, потому что у тебя все экземпляры парсера будут работать с одним и тем же замыканием. А если замыкание возвращать из конструктора парсера, то будет практически один-в-один

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

Vim или Emacs? А LISP в 2021? (комментарий)

byko3y ★★★ ()
Ответ на: комментарий от monk

По-хорошему, надо после обновления перезапускать функции, которые в процессе работы создают данные. Как в UNIX после обновления службы перезапускаются. Именно обновление на ходу делали в Erlang. Поэтому там циклы только через рекурсию, чтобы на очередной итерации можно было заменить функцию. Но это телекоммуникации.
В Common Lisp подход был примерно как в UNIX: если ты обновил httpd, не надо перезагружать всю ОС

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

Метод update-instance-for-redefined-class в обновлённом пакете должен знать про формат предыдущей версии для правильного перехода

Что значит «должен знать»? Я его должен написать потому Я должен знать, про формат предыдущей версии и написать правильный переход. А зачем мне это нужно?

byko3y ★★★ ()
Ответ на: комментарий от byko3y

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

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

Вот ты смотришь на некий кусок кода — что тебе дает гарантию того, что внешний код вызовет его именно с теми параметрами, которые ты ждешь?

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

monk ★★★★★ ()
Ответ на: комментарий от byko3y

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

В коммутаторе? Erlang для телекоммуникаций.

Я его должен написать потому Я должен знать, про формат предыдущей версии и написать правильный переход. А зачем мне это нужно?

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

monk ★★★★★ ()
Ответ на: комментарий от monk

Для new() есть вариант с Option?

Есть. Пока в найтли, да.

Также как в Си.

Как будто что-то хорошее.

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

Не согласен. Там ведь написано, что если рантайм проверки не отключать (целиком или локально), то будет «нормальное падение» (то есть определённое и конкретное поведение), а не UB в общепринятом понимании.

По моему уж лучше когда «почти то же самое» называют иначе (исключения/паника), чем когда вот так переиспользуют устоявшийся термин.

DarkEld3r ★★★★★ ()
Ответ на: комментарий от DarkEld3r

Как будто что-то хорошее.

Иначе мы получаем минусы исключений (программа может внезапно упасть на любой функции) без их плюсов (исключение можно корректно обработать).

то будет «нормальное падение»

Где?

«Most undefined behavior that cannot be detected at compile-time can be detected at runtime. In these cases, Zig has safety checks.»

Most ≠ All. То есть, что-то проверит, но никаких гарантий не даёт.

Да, в Си при UB тоже программа может выдать сообщение об ошибке. Но не обязана.

monk ★★★★★ ()
Ответ на: комментарий от monk

Иначе мы получаем минусы исключений (программа может внезапно упасть на любой функции) без их плюсов (исключение можно корректно обработать).

Кажется, я потерял ход мысли. Мы ведь как раз получили потенциальное падение в любой функции без возможности это падение перехватить? Ведь язык не предоставляет никаких гарантий отсутствия UB? Только надежда на здравый смысл автора функции, что он туда unreachable не насовал. Ну или не ошибся. В общем, действительно как в С, но хорошего в этом ничего не вижу.

Most ≠ All. То есть, что-то проверит, но никаких гарантий не даёт.

Ок, гарантий действительно нет. Но всё-таки “most” - это большинство.

Да, в Си при UB тоже программа может выдать сообщение об ошибке. Но не обязана.

А от тут как раз нет. В С (хотя лучше давай говорить о С++, этот язык я лучше знаю) строго описано, что будет: ошибка компиляции, рантайм проверка или UB. Да, компиляторы могут выводить дополнительные предупреждения, но (при условии соответствия стандарту) поведение более строгое, чем «может упадём, а может будет непонятно что». То, что человеку бывает сложно мысленно убедиться в отсутствии UB в коде - это другой вопрос.

DarkEld3r ★★★★★ ()
Ответ на: комментарий от monk

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

«Неожиданно» в том смысле, что они поменялись на несколько вызовов выше. Если тебе нужно передать аргументы на одну вложенность, то динамические привязки не нужны — они нужны как раз для сложносплетенного кода. А я пишу о том, что задача, которую они пытаются решить, не должна иметь место в хорошем коде в принципе.

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

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

Аналогичные динамическим привязкам конструкции, на самом деле, делают в питоне, но на ассоциативных массивах. Да, там нет copy-on-write семантики, но это и не помеха, ведь это один хрен однопоточная шарманка.

byko3y ★★★ ()
Ответ на: комментарий от monk

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

В коммутаторе? Erlang для телекоммуникаций

Да, в коммуникаторе. Считай, что Erlang — это маленькая операционная система.

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

Вот именно: все эти горячие перезагрузки и возобновляемые исключения опираются на то, как я им корректно опишу алгоритмы работы. А мне есть чем заняться, кроме этих «фичей». Потому можно говорить о том, что возобновляемые исключения и перезагрузка УСЛОЖНЯЮТ разработку.

byko3y ★★★ ()
Ответ на: комментарий от DarkEld3r

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

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

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

строго описано, что будет: ошибка компиляции, рантайм проверка или UB.

Здесь также строго описано, что будет UB. Но при UB программа вправе делать проверку (а иногда и ошибку компиляции).

monk ★★★★★ ()
Ответ на: комментарий от byko3y

А как это сделать, если у тебя тут изменился контекст, там костыль подперт?

В любой программе всё равно есть контекст. В виде установленной локали, пути к домашнему каталогу, имени компьютера, операционной системы, версии libc, …

И правильная функция всегда пишется так, чтобы этот контекст правильно учитывать, а не

try:
  config = open("/home/dev/config.txt", "r").read()
catch:
  print("Не удалось прочитать файл конфигурации")
monk ★★★★★ ()
Ответ на: комментарий от byko3y

Аналогичные динамическим привязкам конструкции, на самом деле, делают в питоне, но на ассоциативных массивах. Да, там нет copy-on-write семантики, но это и не помеха, ведь это один хрен однопоточная шарманка.

Ну вот. Потребность ведь есть. И всегда лучше, когда механизм работает хорошо, а не накостылен вручную на ассоциативных массивах.

monk ★★★★★ ()
Ответ на: комментарий от byko3y

Да, в коммуникаторе.

Докер????

Или ты «контейнеры с докерами и оркестраторами» обозвал ерланговских супервизоров?

Считай, что Erlang — это маленькая операционная система.

Ну вот и Common Lisp - это маленькая операционная система. Поэтому и подходы к обновлению функций такие: при обновлении программы операционная система не перезагружается.

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

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

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

monk ★★★★★ ()
Ответ на: комментарий от monk

В любой программе всё равно есть контекст. В виде установленной локали, пути к домашнему каталогу, имени компьютера, операционной системы, версии libc

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

byko3y ★★★ ()
Ответ на: комментарий от monk

Аналогичные динамическим привязкам конструкции, на самом деле, делают в питоне, но на ассоциативных массивах. Да, там нет copy-on-write семантики, но это и не помеха, ведь это один хрен однопоточная шарманка.

Ну вот. Потребность ведь есть. И всегда лучше, когда механизм работает хорошо, а не накостылен вручную на ассоциативных массивах

Вообще-то я писал о том, что это антипаттерн.

byko3y ★★★ ()
Ответ на: комментарий от monk

Или ты «контейнеры с докерами и оркестраторами» обозвал ерланговских супервизоров?

Ну конечно — в каком году возник эрланг, и в каком году возник докер.

Ну вот и Common Lisp - это маленькая операционная система. Поэтому и подходы к обновлению функций такие: при обновлении программы операционная система не перезагружается

Да. Только я что-то не вижу многозадачных распределенных систем на нем. Чот динамические привязки с макросами не помогают.

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

Так-то чистые функции считать даже VS умеет.

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

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

byko3y ★★★ ()
Ответ на: комментарий от MOPKOBKA

Каждый из пунктов – бред сивой кобылы в исполнении несведущего человека, который мог бы поставить софтину и описать свой опыт использования вместо воровства заезженных клише про емакс и превознесения пхпсторма с вскодом. Буквально каждый из пунктов элементарно опровергается, кроме последнего. M-x package-install sensible-user

mazdai ★★ ()
Ответ на: комментарий от mazdai

Ничего не превозносится, просто VSCode и PhpStorm объективно лучше и быстрее.

Или по твоему в Emacs есть Ctrl+C, Ctrl+V, Ctrl+N (хотя бы настройкой) и нормальный современный язык как JavaScript?

MOPKOBKA ()
Ответ на: комментарий от byko3y

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

Локаль может меняться по ходу работы. Журнал может меняться по ходу работы. Соединение с БД может меняться по ходу работы.

monk ★★★★★ ()
Ответ на: комментарий от MOPKOBKA

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

B0B ()
Ответ на: комментарий от MOPKOBKA

Ну а языки похожи, просто синтаксис сначала непривычен. Поляки - странные люди.

B0B ()
Ответ на: комментарий от B0B

Недавно приобщившихся слушать нельзя %) И надо учитывать кому я отвечал. Так то для простого текста Emacs еще долго будет ниче так.

MOPKOBKA ()
Ответ на: комментарий от byko3y

Да. Только я что-то не вижу многозадачных распределенных систем на нем. Чот динамические привязки с макросами не помогают.

Они были. Например, DART. Она одна дала столько прибыли, сколько было потрачено за 30 лет на разработки.

Так-то чистые функции считать даже VS умеет.

В смысле можно их менять не останавливая программу и повторно запускать функцию тестирования?

Я уже отвечал — расплющивать алгоритм и принимать решение на верхнем уровне.

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

monk ★★★★★ ()
Ответ на: комментарий от vM

Нормально - соответствуя норме, без отклонений от неё

Норма - установленное правило или положение, общепринятый порядок

MOPKOBKA ()
Ответ на: комментарий от monk

Локаль может меняться по ходу работы. Журнал может меняться по ходу работы. Соединение с БД может меняться по ходу работы

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

byko3y ★★★ ()
Ответ на: комментарий от monk

Они были. Например, DART. Она одна дала столько прибыли, сколько было потрачено за 30 лет на разработки

Ты не опечатался в названии? Гугл ничего не находит.

В смысле можно их менять не останавливая программу и повторно запускать функцию тестирования?

Можно поменять данные и посчитать от них функцию. Поменять еще данные и снова посчитать от них функцию. Замена функции в выполняющейся программе — это не чистая операция, если что.

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

А я разве писал про обязательные точки? Не обрабатываешь ошибку — падаешь по выходу с общей ошибкой. Вот и вся история.

byko3y ★★★ ()
Ответ на: комментарий от vM

Ctrl+C, Ctrl+V

Это не нормально

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

byko3y ★★★ ()
Последнее исправление: byko3y (всего исправлений: 1)
Ответ на: комментарий от byko3y

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

У мышевозов вставка средней кнопкой. А Alt-W, Ctrl-W не сложнее набрать, чем Ctrl-C, Ctrl-X.

monk ★★★★★ ()
Ответ на: комментарий от byko3y

Замена функции в выполняющейся программе — это не чистая операция, если что.

Замена чистой функции, на которую нет сохранённых указателей - чистая.

Не обрабатываешь ошибку — падаешь по выходу с общей ошибкой.

Я про твой вариант «расплющивать алгоритм и принимать решение на верхнем уровне». В питоне, конечно, можно всюду напихать yield, но необходимость цикла всюду вместо функций останется.

monk ★★★★★ ()
Ответ на: комментарий от byko3y

рука лежит в левом нижнем углу клавы, и кнопки сами нажимаются.

Тогда должны быть кнопки Copy и Paste в левом ряду функциональных клавиш. И дубль между цифровой клавиатурой и основными рядами.

vM ()
Ответ на: комментарий от B0B

Для кого?

Я же ссылку привёл. Для пользователей текстовых редакторов среди пользователей этого форума.

monk ★★★★★ ()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)