Здравствуйте, so5team, Вы писали:
S>вы вообще хоть когда-нибудь в конкретику умеете?
Умею, когда это требуется по условиям задачи. Когда же формулируется общая идея, а в ответ требуют "цифры, графики и таблицы", то по ним, как правило, собеседник поймет лишь часть идеи. Какой тогда смысл в конкретике?
S>Расплываться мыслею по древу в кучу бесполезных словесов вы мастер.
Когда речь идет исключительно об общем подходе, это самое адекватное.
S>Написать что-то конкретное, в виде кода или псевдокода, перечислить конкретные языки или их фичи -- нет от слова совсем.
Конкретные языки с годными макропроцессорами я Вам приводил. Общие принципы описал достаточно подробно. Насколько я понимаю, Вы приличных макропроцессоров вообще не видели даже на примерах — как Вы собираетесь оценивать код, если я таки сподоблюсь разыскать синтаксис и родить пример? Придется или мне давать достаточно подробные пояснения, или Вам что-то почитать про эти технологии.
S>Возьмите, например, std::for_each. Это же что, наследие архитектурно-зависимых возможностей Си? S>Тем не менее, компилироваться будет в простой и компактный двоичный код.
Ну да, поскольку там простая и очевидная подстановка, не используются ни побочные эффекты, ни вложенные шаблоны, ни рекурсия. А многие ли смогут навскидку хотя бы примерно понять, во что будет компилироваться типичный "магический" шаблон, все это использующий? Чтоб раскрутить всю цепочку мысленно, нужно обладать или удачным устройством мозга, или большим разнообразным опытом, или изрядным терпением. А если тупо посмотреть на результат в ассемблерный код, и он не понравится, то что делать, кроме как "вернуться к п.1"?
S>А если вы про RTTI и поддержку исключений, то покажите как этого же достичь в Си с той же эффективностью.
Понятно, что и RTTI, и исключений без поддержки компилятора не сделать. Но основная претензия к RTTI и исключениям в C++ в том, что их невозможно включить в программу частично — либо полностью всю кухню, либо никак, что нарушает пресловутый принцип о плате за использование. А если б ставить задачу не в виде "как узнать тип чего угодно когда угодно", а в виде "как получить информацию о типе у компилятора, чтоб далее использовать ее имеющимися средствами языка", то это можно было реализовать хоть в C с любой разумной эффективностью, и оно не тянуло бы за собой лишних зависимостей
Аналогично и с исключениями. Минимальная функциональность исключений — возможность прервать выполнение кода и передать наверх минимально значимый объем информации. Возможности передавать произвольный объект, который наверху будет автоматически диспетчеризован, при этом не требуется — это уже дополнительное удобство, "сахар", который нетрудно добавить уже имеющимися средствами языка, если потребуются.
S>И если вам (не, не вам, а нормальным людям) в проекте нужны и RTTI, и исключения, то нахера им оглядываться на "низкоуровневые и архитектурно-зависимые возможности"?
Вот мне, внезапно, нужны исключения в ядре Windows, и они, внезапно, там есть. И они, опять же внезапно, есть даже в MS VC, который без плюсов. Именно в том самом минимальном варианте — прерывание выполнения, раскрутка стека и передача наверх ровно одного машинного слова — кода ошибки, числа, символа, указателя. Все это обеспечивается непосредственно ОС, это ее неотъемлемое свойство. Плюсовые исключения, разумеется, реализованы поверх этой функциональности. Надо ли говорить, что они тащат за собой хренову гору зависимостей, которые нужны далеко не каждому, но объем которых в несколько раз превышает минимально необходимый, и поэтому в ядре они не поддерживаются? Как и RTTI, собственно.
Re[13]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Я ж в смежных текстах всегда добавляю эпитет — "серьезных" или "взрослых" ЯВУ. В этой вот фразе не посчитал нужным это отметить.
Потому что это какие-то ваши личные расширения понятия ЯВУ. Со стороны сложно понять почему Си не "серьезный" язык.
ЕМ>Но ни в начале 70-х, н в 80-е, большинство специалистов не признавали C "настоящим ЯВУ".
Какие-то цитаты в подтверждение?
ЕМ>Его всегда ставили где-то посреди между продвинутым ассемблером и любым из популярных ЯВУ, которые подчеркнуто избегали использовать понятия "байт", "слово", "адрес" и т.п.
А где в Си есть "байт", "слово", "адрес" и т.п.?
ЕМ>>>Подход, принятый в C (и частично сохраненный в C++), позволяет малой кровью реализовать простое ядро языка на любой новой платформе, после чего туда автоматически переносится вся стандартная библиотека, написанная на нем самом.
S>>Э... А что этому препятствует в Pascal, Modula-2 и Ada?
ЕМ>Как минимум то, что подход был принят в C, а двух последних на тот момент не существовало. Но и в Pascal отсутствует разделение на ядро и библиотеку, поэтому любая реализация Pascal обязана уметь работать с файлами, даже если на платформе это понятие вовсе отсутствует, а на самом языке эту работу не написать компактно и эффективно
Что-то странное. В стандартной библиотеке Си есть fopen (в стандарте, да). Означает ли это, что на платформах, где понятие файла вовсе отсутствует, Си без fopen для вас перестанет быть Си?
S>>чем Си или C++ в этом вопросе лучше условного Modula-2.
ЕМ>C++ уже мало чем лучше — на ядре какого-нибудь C++03, например, не написать реализации каких-нибудь лямбда-функций
В C++98/03 лямбда функции реализовались вручную посредством функциональных объектов.
ЕМ>Здесь ключ не в том, есть в языке GC или его нет, а в том, насколько вольно язык допускает преобразование типов. Наличие GC — лишь следствие этой вольности, а не ее причина.
Вам к психиатру нужно, если вы считаете, что фундаментальная проблема контроля времени жизни сущности в программе для вас выглядит как "вольность в преобразовании типов".
ЕМ>А вот пресловутыми "умными макросами" это можно было бы сделать и более понятно, и более гибко.
Пример в студию.
S>>Я бы еще понял претензии по поводу эффективности и экономичности (хотя я уже как-то давал в профильных форумах ссылку на использование возможностей современного C++ как раз для экономичности).
ЕМ>Я Вас читаю только здесь
Звиздежь. Я вам в панамку насовывал и в профильных форумах cpp и cpp.applied, и ссылка эта там же давалась. Возможно даже неоднократно.
ЕМ>Но даже по указанной ссылке Вы рассказываете не об "имманентных" свойствах языка, а о трюках.
О каких таких "трюках"? По ссылке рассказ о том, что сделано штатными средствами языка, в рамках стандарта. И работает это на двух разных платформах под двумя совершенно разными компиляторами.
ЕМ>То есть, таки признаете, что за сорок лет развития языка в нем так и не появилось многих вещей, которые давно напрашиваются, и достаточно просты в реализации.
Это вопрос из категории "признаете ли вы что уже перестали пить коньяк по утрам".
S>>Но прозрачность и ортогональность-то здесь каким боком?
ЕМ>Дык, Вас вроде как совершенно не напрягает нечеловеческие синтаксис
Это субъективно.
ЕМ>и семантика
С семантикой вроде все OK.
ЕМ>(то есть — непрозрачность)
Это манипуляция -- вы ставите знак равенства между "нечеловеческой семантикой" и "непрозрачностью" никак это не доказав. Типа так оно и есть, поверьте мне на слово.
ЕМ>многих шаблонных конструкций, уверенное понимание которых невозможно без хотя бы многомесячной плотной практики (ну, или подходящего устройства мозга)
Примеры в студию. Без примеров незачет.
Есть места в C++, которые для меня не выглядят интуитивно и которые приходится запоминать. Например, история с std::integer_sequence. Но у меня нет ощущения, что их вот прям много.
S>>Это как сейчас с C++ными модулями. В теории они есть. На практике для очень многих их нет. Хотя в стандарте описаны, да.
ЕМ>А много ли даст реализация тех модулей в соответствии со стандартом, по сравнению с тем, что можно сделать уже имеющимися средствами языка?
Я вам не об этом говорил и не нужно забалтывать. Речь шла о том, что есть абстрактный конь в вакууме, для которого, может быть когда-нибудь что-то качественное и будет сделано. И есть реальная жизнь здесь и сейчас. И в реальной жизни иногда выгоднее сделать что-то из подручных средств самому, чем ждать этого светлого будущего от кого-то.
S>>А где макросы не примитивные и не тупые?
ЕМ>Например, в ассемблере System/360.
OK, покажете пример как получить в качестве параметра класс, узнать есть ли в этом классе специфический метод и сделать реализацию исходя из наличия или отсутствие этого метода?
Например, в качестве метода пусть будет не бросающий исключений оператор перемещения.
ЕМ>В PL/1 вроде как тоже был вполне годный макропроцессор.
Та же самая задача. Сможете?
ЕМ>Во многих ассемблерах макроязык позволял вырезать подстроки, перебирать фактические параметры, ветвиться, делать повторы и т.п. То есть, к тому времени уже долгое время были достойные примеры, только бери из каждого лучшее.
Страуструп в своей "Дизайн и эволюция C++" на эту тему высказывался: от макросов отказались, т.к. макросы работают еще до того, как в дело вступает компилятор языка и на этом уровне нет никакой информации о типах. Что характерно, это все справедливо и сейчас, даже если смотреть шире Си и C++.
S>>Это возможно в динамически типизируемом языке, типа Lisp-а.
ЕМ>Это возможно в любом языке.
В Си невозможно. В Ada невозможно. В Java невозможно. Этого достаточно, чтобы опровергнуть тезис о "любом языке"
S>>В статически типизируемом вы для этого должны оперировать понятиями языка (вроде анотаций в Java или шаблонов C++), либо работать на уровне лексем. Но на уровне лексем возникают проблемы с тем, чтобы понять что конкретная лексема будет означать.
ЕМ>С чего вдруг такие ограничения?
С самого принципа работы макросов. Которые работают на уровне текста и преобразуют текст в текст еще до того, как текст будет обработан компилятором.
ЕМ>Технически ничто не мешает предоставить языку, на котором пишется макрос, доступ к любой информации, которая известна компилятору на момент вызова макроса. А синтаксически несложно определить, где подразумевается прямая текстовая подстановка, а где — вычисление выражения или управляющая конструкция.
Давайте с примерами: где это реализовано и как это выглядит.
Можете посмотреть на макросы Rust-а. Покажется ли вам это проще и понятнее C++ных шаблонов или нет.
ЕМ>>>И сколько лет прошло от появления в C++ шаблонов, которые внезапно оказались Тьюринг-полными, до появления первых робких средств делать этот разбор иначе, как посредством побочных эффектов? S>>Каких таких эффектов, выражайтесь яснее, плз.
ЕМ>Ну как еще можно было сделать последовательный перебор параметров шаблона до появления с C++11 явных средств для этого, кроме как на побочных эффектах вычисления шаблонных выражений?
Давайте конкретно. Что вы понимаете под "последовательный перебор параметров шаблона"?
Вы хотите видеть type_list-ы в рамках C++98?
S>>прошу показать где обобщенное программирование реализовано лучше и гибче.
ЕМ>Возможно, что и нигде.
Внезапно.
S>>Где такое чудо можно увидеть?
ЕМ>Возможно, что и нигде.
Внезапно №2.
Вы тут в очередной раз заводите шарманку о том, как C++ упустил все шансы и вовремя не скопировал лучшие достижения из других языков. И внезапно выясняется, что у вас вообще нет примеров на которые вы могли бы сослаться и показать "вот здесь вот это лучше потому-то и потому-то".
S>>В современном C++ практически все это под вашим контролем.
ЕМ>Угу — только, как правило, под неявным
Ключевое слово explicit -- это "под неявным"
ЕМ>как правило, через жопу.
Здравствуйте, Евгений Музыченко, Вы писали:
S>>вы вообще хоть когда-нибудь в конкретику умеете?
ЕМ>Умею, когда это требуется по условиям задачи.
Тогда еще раз: вы заявили о "Вам, насколько я знаю из того, что Вы пишете про C++, неинтересны низкоуровневые и архитектурно-зависимые возможности C++, унаследованные от C."
Такая формулировка означает, что есть некий перечень этих самых возможностей. Раз он есть, значит его можно озвучить. Озвучте, пожалуйста.
ЕМ>Когда же формулируется общая идея
Пока не видно никакой общей идеи. Видно только ваше стремление заболтать и переливать из пустого в порожнее.
S>>Написать что-то конкретное, в виде кода или псевдокода, перечислить конкретные языки или их фичи -- нет от слова совсем.
ЕМ>Насколько я понимаю, Вы приличных макропроцессоров вообще не видели даже на примерах
Вы неправильно понимаете.
ЕМ>как Вы собираетесь оценивать код, если я таки сподоблюсь разыскать синтаксис и родить пример?
А вы дайте, там разберемся.
ЕМ>Ну да, поскольку там простая и очевидная подстановка, не используются ни побочные эффекты, ни вложенные шаблоны, ни рекурсия. А многие ли смогут навскидку хотя бы примерно понять, во что будет компилироваться типичный "магический" шаблон, все это использующий?
А зачем? Вы код пишете для того, чтобы ассемблерный выхлоп изучать или чтобы задачу решить?
S>>А если вы про RTTI и поддержку исключений, то покажите как этого же достичь в Си с той же эффективностью.
ЕМ>Понятно, что и RTTI, и исключений без поддержки компилятора не сделать. Но основная претензия к RTTI и исключениям в C++ в том, что их невозможно включить в программу частично — либо полностью всю кухню, либо никак, что нарушает пресловутый принцип о плате за использование.
Э... Насколько я знаю, в том же GCC можно использовать "-fno-rtti", но при этом сохранять исключения.
ЕМ>а в виде "как получить информацию о типе у компилятора, чтоб далее использовать ее имеющимися средствами языка", то
то C++ные шаблоны вам дают именно это. И когда люди не могут платить за штатный RTTI они делают свои минимальные реализации как раз за счет шаблонов.
ЕМ>Аналогично и с исключениями. Минимальная функциональность исключений — возможность прервать выполнение кода и передать наверх минимально значимый объем информации.
Так-то в C++ можно и throw 42 написать.
Другое дело, что в любом большом проекте с включенными исключениями за такое по рукам надают, скорее всего.
ЕМ>Вот мне, внезапно, нужны исключения в ядре Windows, и они, внезапно, там есть. И они, опять же внезапно, есть даже в MS VC, который без плюсов. Именно в том самом минимальном варианте — прерывание выполнения, раскрутка стека и передача наверх ровно одного машинного слова — кода ошибки, числа, символа, указателя. Все это обеспечивается непосредственно ОС, это ее неотъемлемое свойство.
Правильно ли я понимаю, что список "низкоуровневые и архитектурно-зависимые возможности C++, унаследованные от C" состоит из одного пункта -- поддержка SEH на платформе Windows?
ЕМ>Плюсовые исключения, разумеется, реализованы поверх этой функциональности.
Вы точно уверены, что все реализации C++ных исключений сделаны на базе Windows-ного SEH?
Re: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, σ, Вы писали:
x>... x>Смотрел несколько дней назад, уже всего точно не помню, но вот некоторые моменты: x>Инкапсуляцию придумали когда делали симуляцию поведения распределённых систем. В этом случае инкапсуляция — адекватная модель для предметной области. Но оопе-сектанты пропагандируют что для всех областей. x>...
Свежий пример из моей практики, про инкапсуляцию. На текущем проекте мы разрабатываем stateless ui фреймворк поверх ImGui для собственных нужд и благодаря этому не требовалось инкапсуляции, например есть struct TextWidgetContent{ std::string text; } и в коде просто меняешь текст на нужный, без вызова каких либо функций и уведомлений и на следующем фрейме текст обновится. У подхода есть свои плюсы и минусы, но в целом оказалось удобно.
А потом начали вылазить проблемы. Изначально была публичная переменная m_enabled, которая определяла можно ли взаимодействовать с виджетом. Потом функционал начал расширяться. Например, нужно проверить, можно ли перейти к виджету через табуляцию, ну и написали метод типа
Но поленились причесать код, и где-то состояние проверялось через этот геттер (инкапсуляция), а где-то напрямую флаги. А потом добавили ещё одно состояние — m_is_focusable. В геттер его сразу вписали, а вот в нескольких местах, где не было инкапсуляции и напрямую проверялись значения полей — забыли. И потом периодически фиксили баги. Понятно, что можно было прокликать каждую переменную, найти места где она используется (благо Решарпер хорошо с этим справляется) и заменить на тот или иной геттер. Но мелкие баги из-за этого вылазили в течение месяца. А если бы сразу всё заворачивали в геттеры — таких вопросов бы не возникло.
Здравствуйте, so5team, Вы писали:
S>Со стороны сложно понять почему Си не "серьезный" язык.
Потому, что он чрезмерно детальный по сравнению с теми же COBOL, Fortran, PL/1 и подобными языками, на которых предпочитали делать крупные проекты, не слишком ограниченные ресурсами. Затраты на возню с организацией данных и управлением ими, преобразованием типов, динамической памятью и прочим очень быстро растут с ростом объема/сложности проекта.
S>А где в Си есть "байт", "слово", "адрес" и т.п.?
Байт — в стандарте. В любой мало-мальски практической литературе всегда подчеркивается, что char — это почти всегда байт, int — почти всегда машинное слово, указатель — ни что иное, как адрес, и т.п.
S>В стандартной библиотеке Си есть fopen (в стандарте, да). Означает ли это, что на платформах, где понятие файла вовсе отсутствует, Си без fopen для вас перестанет быть Си?
В C в этим гораздо проще: поскольку fopen, как и все остальные функции, входит не в "язык", а в "стандартную библиотеку языка", которая в язык не входит, а лишь прилагается к нему, то в библиотеке целевой платформы той fopen может и вовсе не быть, или быть заглушка, всегда возвращающая ошибку, или может быть реализована какая-то частичная имитация, а пользователь в любой момент может сделать свою версию. А при реализации того же Pascal на платформе, где нет потокового ввода/вывода, write не сможет вернуть ошибку, поэтому придется в сам компилятор закладывать реакцию на использование write, а пользователь не сможет сделать свою реализацию, если ему не раскрыты подкапотные особенности реализации. В этом смысле C отражают структуру системы: поскольку вычисления и обработка данных без процессора невозможны, то сам язык предоставляет доступ лишь к возможностям процессора, а все остальное делается внешними средствами по мере наличия и потребности.
S>В C++98/03 лямбда функции реализовались вручную посредством функциональных объектов.
У меня там было "... с захватом области видимости".
S>Вам к психиатру нужно, если вы считаете, что фундаментальная проблема контроля времени жизни сущности в программе для вас выглядит как "вольность в преобразовании типов".
Ну, не знаю — я действительно не вижу никакой потребности в GC в ситуации, когда любое преобразование типов (включая копирование сложных объектов) подконтрольно создателям этих самых типов/объектов. Неизбежная потребность в GC возникает лишь когда такие операции невозможно перехватывать.
ЕМ>>А вот пресловутыми "умными макросами" это можно было бы сделать и более понятно, и более гибко.
S>Пример в студию.
Не буду я сочинять примеры. Если сама идея понятна, но непонятны детали, то можете задать уточняющие вопросы. Если непонятна даже идея, то нет смысла в это углубляться.
S>О каких таких "трюках"?
"Поэтому было решено прибегнуть к шаблонной магии...".
S>По ссылке рассказ о том, что сделано штатными средствами языка, в рамках стандарта.
От того, что средства, изначально предназначенные для одних целей, но с помощью трюков позволяющие достигать более других, были включены в стандарт, суть трюковости не меняется.
ЕМ>>нечеловеческие синтаксис
S>Это субъективно.
Каким образом могут быть "субъективными" хотя бы принципиально инверсные запись и разворачивание любых вложенных/рекурсивных шаблонных конструкций в процедурном по сути (то есть, с прямым порядком операций) языке?
S>вы ставите знак равенства между "нечеловеческой семантикой" и "непрозрачностью" никак это не доказав. Типа так оно и есть, поверьте мне на слово.
Так это ж очевидно. Сравните количество программистов, у которых вызывает затруднение хотя бы примерная (на уровне "что делает") оценка поведения типичной процедурной функции, с количеством программистов, затрудняющихся навскидку (то есть, без пошаговой симуляции) оценить поведение типичного "магического" (то есть, трюкового) шаблона. Это ж гораздо заметнее, чем пресловутая разница в анализе итерационных и рекурсивных алгоритмов, где последние всегда и бесспорно признаются более сложными для среднего человека. А мало-мальски сложные шаблонные конструкции почти все основаны если не на рекурсии, то на поочередном сопоставлении, которое по смыслу достаточно близко к ней.
S>Есть места в C++, которые для меня не выглядят интуитивно и которые приходится запоминать.
Для большинства людей, мыслящих последовательно и итерационно, вложенность, рекурсия и прочие "вывернутые" понятия (вроде формальных грамматик, синтаксиса объявления массивов/указателей в C и т.п.) никогда не выглядят интуитивно. Запомнить можно небольшое количество часто используемых паттернов, но это мало помогает в понимании их внутреннего устройства (а это желательно хотя бы в тех случаях, когда подстановка шаблона порождает простыню из сообщений компилятора). Поэтому у большинства программистов использование шаблонов за пределами "минимально обобщенного" программирования сводится к тупому переписыванию (вплоть до копипасты) фрагментов из справочников, руководств и примеров, с подстановкой туда своих имен. Когда компилятор выдает пресловутую "простыню", большинство опять же мало что в ней понимает, и либо одним из методом тыка подбирает параметры шаблона, либо применяет известные методы устранения наиболее типичных ошибок. Насколько, по-Вашему, это соответствует нормальному, надежному процессу программирования?
S>в реальной жизни иногда выгоднее сделать что-то из подручных средств самому, чем ждать этого светлого будущего от кого-то.
Я обычно так и делаю, когда есть возможность. Если б у меня был свой компилятор C++, я б там давно сделал большинство вещей, которые облегчают работу, повышают надежность программы и т.п., не создавая значимых затрат. Но допиливать какой-нибудь GCC, попутно поддерживая его соответствие с официальной линией, я тупо не осилю. Поэтому все эти идеи и не выходят из статуса идей.
ЕМ>>Например, в ассемблере System/360.
S>покажете пример как получить в качестве параметра класс
Как Вы представляете себе пример на макроязыке ассемблера System/360, получающий в качестве параметра класс? Для этого пришлось бы городить специальный псевдоязык. А в этом я не вижу ни малейшей надобности, ибо сама идея, на мой взгляд, предельно примитивна, и напрашивается интуитивно. Если для Вас это не так, то мы смотрим на устройство ЯП и процесс их компиляции под несовместимыми углами, и примеры здесь не помогут.
S>узнать есть ли в этом классе специфический метод и сделать реализацию исходя из наличия или отсутствие этого метода?
Вот примерно так же, как в C++ это делается шаблонной магией. Только вместо трюков, приводящих к подстановке нужного значения в результате SFINAE и/или рекурсии, человеческий макроязык должен предоставлять средства доступа к информации о типах, которая есть у компилятора. Нечто вроде того, как в JS организуется доступ к HTML-документу через DOM. А средства условной трансляции, подстановки строк/подстрок, преобразования чисел в текст, циклического повторения и т.п., дают возможность сгенерировать нужные текстовые строки для последующей компиляции.
S>Например, в качестве метода пусть будет не бросающий исключений оператор перемещения.
Какая разница, какой оператор и что он делает? У компилятора вся эта информация есть, достаточно лишь обеспечить доступ, а как — отдельный вопрос. Хоть через отдельные свойства (has_move_operator, get_move_operator, does_throw_exception), хоть через разбор синтетических сигнатур, хоть еще как-то, лишь бы функционально, гибко и удобно.
ЕМ>>В PL/1 вроде как тоже был вполне годный макропроцессор.
S>Та же самая задача. Сможете?
Смогу, если найду справочник и не поленюсь придумать для него недостающие средства. Но не хочу, так как не вижу смысла. Я обозначил идею — лично мне этого достаточно. А как я выгляжу при этом в чужих глазах, мне не особо интересно. Sapienti sat, как говорится.
А если есть вопросы/возражения по особенностям реализации идеи, то с удовольствием.
S>Страуструп в своей "Дизайн и эволюция C++" на эту тему высказывался: от макросов отказались, т.к. макросы работают еще до того, как в дело вступает компилятор языка и на этом уровне нет никакой информации о типах. Что характерно, это все справедливо и сейчас, даже если смотреть шире Си и C++.
Что значит "работают еще до того"? Это непреложное свойство Вселенной? Математическая закономерность? Всепланетный государственный закон? Этический принцип?
S>В Си невозможно. В Ada невозможно. В Java невозможно. Этого достаточно, чтобы опровергнуть тезис о "любом языке"
Этого достаточно, чтобы сообразить, что в этих языках установлены такие правила. Если задаться целью сохранить все правила без исключения, то, само собой, ничего не получится. Если задаться целью создать нечто полезное, и согласиться изменить правила, то можно получить все, что угодно.
ЕМ>>С чего вдруг такие ограничения? S>С самого принципа работы макросов. Которые работают на уровне текста и преобразуют текст в текст еще до того, как текст будет обработан компилятором.
Как именно установлены такие правила для всех сущностей, имеющих в названии слово "макрос", которые когда-либо были, есть и будут реализованы?
ЕМ>>Технически ничто не мешает предоставить языку, на котором пишется макрос, доступ к любой информации, которая известна компилятору на момент вызова макроса. А синтаксически несложно определить, где подразумевается прямая текстовая подстановка, а где — вычисление выражения или управляющая конструкция.
S>Давайте с примерами: где это реализовано и как это выглядит.
Да какая разница? Если даже и нигде/никак, что это меняет? Вопрос ведь о том, будет ли это полезно/удобно, можно ли это реализовать технически, и насколько сложно это сделать. Первое и второе у меня сомнений никогда не вызывало, с третьим есть ряд вопросов которые придется решать — например, необходимость дополнительных проходов компилятора, допустимость динамического изменения условий, управляющих компиляцией, обработка возможных противоречий, свойственных динамическому порождению исходного кода, и т.п. Тут уже надо смотреть, какие бонусы может дать каждый подход, и во что встанет его реализация.
А уж реализовать таким образом поддержку всех без исключения функций, доступных через шаблоны C++, но в более человеческом, прямом-пошагово-процедурном виде, вообще элементарно.
S>Что вы понимаете под "последовательный перебор параметров шаблона"?
Да хоть так же, как сишный main перебирает свои параметры, переданные в argv — хоть подряд в цикле, хоть прямой индексацией по отдельности, хоть задом наперед. Чтоб можно было легко и наглядно определить, что передано — идентификатор объекта/класса/функции/области видимости, литерал, выражение, тип и т.п. Для каждого из этих вариантов извлечь любое из свойств, которые у него технически могут иметься. По всей добытой информации принять решение (решения), сгенерировать исходный текст и вернуть его компилятору в качестве результата вызова/подстановки.
S>Вы хотите видеть type_list-ы в рамках C++98?
Только как частность. И не в виде убогой извращенной реализации от Александреску и его последователей под эгидой "если это технически возможно, да будет так!", а в виде, понятном и удобном для большинства программистов.
S>>>прошу показать где обобщенное программирование реализовано лучше и гибче. ЕМ>>Возможно, что и нигде.
S>Внезапно.
Для меня — почему-то нет. Ибо разумный баланс встречается куда реже, чем строгое следование идеологии или полная анархия.
S>как C++ упустил все шансы
Смотря в каком смысле. Если в смысле достижения значительных результатов разумными средствами, то да. Если в смысле достижения менее значительных результатов заумными, переусложненными средствами, то нет. В первом случае C++ мог бы избежать репутации очень сложного, запутанного и нелогичного языка, в полном объеме доступного лишь немногочисленным гуру, и специалисты вроде Александреску, Степанова или даже Вас были бы менее востребованы. Возможно, искусственное повышение порога вхождения было одной из причин укоренения выбранного подхода.
S>и вовремя не скопировал лучшие достижения из других языков. И внезапно выясняется, что у вас вообще нет примеров на которые вы могли бы сослаться
То есть, отсутствие полностью готовых примеров в других языках — достаточно убедительная отмазка, чтобы не применять саму идею в принципе? Как-то сильно смахивает на старый советский анекдот про спрос на черную икру.
S>Ключевое слово explicit -- это "под неявным"
И куда его вставить, чтоб управлять integral promotions?
Re[15]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, Евгений Музыченко, Вы писали:
S>>Со стороны сложно понять почему Си не "серьезный" язык.
ЕМ>Потому, что он чрезмерно детальный по сравнению с теми же COBOL, Fortran, PL/1 и подобными языками
Это не имеет отношения к "серьезный" или "взрослый".
В Википедии есть термин "язык сверхвысокого уровня", он более уместен и однозначен.
S>>А где в Си есть "байт", "слово", "адрес" и т.п.?
ЕМ>Байт — в стандарте.
Да, действительно, byte есть в стандарте:
byte
addressable unit of data storage large enough to hold any member of the basic character set of the
execution environment
Как и термин "address".
S>>В стандартной библиотеке Си есть fopen (в стандарте, да). Означает ли это, что на платформах, где понятие файла вовсе отсутствует, Си без fopen для вас перестанет быть Си?
ЕМ>А при реализации того же Pascal на платформе, где нет потокового ввода/вывода, write не сможет вернуть ошибку
Какой-то бред. На платформе, где нет ввода/вывода, у вас просто не будет write и все. Ваша программа не скомпилируется.
Очередная сова на глобус.
S>>В C++98/03 лямбда функции реализовались вручную посредством функциональных объектов.
ЕМ>У меня там было "... с захватом области видимости".
У вас там еще и ООП в чистом Си. Вот в C++98 в функциональных объектах был такой же ручной захват, как в и ручной ООП на Си.
S>>Вам к психиатру нужно, если вы считаете, что фундаментальная проблема контроля времени жизни сущности в программе для вас выглядит как "вольность в преобразовании типов".
ЕМ>Ну, не знаю — я действительно не вижу никакой потребности в GC в ситуации, когда любое преобразование типов (включая копирование сложных объектов)
Копирование объектов — это у вас преобразование типов? Батенька, вам бы полечиться.
ЕМ>>>А вот пресловутыми "умными макросами" это можно было бы сделать и более понятно, и более гибко.
S>>Пример в студию.
ЕМ>Не буду я сочинять примеры.
Меня не интересуют идеи больных на голову. Меня интересуют конкретные примеры.
Вы тут заявляли о том, что во времена создания C++ было много языков, из которых можно было заимствовать идеи. Но ни одного не смогли перечислить.
Вы тут заявляли, что обобщенное программирование может быть проще и гибче, чем в C++. Но ни одного примера не смогли привести.
S>>О каких таких "трюках"?
ЕМ>"Поэтому было решено прибегнуть к шаблонной магии...".
Ох ё... Есть такое устойчивое выражение в узких кругах "шаблонная магия".
S>>По ссылке рассказ о том, что сделано штатными средствами языка, в рамках стандарта.
ЕМ>От того, что средства, изначально предназначенные для одних целей, но с помощью трюков позволяющие достигать более других, были включены в стандарт, суть трюковости не меняется.
Простите, у меня цензурные слова закончились.
ЕМ>Как Вы представляете себе пример на макроязыке ассемблера System/360, получающий в качестве параметра класс?
Это вы как-то это дело представляете, раз приводите в пример ассемблер с его макросами. Ну а раз представляете, то показывайте. Или же этот пример вычеркиваем.
ЕМ>Вот примерно так же, как в C++ это делается шаблонной магией. Только вместо трюков, приводящих к подстановке нужного значения в результате SFINAE и/или рекурсии, человеческий макроязык должен предоставлять средства доступа к информации о типах, которая есть у компилятора. Нечто вроде того, как в JS организуется доступ к HTML-документу через DOM. А средства условной трансляции, подстановки строк/подстрок, преобразования чисел в текст, циклического повторения и т.п., дают возможность сгенерировать нужные текстовые строки для последующей компиляции.
Не надоело еще лозунги в стиле "за все хорошее" озвучивать?
S>>Например, в качестве метода пусть будет не бросающий исключений оператор перемещения.
ЕМ>Какая разница, какой оператор и что он делает? У компилятора вся эта информация есть
Еще раз, постараюсь в цензурной форме: макросы работают до компилятора. До.
Когда вы что-то отдаете в макрос, то там еще нет информации от компилятора.
ЕМ>Я обозначил идею — лично мне этого достаточно.
Да, да. Мышки -- станьте ежиками и далее по тексту, до мое дело -- стратегия. Ага.
ЕМ>Что значит "работают еще до того"? Это непреложное свойство Вселенной? Математическая закономерность? Всепланетный государственный закон? Этический принцип?
Принцип работы макросов.
Если мы работаем с информацией от компилятора, то это уже не макропрограммирование, а метапрограммирование, когда элементы программы становятся входными данными для дальнейшей программы.
S>>Давайте с примерами: где это реализовано и как это выглядит.
ЕМ>Да какая разница? Если даже и нигде/никак, что это меняет?
Все.
S>>Что вы понимаете под "последовательный перебор параметров шаблона"?
ЕМ>Да хоть так же, как сишный main перебирает свои параметры, переданные в argv — хоть подряд в цикле, хоть прямой индексацией по отдельности, хоть задом наперед. Чтоб можно было легко и наглядно определить, что передано — идентификатор объекта/класса/функции/области видимости, литерал, выражение, тип и т.п.
Смешались в кучу кони, люди.
S>>Вы хотите видеть type_list-ы в рамках C++98?
ЕМ>Только как частность. И не в виде убогой извращенной реализации от Александреску и его последователей под эгидой "если это технически возможно, да будет так!", а в виде, понятном и удобном для большинства программистов.
В переводе на русский: в том виде, в котором понравится Музыченко.
Александресу показал механизм, который мог использоваться в рамках того C++. Постепенно набрали опыт, развили, усовершенствовали. И на этом, к счастью не останавливаются.
Механизм, кстати говоря, вполне себе в духе Prolog-а и функциональных языков.
Где вы здесь видите побочные эффекты --
А подтвердить свои слова конкретным примером не сможете, не вашем это стиле.
S>>Ключевое слово explicit -- это "под неявным"
ЕМ>И куда его вставить, чтоб управлять integral promotions?
Специально для вас повторю:
В современном C++ практически все это под вашим контролем. За исключением унаследованного из Си неявного преобразования целочисленных типов.
Была сделана оговорка на счет тех самых integral promotions, унаследованных из Си, на которую вы так надрачиваете.
Здравствуйте, so5team, Вы писали:
S>есть некий перечень этих самых возможностей. Раз он есть, значит его можно озвучить. Озвучте, пожалуйста.
Да Вы сами их прекрасно знаете. Спецификация того, как данные размещаются в памяти и выравниваются в ней (если и не для всего языка, то для любой реализации), возможность слепого/принудительного преобразования типов, обязательная спецификация ABI для каждой реализации
S>Пока не видно никакой общей идеи.
Значит, не судьба. На мой взгляд, я уже разжевал подробнее некуда, особенно учитывая то, что я об этом пишу здесь уже лет двадцать.
ЕМ>>Насколько я понимаю, Вы приличных макропроцессоров вообще не видели даже на примерах
S>Вы неправильно понимаете.
Тогда что ж Вам мешает вообразить макропроцессор, работающий не перед фазой компиляции, а во время нее? Ведь шаблоны обрабатываются именно так, в них есть черты и макросов, и функций. Вот и представьте шаблон, в котором вместо псевдофункционального синтаксиса — примерно тот же язык, что и базовый C++, с условными операторами вроде if constexpr, с циклами, локальными переменными, включая массивы, одним из которых является массив фактических параметров. Неужто скажете, что это будет менее функционально, удобно, понятно, наглядно и гибко, чем имеющийся формат с трюками и множеством чисто вспомогательных, служебных шаблонов, без которых нужный функционал попросту не реализуется?
S>Вы код пишете для того, чтобы ассемблерный выхлоп изучать или чтобы задачу решить?
Когда решается задача "написать программу для микроконтроллера с памятью в восемь килобайт на код и два килобайта на данные", или "написать быстродействующий модуль ядра, где полностью отсутствуют средства профилирования", ассемблерный выхлоп становится сверхценным. А задачи под гигабайты/гигагерцы я могу написать и на Java/JavaScript, где ассемблерного выхлопа и вовсе нет.
S>Насколько я знаю, в том же GCC можно использовать "-fno-rtti", но при этом сохранять исключения.
Это уже вынужденные особенности реализаций, вызванные заведомо избыточной концепцией исключений в C++.
ЕМ>>а в виде "как получить информацию о типе у компилятора, чтоб далее использовать ее имеющимися средствами языка", то S>то C++ные шаблоны вам дают именно это.
Они дают не это. Они, грубо говоря, дают примерно то же, что и технологии Meltdown/Spectre — сугубо косвенными методами (то есть, через задницу) определить значение в памяти, которое нельзя просто прочитать. Попробуйте представить себе аппаратную платформу, где прямое чтение из памяти по каким-то странным причинам оказалось вовремя не реализованным, и какие-то забавные ребята, развлечения ради, придумали аналог Meltdown, добывающий содержимое памяти какими-нибудь косвенными, статистическими методами. Каков будет шанс на реализацию прямого чтения в будущем, если та хитрая техника добывания будет быстро возведена в ранг высокой технологии, вокруг нее соберется толпа энтузиастов-поклонников, а противники будут объявлены ретроградами, неспособными постичь новое и современное?
S>когда люди не могут платить за штатный RTTI они делают свои минимальные реализации как раз за счет шаблонов.
Ну да — люди, которые не могут (или не хотят) платить за какой-нибудь Porsche, вынуждены ездить исключительно в инвалидных колясках, поскольку свысока авторитетно объявлено, что это в чистом виде бинарная альтернатива, и любые промежуточные варианты — от лукавого.
S>Так-то в C++ можно и throw 42 написать.
Но платить-то придется за весь банкет, поскольку любой throw или try/catch непременно потянет за собой все зависимости, предназначенные для обработки исключений. Конечно, можно покопать конкретную реализацию, найти, какие функции там подтягиваются, и сделать для них заглушки, но это может быть непросто, если от каких-то функций ожидается принятие определенных решений в ходе раскрутки, а решения эти должны быть основаны на состоянии стека, выброшенных/ожидаемых типах и т.п. Но главное-то в том, что всем этим приходится заниматься не потому, что мир таков, а потому, что одни люди в свое время поленились подумать чуть лучше, а другие не нашли смелости их поправить.
S>Другое дело, что в любом большом проекте с включенными исключениями за такое по рукам надают, скорее всего.
А в больших проектах такого и не нужно. Нужно только там, где главная задача — аккуратно и надежно передать управление снизу вверх, а ситуаций, определяемых передаваемыми попутно данными, может быть всего две-три.
S>Правильно ли я понимаю, что список "низкоуровневые и архитектурно-зависимые возможности C++, унаследованные от C" состоит из одного пункта -- поддержка SEH на платформе Windows?
Так SEH нет ни в C, ни в C++. А остальные низкоуровневые возможности одинаково успешно используются на любой платформе, где важна привязка именно к низкому уровню.
S>Вы точно уверены, что все реализации C++ных исключений сделаны на базе Windows-ного SEH?
Как они могут быть сделаны на базе SEH в каком-нибудь линуксе, где SEH попросту нет? Но, если ОС предоставляет подобные средства, и они технически позволяют реализовать плюсовые исключения, что может помешать реализовать их именно так?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Спецификация того, как данные размещаются в памяти и выравниваются в ней (если и не для всего языка, то для любой реализации)
OK.
ЕМ>возможность слепого/принудительного преобразования типов
Схерали это низкоуровневая или системно-зависимая часть?
Или вы про type punning через Си-шный union?
ЕМ>обязательная спецификация ABI для каждой реализации
К возможностям языка это вообще не относится.
S>>Вы неправильно понимаете.
ЕМ>Тогда что ж Вам мешает вообразить макропроцессор, работающий не перед фазой компиляции, а во время нее?
Уже надцать раз объяснял: это будет не макропроцессор.
То, что вы хотите, вообще выходит за рамки обобщенного программирования и оказывается в области метапрограммирования. Которое до С++26 вынужденно делалось средствами обобщенного программирования, а начиная с C++26 в нашем распоряжении окажется compile-time рефлексия, которая как раз и будет манипулировать информацией от компилятора.
К макросам это тольно не будет иметь никакого отношения.
При этом compile-time рефлексия не заменит обобщенное программирование на шаблонах.
S>>Вы код пишете для того, чтобы ассемблерный выхлоп изучать или чтобы задачу решить?
ЕМ>А задачи под гигабайты/гигагерцы я могу написать и на Java/JavaScript, где ассемблерного выхлопа и вовсе нет.
Практика показывает, что гигабайты обрабатывать на языках вроде C++ или Rust таки дешевле, чем на Java. Во много из-за "того, как данные размещаются в памяти и выравниваются в ней (если и не для всего языка, то для любой реализации)".
S>>то C++ные шаблоны вам дают именно это.
ЕМ>Они дают не это. Они, грубо говоря, дают примерно то же, что и технологии Meltdown/Spectre
Вы бредите.
S>>Вы точно уверены, что все реализации C++ных исключений сделаны на базе Windows-ного SEH?
ЕМ>Как они могут быть сделаны на базе SEH в каком-нибудь линуксе, где SEH попросту нет?
Я говорю исключительно про платформу Windows, т.к. кроме Windows обсуждать SEH нет смысла.
Re[2]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, so5team, Вы писали:
S>В Википедии есть термин "язык сверхвысокого уровня", он более уместен и однозначен.
Тот же PL/1 никогда не считался "языком сверхвысокого уровня", но он значительно мощнее C, имеет готовые и удобные средства для решения многих типовых для тех лет задач. Если нет жесткого ограничения по ресурсам, писать крупные проекты на нем однозначно проще.
S>Какой-то бред. На платформе, где нет ввода/вывода, у вас просто не будет write и все. Ваша программа не скомпилируется.
Если уж и усматривать тут бред, то в первую очередь в том, что у меня не будет возможности реализовать свой собственный write, если стандартная реализация его не имеет (кроме, как я уже сказал, копания под капотом). Но это Вирту простительно, он не планировал Pascal для сколько-нибудь серьезных применений, они как-то сами получились. А в C разделение, как уже говорил, совершенно логичное, полностью соответствующее классической архитектуре.
S>Копирование объектов — это у вас преобразование типов?
А куда деваться, если есть похожие классы, взаимно преобразуемые друг в друга?
S>Вы тут заявляли о том, что во времена создания C++ было много языков, из которых можно было заимствовать идеи. Но ни одного не смогли перечислить.
Я перечислил наиболее типичные — ассемблер System/360 и PL/1. Не дотянул до критического количества, включаюшего осознание?
S>Вы тут заявляли, что обобщенное программирование может быть проще и гибче, чем в C++. Но ни одного примера не смогли привести.
Ну, раз я не привел ни одного примера в виде кода, то, стало быть, оно и существовать не может. Идея — ничто, код — всё.
S>Ох ё... Есть такое устойчивое выражение в узких кругах "шаблонная магия".
Если б оно было только шуточным, да лишь в узких кругах — может, я и не ворчал бы...
S>Это вы как-то это дело представляете, раз приводите в пример ассемблер с его макросами.
Ну дык, оно ж было придумано как раз для обобщенного программирования на том ассемблере. И мне кажется интуитивно, без дополнительных объяснений, понятным то, что это можно применить в любом другом языке — как тупо, в лоб, так и разумно, в соответствии со свойствами языка. Вы же, судя по всему, из всех возможных вариантов применения видите только два — "в лоб" и "никак".
S>Или же этот пример вычеркиваем.
Да хоть все вычеркивайте, мне не жалко.
S>Не надоело еще лозунги в стиле "за все хорошее" озвучивать?
Так вдруг кто-нибудь сподобится понять, а там, глядишь, и реализует...
S>Еще раз, постараюсь в цензурной форме: макросы работают до компилятора. До.
Угу, а экономика должна быть экономной. Если она вдруг неэкономна, то это не экономика, а что-то другое. А если подходяшего названия из одного слова этому явлению не придумали, то оно и вовсе не существует. Удобно, чо.
S>Когда вы что-то отдаете в макрос, то там еще нет информации от компилятора.
Ладно, коли у Вас действительно настолько туго с воображением (что очень странно в сочетании со способностью уверенно понимать и применять те же многократно вложенные/рекурсивные шаблоны), подскажу один известный пример: версия препроцессора (который, как Вы утверждаете, "всегда работает до компилятора", и на том стоит мир), встроенная в компилятор Turbo C, допускала использование sizeof с любой известной на данный момент (по ходу текста) переменной в условных выражениях для #if. Я не интересовался, что при этом выдавал в листинге самостоятельная версия препроцессора, вынесенная в cpp.exe, но не припомню, чтоб кто-то жаловался на несовместимость, и жаждал получить на такой #if сообщение об ошибке. А вот благодарных было заметное количество — это позволяло, как минимум, обходиться без лишних определений вроде "#define long_size 4".
S>Принцип работы макросов.
Этот принцип принудительно установлен единым для всего мира? Или он имманентно присущ нашему миру, был открыт в ходе исследований, и пока не найдено способов его изменения?
S>Если мы работаем с информацией от компилятора, то это уже не макропрограммирование, а метапрограммирование, когда элементы программы становятся входными данными для дальнейшей программы.
И в чем же принципиальная разница? Почему в тех же ассемблерах макросы могли обрабатываться в первом проходе попутно с обработкой остального текста, а в ЯВУ это вдруг стало невозможным? Какие объективные свойства ЯВУ требуют непременно отдельного, предварительного прохода для обработки макроопределений?
S>в том виде, в котором понравится Музыченко.
Не, в том виде, который понравится большинству людей, не имеющих склонности к искусственному усложнению в угоду идеологии.
S>Александресу показал механизм, который мог использоваться в рамках того C++.
То есть, придумал костыль.
S>Постепенно набрали опыт, развили, усовершенствовали.
Костыль отполировали, покрыли лаком, сделали перекладину переставной, надели мягкую прокладку под мышку, сделали подошву рифленой. Разработали технику скоростной ходьбы на костыле по льду, песку и щебню. Учредили соревнования. На робкие вопросы "может, уже пора полечить ногу?" стыдят: "что ты пристал со своей ногой? ты погляди, какая красота, какая утонченность! в руке его покачай, почувствуй, как сбалансирован!".
S>И на этом, к счастью не останавливаются.
Да — в планах замена дерева на карбон, встраивание навигационного модуля и процессора для анализа темпа ходьбы.
S>Механизм, кстати говоря, вполне себе в духе Prolog-а и функциональных языков.
Я в курсе, что в духе. В тех языках он, возможно, и смотрелся бы куда лучше.
S>Где вы здесь видите побочные эффекты --
Вы делаете вид, что не знаете истории, или прикидываетесь?
S>
В современном C++ практически все это под вашим контролем. За исключением унаследованного из Си неявного преобразования целочисленных типов.
А вот у меня как раз с ними основные заморочки. Но пока мне не предлагают ничего, кроме как делать вид, что все хорошо.
Re[11]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, Евгений Музыченко, Вы писали:
S>>как в этом вашем идеальном макрогенераторе решать ту проблему, для которой в C++ добавили специализацию шаблонов (хоть полную, хоть частичную)?
ЕМ>Элементарно. "Макрос" при обработке своего "вызова" анализирует список параметров (напомню, в этой концепции ему доступны все известные на данный момент компилятору типы и значения) и либо порождает соответствующий код, либо выдает сообщение об ошибке. Для вящего удобства и красоты можно добавить третий вариант — "макрос" завершается с результатом "это определение не подходит" (что будет аналогично SFINAE), и компилятор ищет другой макрос с тем же именем и подходящим набором параметров. Чисто технически это не обязательно, можно обойтись первыми двумя путями, а нужные варианты кода порождать вызовом других "макросов", как это принято делать с функциями.
ЕМ>Этот же механизм можно было бы применить и в перегрузках функций, и вместо обширного перечня неявных преобразований с их приоритетами, указывать только допустимые типы и возможные преобразования в явном виде.
Не, такой подход ведёт к тому, что на третьем шаге (когда в качестве параметра макросу передали макрос, который породил ещё один макрос) становится невозможно отлаживать такой не функциональный код. Эта невозможность происходит из-за того, что код является порождаемым, а не написанным, поэтому его нельзя ни прочитать, ни пройти дебагером. И остаётся два варианта: либо отлаживаться идя по ассемблеру, а после нахождения ошибки долго думать как бы исправить порождение этой машинерии макросов, либо сохранить сгенерённый код и отлаживать его. Второе возможно и сейчас, причём с любым языком, а первое — это мы наблюдаем в С++, когда для класса автоматически создаётся конструктор копирования, кода которого программист не видит и только по косвенным признакам догадывается, что конструктор скопировал объект не так как надо и поэтому после вызова деструктора второго объекта программа падает. Так что описанный вами подход для меня на данный момент выглядит тупиковым, либо я не до конца понимаю, о чём вы пишите.
Здравствуйте, so5team, Вы писали:
ЕМ>>возможность слепого/принудительного преобразования типов
S>Схерали это низкоуровневая или системно-зависимая часть?
Дык, по определению. Многие ли языки дадут привести указатель на float к указателю на unsigned int, чтоб извлечь внутреннее представление плавающего числа?
S>Или вы про type punning через Си-шный union?
Это уже частность.
ЕМ>>обязательная спецификация ABI для каждой реализации
S>К возможностям языка это вообще не относится.
Это относится к его применению. В тех же *nix, OS/2 и Windows весь API заточен под C и его ABI, поэтому любая неигрушечная реализация должна этому следовать.
ЕМ>>что ж Вам мешает вообразить макропроцессор, работающий не перед фазой компиляции, а во время нее?
S>Уже надцать раз объяснял: это будет не макропроцессор.
А если я вслед за Вами начну требовать обоснований, ссылок на единое для всех определение макропроцессора, санкций за отход от него — потянете?
А если я пойду дальше и сделаю реализацию C, в которой препроцессор будет работать в фазе компиляции, но останется полностью совместим со стандартом — меня накажут? Подвергнут остракизму? А если пойду еще дальше, и добавлю туда поддержку предикатов is_*/has_*, применяемых к параметрам макросов? До какого момента такая реализация еще будет иметь право именоваться "препроцессором", а после какого совершенно точно его потеряет?
Только не спешите сразу уверенно отвечать, этот вопрос не так прост, как может показаться на первый взгляд.
Тут ведь вопрос главным образом в том, чего ради Вы так отчаянно отстаиваете подход, при котором любой макропроцессор непременно обязан работать исключительно с "сырым" текстом. Какие непреложные ценности будут нарушены, если Вы отступите от этого принципа?
S>То, что вы хотите, вообще выходит за рамки обобщенного программирования и оказывается в области метапрограммирования. Которое до С++26 вынужденно делалось средствами обобщенного программирования, а начиная с C++26 в нашем распоряжении окажется compile-time рефлексия, которая как раз и будет манипулировать информацией от компилятора.
Ну, то есть, на двадцать какой-то год "Зоркий Глаз внезапно заметил", а на тридцать какой-то год "Могучий Ум сообразил, как это использовать". Достойно всяческих похвал.
S>К макросам это тольно не будет иметь никакого отношения. S>При этом compile-time рефлексия не заменит обобщенное программирование на шаблонах.
То есть, как всегда, возможности добавляются строго дозированно, дабы сообщество чрезмерно не возрадовалось, а у Комитета были основания еще много лет делать вид бурного развития. А ведь могли бы относительно просто (через те самые макросы) решить обе задачи еще десятки лет назад, и все оставшееся время заниматься реально полезными улучшениями.
S>Практика показывает, что гигабайты обрабатывать на языках вроде C++ или Rust таки дешевле, чем на Java.
Дык, я-то знаю. Но многих ли это нынче волнует? Если сказано, что на железе, выполняющем несколько миллиардов операций в секунду, технически невозможно обеспечить открывание выпадающего меню быстрее, чем за 0.5 с, какая часть пользователей в этом усомнится?
ЕМ>>Они дают не это. Они, грубо говоря, дают примерно то же, что и технологии Meltdown/Spectre
S>Вы бредите.
Или у Вас плохо с воображением.
S>Я говорю исключительно про платформу Windows, т.к. кроме Windows обсуждать SEH нет смысла.
Зачем обсуждать исключительно SEH? Или Windows — единственная ОС, в которой поддержка аппаратных исключений доступна прикладным процессам?
Re[12]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, B0FEE664, Вы писали:
BFE>на третьем шаге (когда в качестве параметра макросу передали макрос, который породил ещё один макрос) становится невозможно отлаживать такой не функциональный код.
Во-первых, грамотная реализация макроязыка не требует введения служебных, вспомогательных макросов (и на сишных макросах, и на плюсовых шаблонах многие вещи технически невозможно сделать иначе), так что подобная вложенность была бы скорее исключением, чем правилом.
Во-вторых, когда в обработке макросов четко прослеживается стадийность, отладка всегда проще, чем когда состояний только два — на первом входе и на последнем выходе.
Кстати, в любой реализации C++ достаточно легко сделать развернутый вывод сообщений от компилятора о ходе обработки шаблонных подстановок — как выглядела исходная конструкция, во что она превратилась после "канонизации", какие преобразования и подстановки выполнялись на каждом уровне вложенности, каким был результат подстановки каждого из вложенных шаблонов и т.п. Причем не только при ошибках, но и при успешном выполнении. Это сильно облегчило бы и отладку, и диагностику. Насколько я знаю, ни в одной реализации такого нет.
BFE>код является порождаемым, а не написанным, поэтому его нельзя ни прочитать, ни пройти дебагером.
Что значит "нельзя"? Если я сделаю реализацию, которая будет выводить порожденный код в стандартный поток — какие законы или священные заповеди я нарушу? А если вставлю в компилятор примитивный отладчик, который будет выполнять обработку по шагам, и можно будет не только спросить у него текущие значения параметров и локальных переменных, но и поменять их? В этом нет ничего сложного, доля такой функциональности в общих затратах на разработку компилятора ничтожна.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>>>возможность слепого/принудительного преобразования типов
S>>Схерали это низкоуровневая или системно-зависимая часть?
ЕМ>Дык, по определению. Многие ли языки дадут привести указатель на float к указателю на unsigned int, чтоб извлечь внутреннее представление плавающего числа?
С++ это и не позволяет.
S>>Или вы про type punning через Си-шный union?
ЕМ>Это уже частность.
Эта частность под запретом.
ЕМ>>>обязательная спецификация ABI для каждой реализации
S>>К возможностям языка это вообще не относится.
ЕМ>Это относится к его применению.
Мы говорим о языке.
ЕМ>>>что ж Вам мешает вообразить макропроцессор, работающий не перед фазой компиляции, а во время нее?
S>>Уже надцать раз объяснял: это будет не макропроцессор.
ЕМ>А если я вслед за Вами начну требовать обоснований, ссылок на единое для всех определение макропроцессора, санкций за отход от него — потянете?
A general-purpose macro processor or general purpose preprocessor is a macro processor that is not tied to or integrated with a particular language or piece of software.
ЕМ>А если я пойду дальше и сделаю реализацию C, в которой препроцессор будет работать в фазе компиляции, но останется полностью совместим со стандартом — меня накажут? Подвергнут остракизму? А если пойду еще дальше, и добавлю туда поддержку предикатов is_*/has_*, применяемых к параметрам макросов? До какого момента такая реализация еще будет иметь право именоваться "препроцессором", а после какого совершенно точно его потеряет?
Пойдите и сделайте. Звиздеть не мешки ворочать.
ЕМ>Только не спешите сразу уверенно отвечать, этот вопрос не так прост, как может показаться на первый взгляд.
Что вы сделаете язык программирования? Обкакаетесь.
S>>Я говорю исключительно про платформу Windows, т.к. кроме Windows обсуждать SEH нет смысла.
ЕМ>Зачем обсуждать исключительно SEH?
Я у вас спросил уверены ли вы что все компиляторы C++ под Windows используют SEH для реализации обсуждений. Но вы настолько балабол, что даже на прямой вопрос ответить не можете.
Re[17]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, Евгений Музыченко, Вы писали:
S>>Постепенно набрали опыт, развили, усовершенствовали.
ЕМ>Костыль отполировали, покрыли лаком, сделали перекладину переставной, надели мягкую прокладку под мышку, сделали подошву рифленой. Разработали технику скоростной ходьбы на костыле по льду, песку и щебню. Учредили соревнования. На робкие вопросы "может, уже пора полечить ногу?" стыдят: "что ты пристал со своей ногой? ты погляди, какая красота, какая утонченность! в руке его покачай, почувствуй, как сбалансирован!".
Евгений, я честно пытался выудить из вас хоть какие-то крупицы конструктива.
Для меня ваше поведение выглядит так:
— вы заявляете, что во времена создания С++ было множество языков, из которых нужно было просто брать лучшее;
— вам задают вопрос о том, что это были за языки, но вы с трудом озвучиваете ассемблер для System/360 (что даже не смешно) и PL/1, который тогда был общепризнаным образом того, как не нужно проектировать языки программирования (т.е. это был жупел, а не образец). Вы не смогли назвать ни одного внятного примера;
— вы заявляете, что есть языки программирования, которые поддерживают обобщенное программирование еще лучше, чем C++;
— вас просят показать эти языки, но вы не можете;
— вы хаете сделанное в C++ с намеком на то, что нужно было просто смотреть по сторонам, брать лучшее и сразу делать все так, как понравилось бы г.Музыченко.
Вас послушать, так просто удивительно как столько далеко не глупых людей, работавших над C++, ни до чего подобного не додумались. Все же так просто -- вот у Музыченко столько идей. Он, правда, не может их выразить даже в примерах кода, но идеи-то какие.
г.Музыченко глубоко фиолетово, что никто и никогда не знает как правильно, особенно когда делает что-то подобное C++у или PL/1, или Rust-у. Поэтому делают что получается, накапливают опыт, рожают новые идеи, пытаются их впихнуть в существующие рамки, чтобы не поломать вообще все.
И только у г.Музыченко, широко известного во всем мире своими достижениями в области разработки языков программирования, есть совершенно афигительные идеи, до которых пока что никто не дорос и не воплотил в жизнь. Даже удивительно почему так.
Re[13]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, Евгений Музыченко, Вы писали:
BFE>>на третьем шаге (когда в качестве параметра макросу передали макрос, который породил ещё один макрос) становится невозможно отлаживать такой не функциональный код. ЕМ>Во-первых, грамотная реализация макроязыка не требует введения служебных, вспомогательных макросов (и на сишных макросах, и на плюсовых шаблонах многие вещи технически невозможно сделать иначе), так что подобная вложенность была бы скорее исключением, чем правилом.
Речь не о служебных макросах, а о макросах порождающих другие макросы.
ЕМ>Во-вторых, когда в обработке макросов четко прослеживается стадийность, отладка всегда проще, чем когда состояний только два — на первом входе и на последнем выходе.
Отслеживается — это как? По логам?
ЕМ>Кстати, в любой реализации C++ достаточно легко сделать развернутый вывод сообщений от компилятора о ходе обработки шаблонных подстановок — как выглядела исходная конструкция, во что она превратилась после "канонизации", какие преобразования и подстановки выполнялись на каждом уровне вложенности, каким был результат подстановки каждого из вложенных шаблонов и т.п. Причем не только при ошибках, но и при успешном выполнении. Это сильно облегчило бы и отладку, и диагностику. Насколько я знаю, ни в одной реализации такого нет.
Если подстановка не удалась, то gcc выводит рассмотренные варианты. Это действительно помогает. Как это поможет отладке —
BFE>>код является порождаемым, а не написанным, поэтому его нельзя ни прочитать, ни пройти дебагером. ЕМ>Что значит "нельзя"? Если я сделаю реализацию, которая будет выводить порожденный код в стандартный поток — какие законы или священные заповеди я нарушу?
Нарушений заповедей — нет, но это не будет ничем отличаться от кодогенерации.
ЕМ> А если вставлю в компилятор примитивный отладчик, который будет выполнять обработку по шагам, и можно будет не только спросить у него текущие значения параметров и локальных переменных, но и поменять их? В этом нет ничего сложного, доля такой функциональности в общих затратах на разработку компилятора ничтожна.
А что вам сейчас мешает так делать? Берёте свой кодогенератор, на макроязыке пишите код, сохраняете в файл и напускаете на этот файл свой кодогенератор — на выходе код на C++, который компилируете C++ компилятором. Вот в Qt есть такой moc — Qt Meta Object Compiler. Вы за подобный подход?
И каждый день — без права на ошибку...
Re[14]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, B0FEE664, Вы писали:
BFE>Вы за подобный подход?
Как я понимаю -- нет. Он хочет полноценного метапрограммирования на этапе компиляции. Как раз того, что сейчас завозят в C++26 в виде compile-time рефлексии.
Здравствуйте, so5team, Вы писали:
ЕМ>>привести указатель на float к указателю на unsigned int, чтоб извлечь внутреннее представление плавающего числа?
S>С++ это и не позволяет.
Как, и с каких пор?
S>>>Или вы про type punning через Си-шный union? ЕМ>>Это уже частность.
S>Эта частность под запретом.
Как, с каких пор?
S>>>К возможностям языка это вообще не относится. ЕМ>>Это относится к его применению.
S>Мы говорим о языке.
A general-purpose macro processor or general purpose preprocessor is a macro processor that is not tied to or integrated with a particular language or piece of software.
Приставка general-purpose Вас, стало быть, совершенно не смущает. Как и непоколебимая уверенность в том, что любой макро/препроцессор непременно обязан быть general-purpose, иначе основы мироздания рухнут. Ну и ради бога, бывает.
S>Пойдите и сделайте.
Надо будет — пойду и сделаю. Квалификации мне для этого хватает более чем, вопрос исключительно в целесообразности.
Re[14]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, B0FEE664, Вы писали:
BFE>Речь не о служебных макросах, а о макросах порождающих другие макросы.
Это довольно-таки специфический прием, куда больше свойственный неалгоритмическим языкам. Насколько он мог бы оказаться полезен в языках вроде C++? Скорее всего, какие-то интересные приемы найдутся, но вряд ли их будет много, и вряд ли они станут сколько-нибудь массовыми. Ну а энтузиасты нехай развлекаются в свое удовольствие, ежли не лень. Даже если какой-нибудь новый Александреску и сваяет на таких техниках что-то подобное Loki, оно вряд ли выйдет за пределы узких тусовок и специфических соревнований. Ведь массовое распространение подобных творений случилось исключительно от убожества адекватных средств языка, вот народ и ударился в плохо понимаемые и трудно отлаживаемые конструкции.
ЕМ>>когда в обработке макросов четко прослеживается стадийность
BFE>Отслеживается — это как? По логам?
У меня было "прослеживается" — по типичным способам обработки. Вот на этих стадиях нетрудно вставить вывод в логи. Тема логов компиляторов вообще как-то очень плохо раскрыта — еще один пример "залипания" коллективного мышления.
BFE>Если подстановка не удалась, то gcc выводит рассмотренные варианты. Это действительно помогает. Как это поможет отладке —
А, Вы имеете в виду отладку порожденных текстов во время выполнения? Здесь тоже не слишком сложно придумать способы облегчения. Можно сохранять конечные результаты разворачивания макросов во временные файлы, из которых делать ссылки на исходные тексты. Тогда к традиционному номеру исходной строки в отладочной информации добавится номер строки в окончательно развернутом макросе. При желании нетрудно отражать таким образом и вложенные макросы, но насколько это будет востребовано?
BFE>Нарушений заповедей — нет, но это не будет ничем отличаться от кодогенерации.
Я думал, Вы имеете в виду возможность увидеть порожденный макросом текст, передаваемый на компиляцию, и/или пройти по шагам процесс разворачивания сложного (например, циклического) макроса во время компиляции.
BFE>А что вам сейчас мешает так делать? Берёте свой кодогенератор, на макроязыке пишите код, сохраняете в файл и напускаете на этот файл свой кодогенератор — на выходе код на C++, который компилируете C++ компилятором. Вот в Qt есть такой moc — Qt Meta Object Compiler. Вы за подобный подход?
Не, это будет корявый костыль, ничем не лучше препроцессора для "C с классами" к стандартному C. Да и не получится это в виде препроцессора — самая-то вкуснота именно в том, чтобы использовать имеющийся компилятор C++ для разбора информации о типах, размерах, связях и прочем, а в нужный момент эти сведения у него получить. К готовому компилятору такое можно прикрутить только в виду плагина. Но единого стандарта на такие плагины нет, поэтому для каждого компилятора пришлось бы делать заново.
Re[15]: The Big OOPs: Anatomy of a Thirty-five-year Mistake
Здравствуйте, so5team, Вы писали:
S>Он хочет полноценного метапрограммирования на этапе компиляции. Как раз того, что сейчас завозят в C++26 в виде compile-time рефлексии.
Я пока не изучал, что именно туда завозят, но имею смутные сомнения в том, что оно будет хотя бы наполовину полноценным в моем понимании этого термина. Скорее всего, как повелось, скупо нацедят несколько сугубо частных решений, объявят об очередном эпохальном прорыве, многие пользователи сразу же упрутся в ограничения (как повелось — искусственные), начнут мастырить костыли имеющимися средствами, и радикальных перемен не случится.