Вы не поверите, на питоне я буду писать скрипты не более 500 строк (примерно естественно). После этого объёма я возьму компилятор, бьющий по рукам хоть немного. Потому что в динамике любой мало-мальски объёмный рефакторинг — боль.
Проблема «пришибленности» не в мелком размере, а в чертовски неравномерном. На том же UX32LN курсорные клавиши тоже уменьшены — но сама геометрия стрелочного блока сохранена. Здесь же ради «экономии» стрелку «вверх» слили со стрелкой «вниз». Привыкнуть можно, но гораздо сложнее. Я например привык, что средний палец для смены вверх-вниз ощутимо движется через пустоту — которой на ленове нет.
Справедливости ради, мне на моём UX32LN даже нравятся совмещённые курсорные клавиши. Не приходится руку далеко тянуть. После него жать PgUp/PgDn/etc на полноразмерной клавиатуре уже не так удобно. Но «пришибленный» стрелочный блок таки ужасен. Желаю придумавшим это работать на клавиатуре, где их основные рабочие клавиши так же сплющены.
Несколько вопросов:
1. Дизайнеры клавиатуры сами пробовали свой стрелочный блок?
2. Какой тип матрицы экрана? О типе «неплохая» слышу впервые.
3. Что помешало сделать матовое покрытие?
Новость хорошая, конечно.
Плохо что во-первых это надо было делать несколько лет назад, а во-вторых что неизвестно сколько устройств доберётся до Android O.
Хотя нет, если http://en.cppreference.com/w/cpp/thread/async ничего не упускает — всегда или новый поток, или ленивое значение. Однако это всё равно крайне плохое решение. Во-первых, это таки смешивание двух совершенно разных вещей в одну кучу. Во-вторых, что гораздо хуже, выбор производится флагами (!), да к тому же если указаны оба флага, выбор implementation-defined (!!!). В общем грусть-печаль от такой стандартной библиотеки.
Вот в этом и проблема, что смешали в кучу 2 разных инструмента, добавив столь любимую Комитетом горстку implementation-defined. Нет, даже 3. Потому что запуск в эксклюзивном потоке и на тред пуле — две большие разницы.
Чуть-чуть оффтоп. В небезызвестном Minecraft есть мод, добавляющий корову в банке. Для этого надо поставить банку, поставить на неё корову… и уронить сверху наковальню :) Корова оказывается в банке и продолжает давать молоко. Может, это оно и есть?
По моим скромным личным наблюдениям на ниве питона.
Динамика облегчает жизнь где-то до 500 строк. Но чем дальше проект от 500 строк (вверх), тем сильнее она портит жизнь.
Мне кажется, что аннотации типов будут кушать в разы меньше места чем тривиальные юнит-тесты, проверяющие типобезопасность. Так что всё равно net gain.
Подозреваю, как раз наоборот. Потому что наняли пачку лоу-грейдов, которые сбацали чарівне шо-попало на новеньком и красивеньком Node.JS. Не язык делает программу плохой, а кривые руки.
Ну, визитор или не визитор — вопрос конкретного подхода и требований.
Спасибо, буду думать. С exception_ptr действительно как-то многовато мороки выходит.
class AppException: public std::exception
{
// ...
public:
void addContext(ContextData);
private:
std::exception_ptr primalCause;
std::vector<ContextData> contexts;
};
?
Ведь в месте, где вы ловите первое исключение, у вас есть не только само исключение, но и описание контекста, в котором оно возникло (например, ID запроса, параметры сбойной операции и т.д.)
В принципе да, но первичный контекст может быть всё равно слишком "низкоуровневым".
Тут интереснее другое — зачем нужно выстраивать цепочку вложенных исключений.
Смотря что для вас здесь вопрос — сама цепочка или то, что она на исключениях.
Если первое — вполне полезно иметь информацию не только о том, на чём конкретно "свалилась" операция, но и что конкретно при этом происходило. Конечно, идеал — выдавать ровно одно сообщение, точно характеризующее проблему. Но до него ещё как до Луны пешком, и такой подход показался мне более подходящим для плавного перехода.
Если второе — допускаю, что это не лучшее решение. Альтернативы — использовать один объект исключения, который содержит "стек" описаний контекстов и дополняет его новыми в процессе раскрутки, когда проходит через промежуточные try-catch.
Для системного программирования альтернатива в виде Rust-а появилась совсем недавно. Да и присутствие в этой нише того же Rust-а пока минимальное.
Я большой фанат Rust, и именно поэтому не хотел примешивать его в эту дискуссию — чтобы не разводить холивар. Тем более, по вашим собственным словам, его присутствие в нише системного программирования минимальное.
На счет корявости раскрутки исключений. Есть ощущение, что коряво это выглядит так, потому, что мало кому нужно использовать исключения именно таким образом.
Допускаю, что я их неправильно готовлю. Но, опять же, единственный способ вытрясти информацию о вложенном исключении — перевыбросить его и тут же поймать. Плюс я хотел иметь логику "раскрутки" такой цепочки отдельно от логики обработки каждого отдельного исключения.
К примеру, в iostreams ошибки репортятся через состояние объекта. filesystem имеет отдельный набор перегрузок, которые возвращают код ошибки. Т.е. такое впечатление, что со стратегией не определились до сих пор.
Другое дело, что сейчас модно и молодежно в АглТД и паттерн-матчинг.
Дело даже не в этом. Я показывал выше, что "раскрутка" цепочки исключений выглядит коряво. Ещё более коряво и многословно выглядит работа через result. Это при том, что С++ частенько используют в системном программировании, где исключения отключены.
В модели с исключениями меня, как правило, вообще не интересует, какое именно исключение вылетит и почему.
Могу поспорить, что в модели с Result-типами вас это будет тоже интересовать максимум на уровне сведения типов.
Но у вас явно другая специфика, раз вам нужно понимать что именно выскочило.
Как ни странно, у меня сейчас банальнейший виндесктоп. И мне как раз не надо особо понимать, что вылетело, пока я не соберусь это ловить. Просто не очень нравится ситуация с тем, что в стандарт накидали и исключений, и кодов возврата, но при этом не продумали нормального механизма работы ни с тем, ни с другим. Более того, стандартная библиотека не придерживается единой схемы обработки ошибок.
в котором обращение к get_base() и get_seed() может приводить к преждевременному возврату с каким-то значением Error
В модели с исключениями вы этого не увидите вообще никак, не проверив код обоих функций и перегруженного оператора сложения (если он перегружен конечно). Но давайте не будем углубляться в спор "исключения против кодов возврата". Меня лично устроил бы просто макрос примерно того вида, что я привёл в своём ответе выше.
Вы не поверите, на питоне я буду писать скрипты не более 500 строк (примерно естественно). После этого объёма я возьму компилятор, бьющий по рукам хоть немного. Потому что в динамике любой мало-мальски объёмный рефакторинг — боль.
1. Дизайнеры клавиатуры сами пробовали свой стрелочный блок?
2. Какой тип матрицы экрана? О типе «неплохая» слышу впервые.
3. Что помешало сделать матовое покрытие?
Плохо что во-первых это надо было делать несколько лет назад, а во-вторых что неизвестно сколько устройств доберётся до Android O.
Хотя нет, если http://en.cppreference.com/w/cpp/thread/async ничего не упускает — всегда или новый поток, или ленивое значение. Однако это всё равно крайне плохое решение. Во-первых, это таки смешивание двух совершенно разных вещей в одну кучу. Во-вторых, что гораздо хуже, выбор производится флагами (!), да к тому же если указаны оба флага, выбор implementation-defined (!!!). В общем грусть-печаль от такой стандартной библиотеки.
Вот в этом и проблема, что смешали в кучу 2 разных инструмента, добавив столь любимую Комитетом горстку implementation-defined. Нет, даже 3. Потому что запуск в эксклюзивном потоке и на тред пуле — две большие разницы.
Для начала, std::async из с++ это просто потоковая функция с гардом, на котором можно подождать окончания и получить результат. Полный аналог https://doc.rust-lang.org/std/thread/fn.spawn.html. Если хотите полноценной асинхронности — https://tokio.rs/
По моим скромным личным наблюдениям на ниве питона.
Динамика облегчает жизнь где-то до 500 строк. Но чем дальше проект от 500 строк (вверх), тем сильнее она портит жизнь.
Мне кажется, что аннотации типов будут кушать в разы меньше места чем тривиальные юнит-тесты, проверяющие типобезопасность. Так что всё равно net gain.
Ну, визитор или не визитор — вопрос конкретного подхода и требований.
Спасибо, буду думать. С exception_ptr действительно как-то многовато мороки выходит.
Т.е. вы бы сделали что-то вроде
?
В принципе да, но первичный контекст может быть всё равно слишком "низкоуровневым".
Смотря что для вас здесь вопрос — сама цепочка или то, что она на исключениях.
Если первое — вполне полезно иметь информацию не только о том, на чём конкретно "свалилась" операция, но и что конкретно при этом происходило. Конечно, идеал — выдавать ровно одно сообщение, точно характеризующее проблему. Но до него ещё как до Луны пешком, и такой подход показался мне более подходящим для плавного перехода.
Если второе — допускаю, что это не лучшее решение. Альтернативы — использовать один объект исключения, который содержит "стек" описаний контекстов и дополняет его новыми в процессе раскрутки, когда проходит через промежуточные try-catch.
Я большой фанат Rust, и именно поэтому не хотел примешивать его в эту дискуссию — чтобы не разводить холивар. Тем более, по вашим собственным словам, его присутствие в нише системного программирования минимальное.
Допускаю, что я их неправильно готовлю. Но, опять же, единственный способ вытрясти информацию о вложенном исключении — перевыбросить его и тут же поймать. Плюс я хотел иметь логику "раскрутки" такой цепочки отдельно от логики обработки каждого отдельного исключения.
К примеру, в iostreams ошибки репортятся через состояние объекта. filesystem имеет отдельный набор перегрузок, которые возвращают код ошибки. Т.е. такое впечатление, что со стратегией не определились до сих пор.
Дело даже не в этом. Я показывал выше, что "раскрутка" цепочки исключений выглядит коряво. Ещё более коряво и многословно выглядит работа через result. Это при том, что С++ частенько используют в системном программировании, где исключения отключены.
Могу поспорить, что в модели с Result-типами вас это будет тоже интересовать максимум на уровне сведения типов.
Как ни странно, у меня сейчас банальнейший виндесктоп. И мне как раз не надо особо понимать, что вылетело, пока я не соберусь это ловить. Просто не очень нравится ситуация с тем, что в стандарт накидали и исключений, и кодов возврата, но при этом не продумали нормального механизма работы ни с тем, ни с другим. Более того, стандартная библиотека не придерживается единой схемы обработки ошибок.
В модели с исключениями вы этого не увидите вообще никак, не проверив код обоих функций и перегруженного оператора сложения (если он перегружен конечно). Но давайте не будем углубляться в спор "исключения против кодов возврата". Меня лично устроил бы просто макрос примерно того вида, что я привёл в своём ответе выше.