Здравствуйте, Евгений Музыченко, Вы писали:
S>>можно наделить понятие "макроса" еще 100500 дополнительными смыслами.
ЕМ>Нет надобности его чем-то "наделять". Оно изначально предельно общее, буквально вытекающее из смысла слова "macro" (надеюсь, найдете самостоятельно).
А можно поподробнее о макросах, для тех, кто не нашел самостоятельно? Или опять бла-бла?
ЕМ>И оно испокон веку обозначало все, что подпадает под технологию "сгенерировать результат из указанной текстовой конструкции".
Можно ссылку на это определение?
ЕМ>Ну а потом выросли поколения, которые уже знали макросы исключительно по их реализациив в C/C++, m4 и подобных средствах, а про иные способы реализации даже не догадывались, и стали придумывать разные искусственные разделения.
Ну почему же, мы и на макроассемблерах пописывали. А в плюсах нет макросов. Есть поддержка сишных макросов. Их так все и называют: "сишные макросы". И если ты не в курсе, от них многие рекомендуют отказываться.
ЕМ>Настаивая на том, чтоб называть обработку текста программ, выходящую за пределы чисто лексической, непременно "метапрограммированием", а термина "макрос" в данном контексте избегать, попробуйте представить, как будет выглядеть реализация языка с подобным разделением. Вот надо Вам сделать почти чисто текстовую подстановку, но так, чтоб текст содержал, скажем, имя текущей функции. Сейчас для этого есть встроенные макросы вроде __FUNCTION__, но это уже читерство — препроцессор (которым, по-Вашему, обязан быть любой макропроцессор) ни о каких функциях не знает. А в "метаконструкциях для рефлексии" Вам предложат богатый инструментарий для манипуляции типами, объектами, перебора методов классов и т.п., но банальной склейки двух подстрок не дадут, ибо это уже "типичная макрооперация", пожалте в препроцессор. И будете опять изворачиваться в попытках скрестить ежа с ужом, как тот комсомолец, который не может без трудностей.
Ну покажи нам идеальный мета/макро-язык, хоть как его называй, но покажи, а то мы все уже извелись от нетерпения
Здравствуйте, Евгений Музыченко, Вы писали:
S>>В общем, compiler costs, ассоциированные с "семантическими макросами", или там "императивными шаблонами", вряд ли напугают целевую аудиторию плюсов.
ЕМ>Тем более, что эти costs вовсе не ожидаются неизбежно высокими. Тело макроса обычно состоит либо преимущественно из текста с относительно редкими включениями операций, что обрабатывается довольно просто и быстро, либо преимущественно из метаязыка, и тогда возможна предварительная компиляция.
Мы не знаем, из чего состоит тело твоего макроса, потому что ты нам так его и не показал
ЕМ>А уж при наличии прямого доступа ко всей информации, собранной компилятором, реализация многих конструкций, которые сейчас делаются на вложенно-рекурсивных шаблонах, будет достаточно тривиальной. Легко может получиться, что время компиляции даже уменьшится, в ряде случаев — сильно.
А в ряде случаев — со сверхсветовой скорость. Ага. Давай, начинай нам показывать свой макро-язык. Вот ты сам не хочешь ничего писать (в смысле — разрабатывать), так хоть бы описал спеку по своему гениальному макроязыку, будет что-то годное — люди сами реализуют. Но ты не потрудился даже одного примера привести, но зато есть время страдать изо дня в день о несовершенстве мира и C++ в частности
Здравствуйте, Евгений Музыченко, Вы писали:
S>>Если бы в C++ попытались бы развить некие хитрые макросы, которые могут прыгать со стадии препроцессинга в стадию компиляции и обратно
ЕМ>Вы, судя по всему, действительно не понимаете даже принципов предлагаемых идей, поэтому совершенно зря требуете примеров, которые Вам совершенно в этом понимании не помогут.
Так идей никаких и не было, одно бла-бла за всё хорошее
ЕМ>Перечисленные идеи вообще не предполагают препроцессинга, как сколько-нибудь отдельной стадии. Для сохранения совместимости препроцессор, разумеется, придется сохранять и тащить дальше. Но, если делать "умные" макросы, то исключительно внутри компилятора.
Давай ты хотя бы идеи структурированно изложишь (но тут уже да, обычно люди идеи иллюстрируют примерами, и описывают, как это работает, по их мнению. Но ты же выше этого)
ЕМ>Если уж Ваше восприятие настолько прочно залипло на концепции плюсовых шаблонов, то попробуйте вместо "макрос" подставить "шаблон", затем допустить, что шаблон может содержать внутри себя синтаксически бессмысленные конструкции, которые примут осмысленный вид только после подстановки параметров (и не тривиальной, а, возможно, после их определенной обработки), и после этого представить, что внутри шаблона могут быть служебные конструкции метаязыка (желательно похожего на C/C++), на которых можно написать "подпрограмму времени компиляции", которая и обработает заданные параметры, породив код для компилятора.
А сейчас примерно как-то так и работает
ЕМ>Если хоть среднему C++нику, хоть Вам, нужны хотя бы те убогие средства обобщенного программирования, что предоставляет std, то это как раз и для них, и для Вас.
За долгое время чтения твоих сообщений сложилось впечатление, что ты очень мало знаешь об "убогих" средствах обобщенного программирования C++, но очень любишь порассуждать об их убогости
Здравствуйте, Евгений Музыченко, Вы писали:
S>>вы вообще хоть когда-нибудь в конкретику умеете?
ЕМ>Умею, когда это требуется по условиям задачи. Когда же формулируется общая идея, а в ответ требуют "цифры, графики и таблицы", то по ним, как правило, собеседник поймет лишь часть идеи. Какой тогда смысл в конкретике?
Никакой сформулированной общей идеи я не увидел.
ЕМ>Когда речь идет исключительно об общем подходе, это самое адекватное.
К сожалению, мы тут все практики. Это ты у нас чистый теоретик. И мы, как практики, хотим видеть практические примеры, чтобы прикинуть, как это нам на практике можно было бы использовать
S>>Написать что-то конкретное, в виде кода или псевдокода, перечислить конкретные языки или их фичи -- нет от слова совсем.
ЕМ>Конкретные языки с годными макропроцессорами я Вам приводил. Общие принципы описал достаточно подробно. Насколько я понимаю, Вы приличных макропроцессоров вообще не видели даже на примерах — как Вы собираетесь оценивать код, если я таки сподоблюсь разыскать синтаксис и родить пример? Придется или мне давать достаточно подробные пояснения, или Вам что-то почитать про эти технологии.
Конечно придётся давать объяснения
S>>Тем не менее, компилироваться будет в простой и компактный двоичный код.
ЕМ>Ну да, поскольку там простая и очевидная подстановка, не используются ни побочные эффекты, ни вложенные шаблоны, ни рекурсия. А многие ли смогут навскидку хотя бы примерно понять, во что будет компилироваться типичный "магический" шаблон, все это использующий? Чтоб раскрутить всю цепочку мысленно, нужно обладать или удачным устройством мозга, или большим разнообразным опытом, или изрядным терпением.
Зачем мысленно? Зашел на gotbolt, он тебе всё покажет
ЕМ>А если тупо посмотреть на результат в ассемблерный код, и он не понравится, то что делать, кроме как "вернуться к п.1"?
Если тупо смотреть, ничего хорошего не получится. Я думаю, впрочем, ты так на шаблоны и смотришь
ЕМ>Понятно, что и RTTI, и исключений без поддержки компилятора не сделать. Но основная претензия к RTTI и исключениям в C++ в том, что их невозможно включить в программу частично — либо полностью всю кухню, либо никак, что нарушает пресловутый принцип о плате за использование. А если б ставить задачу не в виде "как узнать тип чего угодно когда угодно", а в виде "как получить информацию о типе у компилятора, чтоб далее использовать ее имеющимися средствами языка", то это можно было реализовать хоть в C с любой разумной эффективностью, и оно не тянуло бы за собой лишних зависимостей
Информацию о типе можно узнавать при помощи шаблонов на этапе компиляции, не очень понятно, зачем тут RRTI. RRTI нужна в рантайме. Ты можешь хоть вообще её отключить, и для шаблонов ничего не изменится
ЕМ>Аналогично и с исключениями. Минимальная функциональность исключений — возможность прервать выполнение кода и передать наверх минимально значимый объем информации.
Минимально значимый объем информации — это целое число? Очень полезно, ага
ЕМ>Возможности передавать произвольный объект, который наверху будет автоматически диспетчеризован, при этом не требуется — это уже дополнительное удобство, "сахар", который нетрудно добавить уже имеющимися средствами языка, если потребуются.
И где же исключения делаются средствами языка?
S>>И если вам (не, не вам, а нормальным людям) в проекте нужны и RTTI, и исключения, то нахера им оглядываться на "низкоуровневые и архитектурно-зависимые возможности"?
ЕМ>Вот мне, внезапно, нужны исключения в ядре Windows, и они, внезапно, там есть. И они, опять же внезапно, есть даже в MS VC, который без плюсов. Именно в том самом минимальном варианте — прерывание выполнения, раскрутка стека и передача наверх ровно одного машинного слова — кода ошибки, числа, символа, указателя. Все это обеспечивается непосредственно ОС, это ее неотъемлемое свойство.
ЕМ>Плюсовые исключения, разумеется, реализованы поверх этой функциональности.
С чего бы? Это только под виндой, и, вполне вероятно, только у MSVC
ЕМ>Надо ли говорить, что они тащат за собой хренову гору зависимостей, которые нужны далеко не каждому, но объем которых в несколько раз превышает минимально необходимый, и поэтому в ядре они не поддерживаются?
Здравствуйте, Sinclair, Вы писали:
S>>При этом если программа написана на С++ (а не на поддерживаемым конкретным компилятором диалекте), то она компилируется любым из этих компиляторов. S>
Смех без причины признак дурач .NET-евангелиста, который думает, что разбирается еще в чем-то.
S>>Мне думается, что вы не разбираетесь в предмете. S>В достаточной степени, увы. Ну, то есть я, конечно, в предмете разбираюсь плохо, но по моей статистике те, кто громче всех считает себя С++-профи, чаще всего разбираются в этом предмете ещё хуже, чем я.
Ну тогда попробуйте объяснить вот это:
Но ведь чёрт возьми нет — прямо в стандарте у нас есть всякие implementation-defined специально для того, чтобы вендор мог ставить палки в колёса тем, кто пытается такую штуку сделать.
S>Стадия препроцессинга — это не то, чем стоит гордиться в современном компиляторе.
Либо кто-то не умеет его готовить.
S>>Не слишком рано, время тут не при чем. Критична была совместимость с Си. S>Как совместимость с Си могла помешать реализации модульности?
Можно было бы предложить подумать, но вряд ли это поможет.
S>И что случилось с этой совместимостью в C++20?
На нее забили.
И, как по мне, принятие модулей в стандарт C++ -- это диверсияглупость ошибка, за которую придется расплачиваться еще долгие-долгие годы.
S>>Вы, вероятно, могли еще не родиться вообще, а программистам приходилось писать код на C++ и Си так, чтобы этот код мог компилироваться как Си-шным, так и C++ным компиляторами. S>Я всё-таки постарше С++. И его код никак-никак не мог компилироваться С-шным компилятором.
А я и не говорил, что код на C++ компилировался Сишным компилятором.
S>>Чтобы разрешить макросам порождать новый исходный код, в котором используются другие макросы, требующие своего раскрытия. S>Для этого совершенно необязательно порождать буквы.
Тогда мы говорим и не о макросах. Хотя, если вам макросы привиделись даже в D, то значит вам они везде будут мерещиться.
S>>Например, использование паттерна CRTP дает чуть более производительный код, чем использование обычных виртуальных методов. Но CRTP требуют от программиста сдвига мозгов, которое позволяет осознать, что означает запись S>>
S>>class Derived : public Base<Derived> {...};
S>>
S>О, вот может вы мне объясните подробнее сценарий использования этого трюка — почему нельзя сделать просто S>
Тем, что его написал дебил, который этого не осознает .NET-евангелист пыжащийся в C++.
Одна из задач CRTP на уровне Base реализовать некий алгоритм, который точечно нуждается в уточнениях. Эти уточнения делаются в производных классах через методы, которые в обычном ООП были бы виртуальными. ЕМНИП, называется это template method pattern.
По классике могло бы быть что-то вроде:
class missile_launcher {
public:
void launch() {
... // Куча кода.auto target = lock_target();
... // Куча кода с использованием target.
}
...
private:
virtual target_coordinate lock_target() = 0;
};
class surface_to_air : public missile_launcher<surface_to_air> {
target_coordinate lock_target() override {...}
};
class air_to_air : public missile_launcher<air_to_air> {
target_coordinate lock_target() override {...}
};
Тогда как через CRTP это будет чем-то вроде:
template<typename D>
class missile_launcher {
public:
void launch() {
... // Куча кода.auto target = static_cast<D *>(this)->lock_target();
... // Куча кода с использованием target.
}
...
};
struct surface_to_air : public missile_launcher {
target_coordinate lock_target() {...}
};
struct air_to_air : public missile_launcher {
target_coordinate lock_target() {...}
};
S>>Есть у меня уверенность, что это один из тех "трюков", за которые г.Музыченко ругает шаблоны C++ и который г.Музыченко не нужен. S>А вы точно уверены, что знаете, за что г.Музыченко ругает шаблоны C++?
Не точно. Но я его критику С++ слышу не в первый раз.
S>>А вы точно уверены что знаете за что именно я люблю C++? S>Нет, неточно. Приходится полагаться на ваши собственные слова.
И где же я говорил про свою любовь к низкоуровневым деталям?
Re[29]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, Евгений Музыченко, Вы писали:
S>>Шаблоны не дали радикальных улучшений?
ЕМ>Радикальные улучшения они дали на основном своем применении (для подстановки конкретных типов/значений в абстрактную заготовку). То, что трюковые варианты применения дали возможность еще немного повысить гибкость, я не готов считать радикальными улучшениями. Хотя бы потому, что каждое незначительное повышение гибкости достигалось все более сложными и запутанными комбинациями трюков, а разработчики языка не торопились переносить в язык хотя бы самое основное, вроде условной генерации по is_*/has_.
Ну конечно же это не так. Чем дальше, тем проще пользоваться языком. Ты бы всё-таки попробовал бы вылезти из скорлупы своего невежества
S>>variadic templates не дали радикальных улучшений в сравнении с обычными шаблонами?
ЕМ>Это ж, по сути, чисто количественное улучшение — вместо пачки подстановок стало можно написать одну со списком.
Да. А шаблоны они такие — вместо пачки функций позволяют написать одну универсальную. Тоже ведь чисто количественное улучшение
S>>constexpr/consteval не дал радикальных улучшений?
ЕМ>А это сюда каким боком? Не вижу в них ничего трюкового.
А, то есть тебе обязательно нужно увидеть что-то трюковое? Ну так, за этим в цирк
S>>Может это из-за того, что вы занимаетесь задачами, для которых нужно что-то не сильно выше ассемблера?
ЕМ>В моих задачах найдется немало мест, куда можно было бы вставить шаблонные конструкции из std. И я даже несколько раз пробовал это делать. Но, как уже говорил, все упирается в то, что они реализованы средствами языка, но не имеют возможности избавить меня от знакомства с особенностями своей внутренней реализации.
Не знаю, я как-то вполне пользуюсь всеми прелестями использования std, и понятия не имею об особенностях их внутренней реализации. Ну, единственно, я в целом знаю, какие гарантии дают контейнеры, основные алгоритмы, и тп. Ну и всё.
ЕМ>Будь они сделаны так, чтоб либо работать, либо выдавать, как компилятор, информативное сообщение об ошибке разумного объема, не требующее копания в кишках, то я б, наверное, это как-то пережил.
Ты просто не осилил. Вообще, копаться в кишках стандартной библиотеки я даже не могу представить, зачем бы это могло понадобится. Мне примерно 0 раз это было нужно
S>>новые фичи снижают стоимость реализации тех или иных задач.
ЕМ>Они снижают ее, когда затраты на знакомство с фичами компенсируются выгодами от их использования. Большинство программистов, использующих C++, как я уже подчеркивал, лишь в общих чертах понимает, как работают шаблонные конструкции, активно использующие SFINAE, рекурсию, особенности частных случаев и прочее.
И что? Да, я в общих чертах понимаю, на детальные знания не претендую. Это не мешает мне использовать C++ в полном объёме.
ЕМ>Эти люди сами не смогли бы написать подобные реализации без серьезных затрат на изучение этих механизмов, а то и вообще. Пока им удается на этом уровне понимания более-менее интуитивно вставлять свои параметры в кем-то подготовленные примеры, их работа ускоряется. Когда они упираются в то, что при введении новых типов, или коррекции имеющихся, давным-давно обкатанные фрагменты кода вдруг разваливаются совершенно непонятным для них образом, они предсказуемо впадают в ступор. А дальше все определяется тем, насколько быстро получится угадать, почему так получилось.
Я примерно так и изучаю плюсики. Пишу так, как умею. Потому начинаю хотеть что-то, что ещё могло бы мне упростить жизнь. Иногда бывают проблемы, самому не всегда удаётся разобраться, тогда спрашиваю у зала, и/или гугл. Но это от лени. Неленивый человек хотя бы пролистал бы стандарт, я же в него заглядываю крайне редко.
ЕМ>Если уж довольно серьезные и опытные люди периодически заявляют об отказе от использования трюковых методов, а то и о возврате к чистому C, то проблема явно существует не только в уме отдельно взятого музыченко.
Пример таких серьёзных и опытных людей в студию.
Тут, кстати, пересел на чистую сишечку. Божечки, как там всё убого, сколько долботни тупой приходится делать, и как там всё небезопасно...
S>>в групповой разработке приходится следить за тем, чтобы сложность применяемых элементов языка соответствовала способностям самых слабых участников группы. И чем больше группа, тем внимательнее за этим нужно следить.
ЕМ>Так вся-то беда в том, что на первый взгляд эти элементы вовсе не выглядят сложными — вроде бы понятные имена, список параметров в угловых скобках, подставляй да пользуйся. Он раз подставил — получилось, два — снова получилось, а на третий раз он получает несколько сотен сообщений об ошибках, 95% которых указывают на какие-то служебные файлы, и содержат какие-то исходники, которых у него нет. Подобные впечатления, наверное, были бы от какого-нибудь телевизора на Android, который вместо сообщений "нет сигнала", "источник данных недоступен" и т.п., вываливал бы на экран выдачу logcat.
Осподя, ну взрослый уже дядя, пора бы наконец понять, что это всё наведённые ошибки, и нет смысла их разглядывать, проблему надо начинать искать начиная с начала списка ошибок, а не с конца. Попробуй, и тебе сразу станет проще жить
S>>Само употребление термина "трюк" выглядит неоднозначным. Непонятно что вы под этим понимаете.
ЕМ>Ровно то же самое, что и другие специалисты — использование побочных эффектов от средств, изначально предназначенных для других целей. По сути это то же самое, что арифметические/логические трюки в машинном коде, передача управления "внутрь команды", самомодификация кода и подобное.
Половина современной науки держится на использовании побочных эффектов, а куча всего просто случайно было открыто. Ты же не отказываешься от антибиотиков только потому, что пеницилин был открыт случайно. Или отказываешься?
ЕМ>По мне, такие трюки лежат за границей и разумности
Только по тебе
ЕМ>(потому, что они чрезмерно сложны и непрозрачны),
Не осилил понять
ЕМ>и дозволенности (потому, что позволяют делать нежелательные/опасные вещи, которые трудно обнаружить даже целенаправленным поиском).
Можно тут поподробнее?
ЕМ>Куда правильнее были бы встроенные языковые средства, вроде "принудительного" приведения типов в стиле C,
Вот это как раз огромный источник ошибок. А уж как "шоколадно" в чистой сишечке...
ЕМ>на которые компилятор мог бы по умолчанию выдавать предупреждения.
Ты через полчаса отключил бы их
ЕМ>Тогда и нужный результат бы достигался, если уж иначе невмоготу, и по настройкам предупреждений сразу было бы видно — использует программа подобное жульничество, или она "честная".
Нормальная программа без всякого жульничества компилируется при /Wall /Werror
ЕМ>Суть трюка не меняется от уровня его сложности. Какая разница, достигает фокусник нужного эффекта простым зеркалом или навороченной электронной системой? Суть в том, что он вроде бы честно и открыто показывает вам одно, а за спиной при этом делает совершенно другое. В развлекательных целях это работает отлично, но многие ли захотят нанять фокусника, чтоб он делал такими методами серьезные вещи?
Полупроводники, например, если по тебе, тоже жульничество. Однако ты же почему-то пользуешься электроникой
Здравствуйте, Евгений Музыченко, Вы писали:
S>>с variadic-шаблонами вы можете написать так:
ЕМ>Я и без них могу так написать, только писать придется на макросах, и обработка ошибок будет не менее заморочной.
Покажете?
ЕМ>Неужто Вы не понимаете, что в этом примере constexpr выполняет исключительно формальную роль?
Нет. Я даже не понимаю, что может значить выражение "исключительно формальную роль".
ЕМ>Такое и в традиционных "макросах для препроцессора" имело бы достаточный спрос (и наверняка имеет у тех, кто ими активно пользуется).
В традиционных Си-ных макросах очень скудные возможности. Ну просто очень скудные.
ЕМ>>>В моих задачах найдется немало мест, куда можно было бы вставить шаблонные конструкции из std.
S>>Например?
ЕМ>У меня, как ни удивительно, есть ряд более-менее общих классов и функций, структура и поведение которых меняются в зависимости от контекста. Сейчас там многое сделано на макросах, а будь в языке или std подходящие средства без трюков, я бы с удовольствием их использовал.
Примера я так и не увидел.
В очередной раз.
...пустопорожний бла-бла-бла поскипан...
S>>Я уже пытался вытащить от вас примеры этих самых "побочных эффектов", но не преуспел.
ЕМ>Да Вы ж их сами прекрасно знаете — языковая конструкция, исходно предназначенная для порождения классов/функций, чтобы использовать их сами по себе, стала регулярно применяться для порождения сугубо нефункциональных, костыльных классов, единственная цель существования которых — извлечение отдельных свойств.
Блин, да покажите вы уже пример!
Типа вот код на C++ -- вот в нем используется вот такой-то побочный эффект.
Re[6]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, so5team, Вы писали:
S>Смех без причины признак дурач .NET-евангелиста, который думает, что разбирается еще в чем-то.
Может быть. А может быть — признак человека, который в курсе того, что собираемость программы чуть сложнее хелловорлд разными компиляторами обычно является результатом существенных усилий разработчика, нежели бесплатной возможностью, которая вытекает из идеологии языка.
S>Ну тогда попробуйте объяснить вот это: S>
Но ведь чёрт возьми нет — прямо в стандарте у нас есть всякие implementation-defined специально для того, чтобы вендор мог ставить палки в колёса тем, кто пытается такую штуку сделать.
А что именно вам непонятно? Что поведение floating types является implementation-defined налево и направо?
Или что всякие #pragma pack в стандарт не входят, и чтобы, к примеру, ваша структура соответствовала ожиданиям аппаратуры, нужно полагаться на добрую волю разработчиков компилятора, а не на стандарт?
S>Либо кто-то не умеет его готовить.
При чём здесь умение? Речь идёт о том, что самые базовые возможности языка построены на текстовой склейке поверх лексически и алгоритмически убогого трансформера.
Ну, вот чисто для примера — аналогом препроцессора в мире дотнет является T4. То есть если я хочу чего-то эдакого, чего в языке нет, я просто прикручиваю полноценный генератор исходников, который умеет много чего за пределами банальной подстановки и импорта файлов. При этом сам язык от T4 не зависит никак — базовые возможности в нём идут из коробки, и для простой гражданской разработки T4 не нужен.
S>>И что случилось с этой совместимостью в C++20? S>На нее забили. S>И, как по мне, принятие модулей в стандарт C++ -- это диверсияглупость ошибка, за которую придется расплачиваться еще долгие-долгие годы.
Я могу допустить, что конкретно плюсовая реализация модульности является ошибочной. Но сама концепция совершенно точно является правильной, и именно её отсутствие является одним из основных недостатков более ранних стандартов С++.
S>А я и не говорил, что код на C++ компилировался Сишным компилятором.
Значит, вы выбрали неудачную формулировку. Если вы имели в виду интероп с Сишным кодом — то опять же, выбранное решение этой проблемы выглядит максимально неудачным.
Раз уж вы настаиваете на том, чтобы я евангелировал дотнет — пжалста, дотнет прекрасно интеропит с сишным кодом, при этом никаких жертв со стороны модульности, или там метаданных, или там рантайм рефлекшна не потребовалось. А интероп из неуправляемого кода вообще был бы лёгким и приятным занятием.
S>Тогда мы говорим и не о макросах. Хотя, если вам макросы привиделись даже в D, то значит вам они везде будут мерещиться.
Мы говорим о метапрограммировании в более широком смысле. Обе принятые в плюсах методики метапрограммирования выглядят неудачными, каждая по своей причине. Для вас почему-то эта тема табуирована, а ваш оппонент хотя бы пробует её открыто обсуждать.
S>Тем, что его написал дебил, который этого не осознает .NET-евангелист пыжащийся в C++.
Ваше желание перейти на обсуждение личностей понятно, но от человека вашей квалификации я ожидал другого.
S>Одна из задач CRTP на уровне Base реализовать некий алгоритм, который точечно нуждается в уточнениях. Эти уточнения делаются в производных классах через методы, которые в обычном ООП были бы виртуальными. ЕМНИП, называется это template method pattern.
Не, я в курсе про этот паттерн. А также про то, что CRTP — "штатный" способ реализации миксинов в С++.
Но забавно, что вы основной целью CRTP считаете оптимизации (которые приличный компилятор мог бы сделать и сам, т.к. девиртуализация в таком очевидном случае проблем не представляет), а не приёмы проектирования.
S>И где же я говорил про свою любовь к низкоуровневым деталям?
Не к деталям, а к низкоуровневым оптимизациям. Желание заменить виртуальный метод невиртуальным — как раз пример такой любви.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>>Смех без причины признак дурач .NET-евангелиста, который думает, что разбирается еще в чем-то. S>Может быть. А может быть — признак человека, который в курсе того, что собираемость программы чуть сложнее хелловорлд разными компиляторами обычно является результатом существенных усилий разработчика
Это у разработчиков на языках Visual C++ или Borland C++, коих в свое время было немало и которых вообще не интересовало, есть ли условный __property в языке C++ или нет.
Ну и вы пытаетесь рассказывать байки человеку, который уже 30 лет компилирует программы посложнее хелловорлда разными компиляторами на разных платформах.
S>А что именно вам непонятно? Что поведение floating types является implementation-defined налево и направо?
Вы хотите сказать, что у вас на ARM умножение float-ов будет работать не так, как на x86? Т.е. если вы умножите 2.5 на 3, то в одном случае получите 12.75, а в другом 36.8?
S>Или что всякие #pragma pack в стандарт не входят, и чтобы, к примеру, ваша структура соответствовала ожиданиям аппаратуры, нужно полагаться на добрую волю разработчиков компилятора, а не на стандарт?
Или упаковывать структуры вручную, что гораздо надежнее и безопаснее.
S>>Либо кто-то не умеет его готовить. S>При чём здесь умение?
О том, что стадия препроцессинга почему-то выдается за проблему.
Сам по себе препроцессор a) безобиден и b) местами удобен.
Проблемы, как водится, начинаются от людей, которые застряли в прошлом веке и, например, используют define вместо констант. Достаточно в заголовочном файле поместить что-нибудь вроде:
#define BUFFER_SIZE 1024
struct data {
char _buffer[BUFFER_SIZE];
...
};
и в один прекрасный день обнаружить, что все навернулось.
S>Речь идёт о том, что самые базовые возможности языка построены на текстовой склейке поверх лексически и алгоритмически убогого трансформера.
Тут бы еще понять что вы понимаете под базовыми возможностями языка. Т.к., например, объявление класса или функции вообще никак к текстовой склейке не относится.
S>Ну, вот чисто для примера — аналогом препроцессора в мире дотнет является T4. То есть если я хочу чего-то эдакого, чего в языке нет, я просто прикручиваю полноценный генератор исходников, который умеет много чего за пределами банальной подстановки и импорта файлов. При этом сам язык от T4 не зависит никак — базовые возможности в нём идут из коробки, и для простой гражданской разработки T4 не нужен.
Открыть вам страшную тайну? В С++ вы можете тоже самое.
Более того, за счет препроцессора вы в одной единице трансляции можете подключить хоть 100500 разных мелких кусочков, сгенерированных внешними инструментами.
S>Я могу допустить, что конкретно плюсовая реализация модульности является ошибочной.
Речь не про ошибочность реализации. Речь о том, что решение добавить модули в язык с 35 летней историей и миллиардами имеющихся на руках строк кода -- это диверсия. Похлеще раскола на Python2 и Python3.
S>Значит, вы выбрали неудачную формулировку.
Я не виноват в том, что в предельно точной формулировке, а именно:
а программистам приходилось писать код на C++ и Си так, чтобы этот код мог компилироваться как Си-шным, так и C++ным компиляторами.
вы видите какую-то неведомую херню.
Речь шла именно о том, что в далекие годы, когда у кого-то в распоряжении был только С-шный компилятор, а у кого-то уже и C++ный, библиотеки писались так, чтобы их можно было компилировать либо С-шным компилятором, либо C++ным, в зависимости от того, что есть под рукой.
Условно:
// Заголовочный файл my_lib.h#ifndef MY_LIB_H
#define MY_LIB_H
#ifdef __cplusplus
#define DEFAULT_ARG_VALUE(v) =v
#endif
void do_something(int a, int b DEFAULT_ARG_VALUE(0), int c DEFAULT_ARG_VALUE(1));
...
Отголоски этого и сейчас можно видеть. Например, в некоторых C++ных библиотеках, которые активно применяются в разных языках, можно увидеть типичную конструкцию с extern "C".
S>Раз уж вы настаиваете на том, чтобы я евангелировал дотнет — пжалста
Пжалста, не нужно в очередной раз демонстрировать дурость типичных евагнелистов -- врываться в темы, не относящиеся к вашей любимой игрушке и рассказывать о ее достоинствах, о которых вас никто и не спрашивал.
S>>Тогда мы говорим и не о макросах. Хотя, если вам макросы привиделись даже в D, то значит вам они везде будут мерещиться. S>Мы говорим о метапрограммировании в более широком смысле.
Допустим.
S>Обе принятые в плюсах методики метапрограммирования выглядят неудачными
Нуждается в доказательствах. Причем не в сравнении с какими другими языками (это сравнение не имеет смысла когда разработка ведется на C++), а применительно конкретно к C++.
S>Для вас почему-то эта тема табуирована, а ваш оппонент хотя бы пробует её открыто обсуждать.
Во-первых, она не табуирована.
Во-вторых, оппонент не может в конкретику, а рассуждать о том, что все могло бы быть гораздо лучше, вот просто могло и все -- бессмыслено.
В-третьих, хотелось бы в процессе дискуссии установить какую-то теминологию, чтобы под макросами понималось что-то одно, под шаблонами что-то другое, под мифическими единорогами г.Музыченко -- третье. Но т.к. г.Музыченко не может в конкретику, то и с этим есть большие проблемы.
S>>Тем, что его написал дебил, который этого не осознает .NET-евангелист пыжащийся в C++. S>Ваше желание перейти на обсуждение личностей понятно, но от человека вашей квалификации я ожидал другого.
А я от вашей квалификации другого и не ожидал, ибо если вы заявляете, что увидели в D макросы, но не можете это хоть как-то обосновать, то ничего хорошего ждать и не приходится. Ну или когда мне байки начинают рассказывать о том, как сложно собирать C++ный код на разных платформах.
S>Но забавно, что вы основной целью CRTP считаете оптимизации (которые приличный компилятор мог бы сделать и сам, т.к. девиртуализация в таком очевидном случае проблем не представляет), а не приёмы проектирования.
Кто считает? Я считаю?
Помилуйте, я всего лишь сказал, что перцы из HFT/HPC нуждаются в продвинутых возможностях шаблонов и привел CRTP как пример. Поскольку в качестве замены виртуальных вызовов CRTP действительно может давать прирост производительности.
S>>И где же я говорил про свою любовь к низкоуровневым деталям? S>Не к деталям, а к низкоуровневым оптимизациям. Желание заменить виртуальный метод невиртуальным — как раз пример такой любви.
Если для вас это пример "низкоуровневой оптимизации", то мне здесь даже и добавить нечего.
Re[7]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, Sinclair, Вы писали:
S>И у вас есть гарантия того, что если вы видите экземпляр общего типа, он является экземпляром одного из этих типов и ничем больше (поэтому у нас есть возможность выполнять exhaustiveness checking). S>И вот тут и возникает некоторая проблема — как запретить порождать других наследников от Expression? В каком-нибудь дотнете это достигается package visibility для Expression.
А как package visibility позволит сделать exhaustiveness checking?
S>В ООП довольно сложно изобразить такую штуку,
Да вроде несложно... Вот на вскидку из популярных: https://docs.oracle.com/en/java/javase/17/language/sealed-classes-and-interfaces.html https://www.geeksforgeeks.org/scala/scala-sealed-trait/ https://kotlinlang.org/docs/sealed-classes.html
Но мне пока не довелось использовать на практике...
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Sinclair, Вы писали:
S>парни в Dart потратили несколько лет на эксперименты. Если они видят, что компиляция выезжает дорогая — значит, для них так и есть.
Вопрос в том, какую компиляцию считать "дорогОй". При компиляции больших текстов на C++, активно использующих шаблонную магию (которую неявно используют многие шаблоны std), количество создаваемых этими шаблонами вспомогательных классов/шаблонов может достигать тысяч и десятков тысяч. При вложении этих конструкций друг в друга количество этих сугубо мусорных объектов растет в геометрической прогрессии. Я не изучал предметно эти зависимости, но жалоб на "очень медленную компиляцию" полно, а ведь в популярных компиляторах обработка этих конструкций наверняка неплохо оптимизирована.
S>Хотя С++ практически целенаправленно организован так, что в нём невозможно сделать эффективную компиляцию.
Да можно, почему нет. Но тогда нужно прекратить вынос конструкций, генерирующих исполняемый код, в заголовки, включаемые множеством разных файлов. А это повлечет ухудшение оптимизации кода. Какую-то оптимизацию нынче делают линкеры, их возможности далеки от компиляторских.
S> Но всякие SFINAE выглядят как неизбегаемые грабли, заложенные с самого начала.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вопрос в том, какую компиляцию считать "дорогОй". При компиляции больших текстов на C++, активно использующих шаблонную магию (которую неявно используют многие шаблоны std), количество создаваемых этими шаблонами вспомогательных классов/шаблонов может достигать тысяч и десятков тысяч. При вложении этих конструкций друг в друга количество этих сугубо мусорных объектов растет в геометрической прогрессии.
В общем-то корень проблемы лежит именно там. S>>Хотя С++ практически целенаправленно организован так, что в нём невозможно сделать эффективную компиляцию.
ЕМ>Да можно, почему нет. Но тогда нужно прекратить вынос конструкций, генерирующих исполняемый код, в заголовки, включаемые множеством разных файлов. А это повлечет ухудшение оптимизации кода. Какую-то оптимизацию нынче делают линкеры, их возможности далеки от компиляторских.
Дело не в ухудшении оптимизации. А в том, что по-другому — никак. Вот у нас компилятор видит вызов какой-нибудь функции call(f, "foo", 42). Чтобы понять, что такое call, ему может потребоваться сделать довольно много приседаний. Если у нас call объявлена на основе шаблонной магии, компилятор начинает раскручивать шаблоны. При этом sfinae означает, что часть работы, возможно, будет выполнена впустую — раскрытый шаблон не подойдёт, и надо будет проверять другие варианты. Вот это всё в принципе не получится перенести в линкер — линкер не умеет раскрывать шаблоны и выбирать наилучшую перегрузку из возможных.
Всякие межпроцедурные оптимизации (если компилятор отдаёт не реальный бинарь, а IR) — да, может, и даже делает (LTCG). ЕМ>Ну да, без них же не будет работать магия.
Ну, не столько магия, сколько "декларативные компайл-тайм вычисления".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вопрос в том, какую компиляцию считать "дорогОй". При компиляции больших текстов на C++, активно использующих шаблонную магию (которую неявно используют многие шаблоны std), количество создаваемых этими шаблонами вспомогательных классов/шаблонов может достигать тысяч и десятков тысяч. При вложении этих конструкций друг в друга количество этих сугубо мусорных объектов растет в геометрической прогрессии. Я не изучал предметно эти зависимости, но жалоб на "очень медленную компиляцию" полно, а ведь в популярных компиляторах обработка этих конструкций наверняка неплохо оптимизирована.
Да, мантры про замедление компиляции очень популярны у всех неосиляторов. Это примерно из той же серии, что и слова Кота Базилио: "Один мой знакомый читал книжки и ослеп!".
На самом деле реальность несколько другая: замедление компиляции проистекает не от "шаблонной магии", а от говнодизайна, нездоровой связности по коду и данным и неумелого структурирования кода. Зачастую все эти проблемы создаются людьми, которые в своё время начитались книжек про паттерны проектирования, но применять эти паттерны толком так и не научились.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Sinclair, Вы писали:
ЕМ>>Да можно, почему нет. Но тогда нужно прекратить вынос конструкций, генерирующих исполняемый код, в заголовки, включаемые множеством разных файлов. А это повлечет ухудшение оптимизации кода. Какую-то оптимизацию нынче делают линкеры, их возможности далеки от компиляторских. S>Дело не в ухудшении оптимизации. А в том, что по-другому — никак. Вот у нас компилятор видит вызов какой-нибудь функции call(f, "foo", 42). Чтобы понять, что такое call, ему может потребоваться сделать довольно много приседаний. Если у нас call объявлена на основе шаблонной магии, компилятор начинает раскручивать шаблоны. При этом sfinae означает, что часть работы, возможно, будет выполнена впустую — раскрытый шаблон не подойдёт, и надо будет проверять другие варианты. Вот это всё в принципе не получится перенести в линкер — линкер не умеет раскрывать шаблоны и выбирать наилучшую перегрузку из возможных.
Интересно, а кто-то из общающихся смотрел отчеты компиляторов о том, на что время уходит?
(у GCC и clang-а есть ключики, которые пользволяют отчеты показывать, вроде `-ftime-report`)
Здравствуйте, rg45, Вы писали:
R>На самом деле реальность несколько другая: замедление компиляции проистекает не от "шаблонной магии", а от говнодизайна, нездоровой связности по коду и данным и неумелого структурирования кода.
По моим наблюдениям, замедление именно что от инстанциирования шаблонов и оптимизации шаблонного кода.
А вот говнодизайн, связность, излишняя видимость деталей реализации и прочее -- работают как множитель
Т.е. если делать относительно прямыми руками, то файл может компилироваться секунд 8-10.
На фоне того, с какой скоростью компилируются некоторые другие языки (не будем показывать пальцем на Go, но посмотрим в его сторону), это просто вечность.
При том, что код в стиле "Си с классами", который без шаблонов, компилируется ну просто влет.
Здравствуйте, so5team, Вы писали:
S>По моим наблюдениям, замедление именно что от инстанциирования шаблонов и оптимизации шаблонного кода. S>А вот говнодизайн, связность, излишняя видимость деталей реализации и прочее -- работают как множитель
Конечное же, обработка шаблонов имеет какие-то дополнительные расходы, чудес же не бывает. Но одно дело, когда использование шаблонов локализовано и общее замедление не носит сколько-нибудь драматичного характера. И совсем другое дело, когда шаблонный код бездумно размазан по коду многих проектов.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
S>>По моим наблюдениям, замедление именно что от инстанциирования шаблонов и оптимизации шаблонного кода. S>>А вот говнодизайн, связность, излишняя видимость деталей реализации и прочее -- работают как множитель
R>Конечное же, обработка шаблонов имеет какие-то дополнительные расходы, чудес же не бывает. Но одно дело, когда использование шаблонов локализовано и общее замедление не носит сколько-нибудь драматичного характера.
В том-то и дело, что носит даже когда я сам стараюсь сделать максмимально "прямо"
Т.е. пока находишься в рамках "Си с классами" с минимальным количеством шаблонов, то все OK, .cpp-файлы компилируются меньше секунды каждый.
Как только добавляются навороченные шаблоны, так 8-10 секунд запросто на один .cpp-ник.
Как по мне, так это вполне себе драматично.
Но, полагаю, компиляторостроители здесь уже постарались выжать все, что можно.
R>И совсем другое дело, когда шаблонный код бездумно размазан по коду многих проектов.
Тогда запросто можно умножать на 3-4-5.
Что, собственно, мне и доводится наблюдать на проектах, которые ведут не очень опытные разработчики, либо когда не смогли удержать под контролем и скатились в сами знаете что.
Здравствуйте, so5team, Вы писали:
S>В том-то и дело, что носит даже когда я сам стараюсь сделать максмимально "прямо" S>Т.е. пока находишься в рамках "Си с классами" с минимальным количеством шаблонов, то все OK, .cpp-файлы компилируются меньше секунды каждый. S>Как только добавляются навороченные шаблоны, так 8-10 секунд запросто на один .cpp-ник.
Но всё-таки, какие-то способы решения, какие-то компромиссы находить получается, наверное?
У меня самый такой распространённый способ — это создание нешаблонных фасадов с небольшим числом единиц трансляции, использующих достаточно обширную шаблонную имплементацию. Вот, пример из недавнего — библиотека в специфичной предметной области, состоящая всего из трёх cpp-шников и почти двухсот заголовочных файлов. Использование возможно двойственное — через полностью нешаблонный фасад, но и доступ к отдельным элементам "шаблонной магии" также оставлен открытым. Вся эта кухня, конечно же, имеет чёткую понятную структуру, в которой сразу же ясно, где мухи, где котлеты. Общее время компиляции этих трёх cpp-пишников — около 15 секунд. Что выглядит сущей ерундой на фоне общего времени сборки систем, где эта библиотека используется.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
S>>Как только добавляются навороченные шаблоны, так 8-10 секунд запросто на один .cpp-ник.
R>Но всё-таки, какие-то способы решения
По возможности пересаживаюсь на более мощную машину с большим количеством ядер
Время компиляции одного файла уменьшается незначительно, но общая сборка проекта существенно сокращается