так вас производительность волнует или разбухание?
Насколько я знаю разбухание кода неизбежно сказывается на производительности. Но т.к. вы явно обозначили, что производительность не является целью статьи, но не буду больше развивать эту тему. Мне этой информации в статье не хватило, о чем я вам и сказал. Сами решайте нужно к этому мнению прислушиваться или нет.
прошу обратить внимание, что статья была не о производительности.
Вы это уже говорили. Но тут появилась еще одна ветка обсуждения. Претензии к тому, кто ее начал :)
были обозначены проблемы и пути их решения.
С этим как раз все понятно.
почему бы не поговорить о сути статьи?
Потому что лично для меня суть не раскрыта полностью без обсуждения накладных расходов. Ваш основной тезис – trace points можно расставлять в коде по надобности и не сильно заботиться о том, что они негативно сказываются на производительности. Зато в любой момент их можно активировать и увидеть то, что поможет найти проблему. С этим OK ровно до тех пор, пока накладные расходы реально низкие. А вот так это или нет… Предлагаете праздному читателю самому скачать вашу библиотеку и устроить бенчмарк?
и если вы хотите сказать, что все это разбухание функции f() из-за единственного LogmeTPt – это все совершенно бесплатно, то мне остается еще раз повторить: приведите цифры, пожалуйста.
Слишком много пустых разговоров там, где достаточно было бы сухих цифр. Вы у себя в статье привели в пример код метода ParseHeaders. Вот и озвучили бы замеры – без trace points вообще и с отключенными trace points.
Там дело не только в if-е. А в том, что код с trace point-ами будет выглядеть как куча if-ов с некоторым (подозреваю) не сильно маленьким телом then. Что раздувает код выполняемой функции и это может сказаться общей скорости работы. Поэтому и хотелось бы видеть в статье бенчмарки.
в данном случае я видел свою задачу в том чтобы обсудить проблему как таковую
Ну вот по крайней мере одному читателю этого оказалось недостаточно. А может и не одному, просто одному стало не лень об этом написать.
Что касается подхода, то на обычном логгинге что-то подобное делается либо посредством иерархических логгеров, либо посредством отдельных объектов-логгеров (с общим бэк-ендом). Тогда логгеры могут включаться-выключаться независимо и это не требует внесения в проект новых типов сущностей.
Мне кажется, что вы не понимаете суть высказанной мной претензии к вашей статье. Я прекрасно понимаю роль этих ваших trace points. Но ваша статья выглядит откровенно неполной без упоминания того, какие накладные расходы эти самые trace points несут. Типа того, что вот эта процедура вообще без trace points в таком-то бенчмарке показывает время N sec, а с trace points – (N sec + 150ms). Или (N sec + 150 sec).
но в этой реализации “спящий” trace point не похож на обычное отключённое логирование. он не строит сообщение, не форматирует данные, не создаёт контекст, не вызывает backend-ы и не захватывает lock-и
В нормальных системах логирования ничего этого нет, если уровень логирования ниже активного сейчас. Фактически, это один if внутри которого идет одно атомарное чтение этого самого активного уровня. А все, что вы перечислили выполняется только внутри then-а.
Не раскрыта тема накладных расходов на “спящие” trace point. Так-то в нагруженных участках кода даже логирование стараются не оставлять (даже не смотря на то, что из этого логирования по факту остается только лишь один if на проверку log-level), а тут подразумевается большое количество trace point-ов в коде. Они же должны оказывать влияние на скорость и тем, что хотя бы один if делается + размер кода растет за счет наличия таких if-ов.
А если язык недостаточно выразителен, то это невозможно
Это понятно. Но тут можно было бы дать какое-то более понятное описание принципа работы зависимых типов либо просто в текстовом виде, либо в виде псевдокода на C++подобном языке (мол если бы в C++ было вот это и вот это, то…), либо можно было бы дать ссылку на какое-то хорошее описание зависимых типов, понятное для чайников, либо… (варианты всегда есть).
Но приведенный вами пример кода на неизвестном мне языке оказался для меня совершенно бесполезным. О чем я вам и говорю.
написанный вами код на плюсах не показывает, почему ошибок во время исполнения гарантированно не будет.
А он и не может, т.к. это всего лишь незаконченный набросок.
тоже на непонятном вам языке?
На понятном. Но он направлен на то, чтобы показать недостатки “моего подхода” и не поясняет принцип работы зависимых типов. Поэтому он бесполезен.
Еще раз повторю для чего мне пришлось сделать свой набросок. Из вашего рассказа я понял (возможно, ошибочно), что зависимые типы заставляют разработчика сделать две вещи:
Отказаться от использования в качестве индексов простых числовых типов (вроде int-ов, size_t и т.д.). Вместо этого вводится специальный тип, который обозначает “гарантированно валидный индекс”, при применении которого дополнительные проверки в run-time уже не нужны.
Реализовать какой-то механизм порождения экземпляров этого типа.
Что я и попытался выразить примитивным и незавершенным наброском на C++. Там обе эти вещи выражены явным образом.
И я прекрасно понимаю, что это так себе приближение, но в рамках понятных мне вещей это максимум. Поэтому мне не интересно какие недостатки вы найдете в этом примере.
Типы не запрещают написать функцию, которая всегда для данных (i, N/2) возвращает valid_index { i - N/2 }. С завтипами такую функцию написать невозможно. Понимаете эту разницу?
Понимаю.
Или вы считаете, что это ерунда и эта разница несущественная?
Считаю, что она существенная и поэтому мне интересно за счет чего эта разница возникает. Но вместо того, чтобы объяснить зависимые типы “на пальцах” вы критикуете мой C++ный набросок и пытаетесь строить предположения о моей воинственности.
Это был бы ответ джаваскриптера вам, конечно.
Здесь остается только спросить “а этот джаваскриптер, который типа мне что-то отвечает, он с вами сейчас в одной комнате?”
Он бы вас устроил, и вы бы согласились, что int перед age как отдельный сигнал компилятору — это несущественные мелочи и докапывание до столба, или таки нет, таки это ключевой момент?
Тут я уже честно потерял нить ваших предположений о том, кто кому мог бы сказать.
Ведь лучше — приходить в комменты об $X и воспевать $X, не так ли?
Если вас интересует мое мнение, то оно такое: вы решили приходить в статьи про C++ чтобы рассказывать какое C++ говно, вам явно кажется, что такое поведение – это хорошая идея, но для меня это выглядит как форма какого-то растройства. Есть это расстройство на самом деле (как обида на потраченные впустую молодые годы) или нет – не важно, я исхожу только от впечатления которые производят ваши комментарии на меня.
Приходить ли в комменты про $X чтобы воспевать $X?
ХЗ, меня этот вопрос не заботит.
Да, экстраполяция прошлого опыта
Такая экстраполяция – это ваши личные предположения. Вы что-то себе предположили, а затем выдали это в качестве оценки для собеседника. Грубо говоря: “сами нафантазировали, сами побежали опровергать”.
Желание не понимать начинает становиться воинственным, ну да ладно.
Когда-то вам показалось, что потратить молодость на изучение С++ – это хорошая идея. Потом вам показалось, что приходить в комментарии к статьям про С++ и рассказывать какое C++ говно – это хорошая идея. Теперь вам кажется, что в моих словах есть что-то воинственное.
Попробую еще раз донести до вас простую мысль: если вы хотите объяснить что-то собеседнику, то хорошо бы это делать на том уровне и на том языке, который понятен вашему собеседнику (а не вам лично). Я вот даже не понял что за язык использован в вашем примере кода – Haskell, Agda или Idris. Соответственно, для меня нет ни вашего примера, ни вашего пояснения.
Я уже подробно написал выше, почему этот перевод так себе.
То, что вы написали, есть не более чем “доколупаться до столба”. Мой пример призван был всего лишь показать, что индекс, который программа может считать безопасным для использования, выражается отдельным типом (а не простым size_t или int-ом, как это сейчас массово встречается в реальном C++ном коде). А производят экземпляры этого типа специальные функции, внутри которых делаются необходимые проверки.
Все это набросано за полторы-две минуты в комментарии, уж проссыте, что там не было уделено внимания тем деталям, до которых вы докопались.
Жаль, что понимания таких простых вещей у вас нет, но т.к. общаюсь с вами не в первый раз, то ничуть не удивлен.
в этот раз попробую аналогией
Ну и зря. У вас не получилось. Ожидаемо.
это как если бы вы объясняли джаваскриптеру концепцию проверки типов C++, говоря, что предлагается просто писать
Я бы так не объяснял. А вот вы, вполне возможно. С тем же результатом, с которым вы здесь попытались “объяснить” мне подход с зависимыми типами.
Сам я на Conan давно забил, делаю обновления только на vcpkg. Но и там были случаи, когда принятия PR нужно было ждать неделями.
или оставляем всё как было
Не понимаю такой двоичной логики. Есть еще вариант – комитет таки перестает вредить (шутка) и рожает наконец стандартное описание зависимостей. Тогда все будут описывать зависимости проектов в стандартом виде. Просто не обязательно собирать готовые рецепты в одном месте (как это сейчас происходит с Conan и vcpkg).
Помнится, какой-то подкомитет посвященный тулингу в комитете по стандартизации C++ есть. Результатов пока не видно. Но он есть.
Рецепты хранятся вместе с кодом, registry можно зеркалировать и поднимать свои
Это хорошо для внутрикорпоративных разработок. Сделал зеркало и бодаешься с ним сам потом.
А если делаешь какую-то программку для себя или собственную библиотеку, то это уже оверкилл, как по мне. Между тем, каких-то зависимостей в Conan-е может не быть (или там какие-то старые версии).
Статья затрагивает сразу несколько важных аспектов и OpenSource здесь только один из. Возможно даже не самый важный.
Позволю себе заострить внимание вот на каком моменте: имхо, системы управления зависимостями для C++ не должны быть централизованными (как это происходит с Conan и vcpkg). Вместо того, чтобы сделать рецепт для условной библиотеки X (которая зависит от Y и Z) и отправить PR на включение этого рецепта в Conan/vcpkg, было бы лучше опубликовать этот рецепт где-то отдельно. Например, в репозитории библиотеки X.
В рецепте для X были бы ссылки на аналогичные рецепты для Y и Z, что-то вроде (синтаксис условный):
При загрузке зависимостей сперва бы сходили в репозиторий X, достали бы оттуда рецепт. Потом сходили бы по репозиториям, которые описаны в рецепте X, достали бы оттуда информацию и т.д.
При такой распределенной структуре можно было бы не зависеть от того, что в условный conan-center PR могут принимать неделями. Да и для каких-то библиотек можно собственные рецепты писать и поддерживать (даже если авторы библиотек не хотят потом эти рецепты к себе в апстрим забирать).
Объяснение было? Простите, если оно было, то оно было расчитано на людей, гораздо более умных и эрудированных, чем я, поэтому оно прошло совершенно мимо меня.
Ну вообще да
Ну вообще нет.
в вашем коде это просто вопрос соглашения между программистами: мы договорились, что valid_index точно валидный
Мой код – это всего лишь попытка перевести то, что я (не)понял из ваших объяснений и примера кода на неизвестном мне языке программирования на псевдокод на C++ (который, полагаю, гораздо лучше понятен читателям данной статьи). А именно – вводится тип, который означает “валидный индекс” и работа далее ведется именно через экземпляры этого типа, посему дополнительные проверки при обращении к вектору посредством таких экземпляров уже не нужны.
Насколько я знаю разбухание кода неизбежно сказывается на производительности. Но т.к. вы явно обозначили, что производительность не является целью статьи, но не буду больше развивать эту тему. Мне этой информации в статье не хватило, о чем я вам и сказал. Сами решайте нужно к этому мнению прислушиваться или нет.
Пусть будут хотя бы какие-то цифры. Но их нет вообще. Этого, собственно, в статье и не хватило.
Вы это уже говорили. Но тут появилась еще одна ветка обсуждения. Претензии к тому, кто ее начал :)
С этим как раз все понятно.
Потому что лично для меня суть не раскрыта полностью без обсуждения накладных расходов. Ваш основной тезис – trace points можно расставлять в коде по надобности и не сильно заботиться о том, что они негативно сказываются на производительности. Зато в любой момент их можно активировать и увидеть то, что поможет найти проблему. С этим OK ровно до тех пор, пока накладные расходы реально низкие. А вот так это или нет… Предлагаете праздному читателю самому скачать вашу библиотеку и устроить бенчмарк?
Здесь речь идет о том, что наличие LogmeTPt превращает код простой функции:
во что-то вида:
и если вы хотите сказать, что все это разбухание функции f() из-за единственного LogmeTPt – это все совершенно бесплатно, то мне остается еще раз повторить: приведите цифры, пожалуйста.
Полагаю, что вот в этом месте:
Он все-таки не один. Тут есть еще вызовы GetIp(), c_str(), Size().
И еще неизвестно во что разворачивается сам LogmeTPt.
Upd. А разворачивается LogmeTPt отнюдь не совсем в безобидную конструкцию. Там декларация статической переменной, вызов Hit для нее (всегда), проверка флага Registered… И только потом собственно логирование, если оно разрешено.
Слишком много пустых разговоров там, где достаточно было бы сухих цифр. Вы у себя в статье привели в пример код метода ParseHeaders. Вот и озвучили бы замеры – без trace points вообще и с отключенными trace points.
Там дело не только в if-е. А в том, что код с trace point-ами будет выглядеть как куча if-ов с некоторым (подозреваю) не сильно маленьким телом then. Что раздувает код выполняемой функции и это может сказаться общей скорости работы. Поэтому и хотелось бы видеть в статье бенчмарки.
Ну вот по крайней мере одному читателю этого оказалось недостаточно. А может и не одному, просто одному стало не лень об этом написать.
Что касается подхода, то на обычном логгинге что-то подобное делается либо посредством иерархических логгеров, либо посредством отдельных объектов-логгеров (с общим бэк-ендом). Тогда логгеры могут включаться-выключаться независимо и это не требует внесения в проект новых типов сущностей.
Мне кажется, что вы не понимаете суть высказанной мной претензии к вашей статье. Я прекрасно понимаю роль этих ваших trace points. Но ваша статья выглядит откровенно неполной без упоминания того, какие накладные расходы эти самые trace points несут. Типа того, что вот эта процедура вообще без trace points в таком-то бенчмарке показывает время N sec, а с trace points – (N sec + 150ms). Или (N sec + 150 sec).
В нормальных системах логирования ничего этого нет, если уровень логирования ниже активного сейчас. Фактически, это один if внутри которого идет одно атомарное чтение этого самого активного уровня. А все, что вы перечислили выполняется только внутри then-а.
Не раскрыта тема накладных расходов на “спящие” trace point. Так-то в нагруженных участках кода даже логирование стараются не оставлять (даже не смотря на то, что из этого логирования по факту остается только лишь один if на проверку log-level), а тут подразумевается большое количество trace point-ов в коде. Они же должны оказывать влияние на скорость и тем, что хотя бы один if делается + размер кода растет за счет наличия таких if-ов.
Вы глубоко заблуждаетесь. Впрочем, как и обычно.
Это понятно. Но тут можно было бы дать какое-то более понятное описание принципа работы зависимых типов либо просто в текстовом виде, либо в виде псевдокода на C++подобном языке (мол если бы в C++ было вот это и вот это, то…), либо можно было бы дать ссылку на какое-то хорошее описание зависимых типов, понятное для чайников, либо… (варианты всегда есть).
Но приведенный вами пример кода на неизвестном мне языке оказался для меня совершенно бесполезным. О чем я вам и говорю.
А он и не может, т.к. это всего лишь незаконченный набросок.
На понятном. Но он направлен на то, чтобы показать недостатки “моего подхода” и не поясняет принцип работы зависимых типов. Поэтому он бесполезен.
Еще раз повторю для чего мне пришлось сделать свой набросок. Из вашего рассказа я понял (возможно, ошибочно), что зависимые типы заставляют разработчика сделать две вещи:
Отказаться от использования в качестве индексов простых числовых типов (вроде int-ов, size_t и т.д.). Вместо этого вводится специальный тип, который обозначает “гарантированно валидный индекс”, при применении которого дополнительные проверки в run-time уже не нужны.
Реализовать какой-то механизм порождения экземпляров этого типа.
Что я и попытался выразить примитивным и незавершенным наброском на C++. Там обе эти вещи выражены явным образом.
И я прекрасно понимаю, что это так себе приближение, но в рамках понятных мне вещей это максимум. Поэтому мне не интересно какие недостатки вы найдете в этом примере.
Понимаю.
Считаю, что она существенная и поэтому мне интересно за счет чего эта разница возникает. Но вместо того, чтобы объяснить зависимые типы “на пальцах” вы критикуете мой C++ный набросок и пытаетесь строить предположения о моей воинственности.
Здесь остается только спросить “а этот джаваскриптер, который типа мне что-то отвечает, он с вами сейчас в одной комнате?”
Тут я уже честно потерял нить ваших предположений о том, кто кому мог бы сказать.
Если вас интересует мое мнение, то оно такое: вы решили приходить в статьи про C++ чтобы рассказывать какое C++ говно, вам явно кажется, что такое поведение – это хорошая идея, но для меня это выглядит как форма какого-то растройства. Есть это расстройство на самом деле (как обида на потраченные впустую молодые годы) или нет – не важно, я исхожу только от впечатления которые производят ваши комментарии на меня.
Приходить ли в комменты про $X чтобы воспевать $X?
ХЗ, меня этот вопрос не заботит.
Такая экстраполяция – это ваши личные предположения. Вы что-то себе предположили, а затем выдали это в качестве оценки для собеседника. Грубо говоря: “сами нафантазировали, сами побежали опровергать”.
Когда-то вам показалось, что потратить молодость на изучение С++ – это хорошая идея. Потом вам показалось, что приходить в комментарии к статьям про С++ и рассказывать какое C++ говно – это хорошая идея. Теперь вам кажется, что в моих словах есть что-то воинственное.
Попробую еще раз донести до вас простую мысль: если вы хотите объяснить что-то собеседнику, то хорошо бы это делать на том уровне и на том языке, который понятен вашему собеседнику (а не вам лично). Я вот даже не понял что за язык использован в вашем примере кода – Haskell, Agda или Idris. Соответственно, для меня нет ни вашего примера, ни вашего пояснения.
То, что вы написали, есть не более чем “доколупаться до столба”. Мой пример призван был всего лишь показать, что индекс, который программа может считать безопасным для использования, выражается отдельным типом (а не простым size_t или int-ом, как это сейчас массово встречается в реальном C++ном коде). А производят экземпляры этого типа специальные функции, внутри которых делаются необходимые проверки.
Все это набросано за полторы-две минуты в комментарии, уж проссыте, что там не было уделено внимания тем деталям, до которых вы докопались.
Жаль, что понимания таких простых вещей у вас нет, но т.к. общаюсь с вами не в первый раз, то ничуть не удивлен.
Ну и зря. У вас не получилось. Ожидаемо.
Я бы так не объяснял. А вот вы, вполне возможно. С тем же результатом, с которым вы здесь попытались “объяснить” мне подход с зависимыми типами.
Чуть меньше чем все.
Как будто отправляя рецепт в Conan или в vcpkg вы поступаете как-то иначе.
Что в рецепте Conan-а, что в порте vcpkg лежат точно такие же внешние ссылки, которые склонны умирать, устаревать и просто бесследно исчезать ©
PS. Предлагаю воздержаться от продолжения этого бесполезного обсуждения ваших глупостей.
Это слишком сильное и, полагаю, бездоказательное утверждение.
О том, к чему это ведет, видно из статьи.
Сам я на Conan давно забил, делаю обновления только на vcpkg. Но и там были случаи, когда принятия PR нужно было ждать неделями.
Не понимаю такой двоичной логики. Есть еще вариант – комитет таки перестает вредить (шутка) и рожает наконец стандартное описание зависимостей. Тогда все будут описывать зависимости проектов в стандартом виде. Просто не обязательно собирать готовые рецепты в одном месте (как это сейчас происходит с Conan и vcpkg).
Помнится, какой-то подкомитет посвященный тулингу в комитете по стандартизации C++ есть. Результатов пока не видно. Но он есть.
Это хорошо для внутрикорпоративных разработок. Сделал зеркало и бодаешься с ним сам потом.
А если делаешь какую-то программку для себя или собственную библиотеку, то это уже оверкилл, как по мне. Между тем, каких-то зависимостей в Conan-е может не быть (или там какие-то старые версии).
Статья затрагивает сразу несколько важных аспектов и OpenSource здесь только один из. Возможно даже не самый важный.
Позволю себе заострить внимание вот на каком моменте: имхо, системы управления зависимостями для C++ не должны быть централизованными (как это происходит с Conan и vcpkg). Вместо того, чтобы сделать рецепт для условной библиотеки X (которая зависит от Y и Z) и отправить PR на включение этого рецепта в Conan/vcpkg, было бы лучше опубликовать этот рецепт где-то отдельно. Например, в репозитории библиотеки X.
В рецепте для X были бы ссылки на аналогичные рецепты для Y и Z, что-то вроде (синтаксис условный):
В проекте, где потребовался бы X, было бы что-то вроде:
При загрузке зависимостей сперва бы сходили в репозиторий X, достали бы оттуда рецепт. Потом сходили бы по репозиториям, которые описаны в рецепте X, достали бы оттуда информацию и т.д.
При такой распределенной структуре можно было бы не зависеть от того, что в условный conan-center PR могут принимать неделями. Да и для каких-то библиотек можно собственные рецепты писать и поддерживать (даже если авторы библиотек не хотят потом эти рецепты к себе в апстрим забирать).
Объяснение было? Простите, если оно было, то оно было расчитано на людей, гораздо более умных и эрудированных, чем я, поэтому оно прошло совершенно мимо меня.
Ну вообще нет.
Мой код – это всего лишь попытка перевести то, что я (не)понял из ваших объяснений и примера кода на неизвестном мне языке программирования на псевдокод на C++ (который, полагаю, гораздо лучше понятен читателям данной статьи). А именно – вводится тип, который означает “валидный индекс” и работа далее ведется именно через экземпляры этого типа, посему дополнительные проверки при обращении к вектору посредством таких экземпляров уже не нужны.