LINUX.ORG.RU

Герб Саттер предлагает добавить в С++ метаклассы

 , ,


1

7

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0707r0.pdf

В свежем пропосале Саттер предлагает добавить в С++ механизм для добавления пользовательских мета-типов. Автор отталкивается от наблюдения, что struct это просто class с public:, а enum class это просто class с константами, и предлагает обобщить этот подход и сделать его доступным разработчику. Вот пример реализации аналога interface из Java :

$class interface
{
    ~interface() noexcept {}
    constexpr {
        compiler.require($interface.variables().empty(),
                         "interfaces may not contain data");
        for (auto f : $interface.functions()) {
            compiler.require(!f.is_copy() && !f.is_move(),
                             "interfaces may not copy or move; consider a"
                             " virtual clone() instead");
            if (!f.has_access ()) f.make_public();
            compiler.require(f.is_public(),
                 "interface functions must be public");
            f.make_pure_virtual();
        }
    }
};
// User code (proposed C++)
interface IShape {
    int area() const ;
    void scale_by(double factor);
};
Лично я не верю, что комитет это пропустит, но сам Саттер не последний человек в комитете и понимает, что предлагает.

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

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

И да, это не означает, что CL не мертв.

Как говорил Оби Ван Кеноби: «кто глупее: дурак или тот, кто следует за ним?»

Это я про утаскивание фич из «мёртвых» языков.

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

К слову, это легко решается через атрибут derive в rust. Правда хз, сделал уже кто-то такое или нет.

при чем тут раст? тема про C++

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

В этом случае для полей нужно задавать значения Tag. Что-то вроде:

треш, угар и содомия же. вот для примера, как это в D делается

ещё с Dconf2017 прикольные примеры про CTFE парсеры, Pry и Pegged

и CTFE ассемблер

compiler.require($

поговаривают в D, чтобы сделать компилятор библиотекой

аллокации и «ненужный» GC тоже можно убрать. для этого нужно заменить рантайм и библиотеку контейнеров. в этом направлении работает Тимур.

например, пишет игрушку с PBR на движке.

где-то то ли в бложике, то ли в журнале FPS, то ли на гитхабе он писал про свою библиотеку контейнеров, и про то, что ему удалось отстрелить GC.

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

среднестатистический дебил, пищущий на C++ этого не оценит

А ему и не надо. А вот библиотекам будет полезно, что оценят уже все.

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

или ещё отсюда про библиотеку контейнеров и отстреливаемый GC

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

треш, угар и содомия же. вот для примера, как это в D делается

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

Казалось бы, задрачиваете вы на D до кровавых волдырей на ладонях, ну никто же не запрещает. Никто не может помешать вам притащить кучу никому не интересных ссылок про D в тред про C++.

Ну, млин, что во фразе «Например, пусть используется механизм Tag-Length-Value (он же ASN1 BER). В этом случае для полей нужно задавать значения Tag.» вам настолько не понятно, что вы позволяете себе показать пример сериализации в JSON? Олигофрения или что?

eao197 ★★★★★
()

метаклассы в С++ — не прошло и 20 лет..

... после диссера (автореферат | сам диссер) Константина Книжника про ООСУБД GOODS, где он применил метаклассы и ООП (на с++98) для разработки сервера ОО СУБД:

1. сначала добавляется рефлексия и интроспекция в С++98. кривым, ужасным, компиляторозависимым и непереносимым битхаком, с картами сообщений в духе MFC макросов (раскрывающиеся в нечто типа SFINAE)

2. затем, на полученной интроспекции он изображает метаклассы (в С++98, да)

3. затем, на метаклассах изображает метаобъектный протокол (в С++98, да. «Art of MOP» тут совершенно не причём, ога-ога )))

4. затем, на МОП в С++ он изображает аспекты и АОП.

5. затем, аспектами реализует подкачку страниц, стратегии ACID для персистентности объектного сервера, поддержку транзакций, многопоточности. это отдельные слои в сервере ООСУБД, которые реализованы как аспектно-ориентированное программирование поверх МОП.

... и всё это работает на С++98. ну разве что, дикий битхак и компиляторозависимость, поэтому немного «неаккуратненько».

.... не прошло и 20 лет, как Саттер тоже что-то подобное предложил пропихнуть в основной стандарт С++.

прогресс!!! развитие!!! С++ --- инновационные технологии же!!! С++ — глобально и надёжно !!! 111 адын адын адын

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

смотри начиная с 41 слайда, например. чем тебе сериализация в JSON не нравится? главное, общий паттерн — как пишется сериализация.

В этом случае для полей нужно задавать значения Tag

как задавать это в С++?

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

слайд 47, например. вот как это сделать в с++?

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

Rust? Haskell? Не, не слышал. Рефлексия бывает разной и с eval связана куда меньше чем ты думаешь. Загляни например в tcc, где при отсутствии рефлексии есть некоторая вариация eval. Да и что плохого в eval в конце концов?

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

точнее даже, 59-62. там трейты, которых в С++ как раз и нету.

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

compiler.require

и чем он ещё будет расширять «интерфейс компилятора»? и для этого что, нужно будет ждать очередного стандарта С++10500x?

в D можно помимо стандартных трейтов использовать универсальный трейт «это компилируется».

и всё это работает уже сейчас, а не когда там какой-то комитет одобрит.

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

откуда ты эти Tag-Length-Value в С++ выковыривать собираешься ?

Еще раз: что в исходном комментарии, на который вы пытаетесь ответить, вам не понятно? Там все расписано, с примерами. Демонстрирующими что нужно от языка, дабы это получить. Что вам не понятно?

чем тебе сериализация в JSON не нравится?

Тем, что не везде используется JSON, ваш К.О.

главное, общий паттерн — как пишется сериализация.

Ага, какой-то анонимный дятел будет учить меня сериализации. Дяденька, вы совсем больной?

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

Что вам не понятно?

как вот тут считается это 0x28? какой функцией? как предикат с лямбдой считается, как его сгенерировать?

[[tlv-tag=0x28;tlv-store-if=(cx!=cy)]] int cy;

Тем, что не везде используется JSON, ваш К.О.

сам ты дятел. смотри в суть кода: что и как там считается в атрибутах рефлексии, а не в форму.

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

а теперь напиши CTFE С++ код, который это генерирует.

как считаются индексы, откуда берутся предикаты, как заполняются атрибуты, как они используются. вот это вот всё.

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

вот слайды 41-50 например, показывают как это всё заполняется. отсюда понятно, как этот шаблон генерируется, во что он разворачивается, как применяется.

а из твоего «примера» как генерируется атрибут — не понятно. почему 0x27 а не 10500, например?

контекст использования тоже не ясен. tlv-store-if как используется? когда, в каких случаях? как корректность этих случаев гарантировать CTFE, при раскрытии шаблона?

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

карочи, напиши аналог makeStruct для своего примера. на С++, лол.

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

в D то понятно, откуда брать инфу по рефлексии, для трейтов: из тайпинфо. которое там есть.

откуда его брать в С++, тоже из тайпинфо которого там нет?

и нерасширяемый compiler.require без универсального механизма расширения типа __trait(compiles, ...) не поможет.

вот пример про слайды с инструментацией COM (слайды 63,64) — как в С++ через compiler.require делать?

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

ваш пример

void f(const rectange & a, const rectangle & b) {
  if(a == b) {...}
}
Я всё таки не понимаю, чего вы хотите, т.к. пример кода сравнения вы не приводите даже в гипотетическом варианте.

Ну давайте я предположу. Сравнивать rectangle с rectangle мы умеем и так, значит речь идет о производных от rectangle класса.

А это невозможно, потому что это невозможно. Вот поставьте себя на место компилятора. Вам дали один translation unit в котором есть всего один описанный вами оператор сравнения. Вопрос: как мне учесть все возможные варианты производных от rectangle классов?

Часть производных классов может вообще быть определена только в других cpp-файлах, либо в других библиотеках. Как вы собираетесь сравнивать неизвестно что с неизвестно чем?

Пусть у нас есть rectangle, производные от него animal и подушка, от animal производные змея и собака, от подушки - сено и бревно. Причем в данном файле вам доступны только rectangle и подушка. Ну например. Вот как вы в compile time сравните бревно со змеёй?

Давайте даже для простоты наложим на rectangle требование обладать vtable, либо же будем неявно передавать информацию о типе в числе прочих аргументов. Максимум что нам это даст - это возможность вручную перебрать и сравнить все memberы. Только это не compile-time, а runtime.

ckotinko ☆☆☆
()
Ответ на: комментарий от anonymous

как вот тут считается это 0x28? какой функцией? как предикат с лямбдой считается, как его сгенерировать?

Объясню для совсем уже альтернативно одаренных: посыл был в том, что предлагаемый способ рефлексии позволит сделать только очень простые способы сериализации. В более сложных случаях, как, например, в ASN1 BER, пользователь должен будет предоставить дополнительную информацию для системы сериализации. Как то: значения Tag-ов (тот самый 0x28 или 100500, это зависит от конкретного транспортного протокола), предикаты для выявления опциональных атрибутов и пр.

Один из возможных способов того, как предоставить такую информацию и был показан.

Очевидно, что сейчас в C++ это невозможно. И вряд ли будет возможно даже после принятия предложения Саттера. Поэтому все это для сложных видов сериализации вряд ли поможет. На что и был обращен акцент.

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

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

Я всё таки не понимаю, чего вы хотите, т.к. пример кода сравнения вы не приводите даже в гипотетическом варианте.

Очевидно, что не понимаете.

Во в чем смысл: допустим, я написал класс rectangle, в котором будут только поля. Мне лень писать оператор равенства, который тривиальный, но довольно объемный. Я бы хотел сделать что-то вроде:

struct rectangle {...};
$make_strick_eq_operator<rectangle>;
после чего иметь возможность писать:
void f(const rectange & a, const rectangle & b) {
  if(a == b) {...}
}

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

Я всё таки не понимаю

ты тормоз, у тебя сутки были чтобы разобраться

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

мой point в том, что в D это всё возможно уже сейчас. а в том способе, что предлагает Саттер недостаточно, ибо недостаточно универсально расширяемо.

В более сложных случаях, как, например, в ASN1 BER, пользователь должен будет предоставить дополнительную информацию для системы сериализации. Как то: значения Tag-ов (тот самый 0x28 или 100500, это зависит от конкретного транспортного протокола), предикаты для выявления опциональных атрибутов и пр.

ты не умничай, ты пальцем покажи. то есть: напиши код на метаязыке, шаблон, который расширяется в нужный код на языке, вычисляя все эти 0х28 во время компиляции метаязыка, специализированного <<непонятно-чем>>.

вот насколько гибкий должен быть метаязык чтобы всё это вычислить и почему предложенный Саттером вариант не подходит?

моё ИМХО: потому что предложенный им вариант «метаклассов» недостаточно универсален, в отличие от.

Один из возможных способов того, как предоставить такую информацию и был показан.

не показан, ибо у тебя не показано как вычисляется эта «дополнительная информация». или её пользователь руками предоставляет, для всех случаев считая «в уме»? тогда тю это, а не метавычисления.

тоже и про сериализацию: нужно максимально вычислять всё, что вычисляется, используя максимально универсальный механизм. например, тот же метаобъектный протокол с рефлексией — либо как в Common Lisp (1) либо как у К. Книжника (2) либо как string mixin и template mixin на D.

пойнт в том, что в этих механизмах расширения — с предложенным примером всё в порядке, в отличие от С++.

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

хотя аналог string mixin / template mixin у Саттера вроде бы есть: inject -> { ... }

но в отсутствие __trait(compiles, ... ) это ... может быть всяким мусором.

я так понял, он предлагает обмазаться концептами и constraints. ИМХО, не получится, да и человеконечитаемая лапша типа буста будет на выходе.

в отличие от D в котором это возможно уже сейчас.

и когда причешут компилятор библиотекой и альтернативный Druntime с контейнерами, с custom memory allocator (не требующие GC) — будет ещё красивее выглядеть.

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

в отличие от D в котором это возможно уже сейчас.

Все очень рады за D, но тема про C++. Неадекватный спам про свой любимый язык приветствуется в сообществе раста, как туда попасть и что в первую очередь рассказать им про D спросите у RazrFalcon

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

Извините, а нельзя просто привинтить что-нибудь типа

bool operator==(const X& other) const = default
которое сравнивало бы поля?!

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

Ну метаст^W метаклассы-то это совсем другое дело, это же очевидно как их сделать.

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

есть конкретный пример про практическое применение, из той же презентации «Practical Metaprogramming» с DConf 2017.

примеры просты и наглядны, ясен контекст, механизм и реализация механизма. функция-конструкция-назначение.

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

в отличие от других способов реализации и применения метаклассов: тот же MOP, ну или метаклассы в объектной модели SOM в OS/2.

ну или примеры из презентации.

вот если пропозал Саттера переписать под примеры из презентации, будет более ясна суть собсно пропозала, с практическим применением и контекстом.

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

как минимум, оно менее наглядно, чем примеры из презентации.

другие доклады из DConf тоже интересны, в контексте топика.

например про CTFE реализации парсеров, один Pry на парсер комбинаторах, и другой Pegged — в packrat стиле, с мемоизацией.

парсером раскручивается свой язык, полностью во время компиляции. то есть, пример с ASN1 BER в общем-то вполне себе написать можно, где и написать eval для метаязыка, который будет вычисляться в атрибуты. в это самое 0х28 и pred(cx)=condition(cx), но при этом например с проверкой, что pred(cx)=condition(cy)=const(cx) недопустимо, с каким-то model checking.

возникает вопрос, как это всё сделать на С++. или всё-таки никак не получится? ни с текущим С++, ни с предложением Саттера тоже, ибо предложенного им механизма недостаточно?

anonymous
()

В треде не хватает смайлофага

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

Мне кажется, что кресты больше относятся к «миру», чем оторванные от него Rust, D или с чем вы ещё приходите в тред.

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

Во в чем смысл: допустим, я написал класс rectangle, в котором будут только поля. Мне лень писать оператор равенства, который тривиальный, но довольно объемный.

так погодите, всё ради чего вам нужна рефлексия, это вот это что ли? фи... уже писали, что можно просто сделать = default. и это проще для разрабов компиляторов. то что это в стандарт не прошло - это вообще мелкие детали. вы ведь тоже расширение С++ предлагаете, причем намного более сложное.

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

что можно просто сделать = default

Но вот не сделали же. Так почему бы не переложить рутину на метаклассы и рефлексию?

вы ведь тоже расширение С++ предлагаете

Хде?

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

а чо, рефлексия это не расширение С++?

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

ну может вы просто хотите новый D получить

Лично я бы хотел получить «очищенный» C++, который не тянет за собой наследия C, и который бы был максимально похож на нынешний C++ по синтаксису и семантики, чтобы можно было с разумными усилиями портировать туда свой плюсовый код. D в таком качестве меня не интересует.

Но это не значит, что не нужно тащить из D все, что там сделано удачно. Вот static if в виде if constexpr уже утащили. Можно еще что-нибудь скомуниздить.

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

Меня всегда интересовало, откуда лезут все эти долбоящеры?

Какие? Которым не понятная польза от новых фич?

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

Да и что плохого в eval в конце концов?

Искушение использовать его, чтобы посчитать введенное пользователем выражение. Думаю, не нужно рассказывать, к чему такое приводит.

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

Тем не менее, здесь уже упомянули и питон, и Джаву, и Д, и борщелишп.

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

Извините, а нельзя просто привинтить что-нибудь типа

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

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.