Кресты / Говнокод #25558 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
https://habr.com/ru/article/448466/

*/
А последние пару лет набирает популярность boost.hana. Это boost.fusion,
но с constexpr'ом и лямбдами. Автор hana, Луис Дионе (Louis Dionne),
используя на полную мощь все возможности новых стандартов, в некотором
смысле очеловечил метапрограммирование. С помощью hana всяческие
манипуляции с типами, их кортежами, отображениями, а также компайл- и
рантайм-работа с ними обрели практически человеческое лицо и читаемый
вид. Ну, с поправкой на синтаксис C++, разумеется. Вот, например, как выглядит
универсальный сериализатор структур, написанный с помощью hana:
*/

// 1. Give introspection capabilities to 'Person'
struct Person {
  BOOST_HANA_DEFINE_STRUCT(Person,
    (std::string, name),
    (int, age)
  );
};
// 2. Write a generic serializer (bear with std::ostream for the example)
auto serialize = [](std::ostream& os, auto const& object) {
  hana::for_each(hana::members(object), [&](auto member) {
    os << member << std::endl;
  });
};
// 3. Use it
Person john{"John", 30};
serialize(std::cout, john);

/*
Ну да, структуры приходится описывать особым образом. А кому сейчас легко?
И тут хочется также отметить библиотеку tinyrefl за авторством Manu Sánchez
(Мануэля Санчеса). Довольно неплохая попытка принести в мир C++-разработки
статическую рефлексию без расширения компилятора. Для своей работы библиотека
требует стороннюю утилиту (cppast), но зато предоставляет довольно удобный доступ
к информации о структурах, которую можно использовать в процессе разработки
программы. Преимущество этой библиотеки (по сравнению с другими) в том, что для
работы с ней не надо использовать «птичий язык», а элементы структур (как и сами
структуры) можно произвольным образом атрибутировать прямо в исходном коде:
*/

struct [[serializable]] Person {
    std::string name;
    int age;
};
template<typename Class>
auto serialize(std::ostream& os, Class&& object) -> std::enable_if_t<
        tinyrefl::has_metadata<std::decay_t<Class>>() &&
        tinyrefl::has_attribute<std::decay_t<Class>>("interesting"),
    std::ostream&>
{
    tinyrefl::visit_member_variables(object, [&os](const auto& /* name */, const auto& var) {
        os << var << std::endl;
    });
    return equal;
}

/*
Таких примеров можно привести ещё много (или найти на гитхабе или гитлабе).
Объединяет все эти библиотеки и инструменты одна особенность: значительно
облегчая жизнь своим пользователям, они имеют такую реализацию, что остаётся
лишь предполагать, какое количество страданий испытали их разработчики. Достаточно
заглянуть в реализацию, увидеть забор из ifdef'ов и угловых скобок — и всё понятно.
Нередко эти реализации делаются на грани возможностей компиляторов. workaround'ы
банальных ошибок (или особенностей реализации языка конкретной версии конкретного
компилятора с конкретными флагами) здорово раздувают их код. Желание поддерживать
несколько стандартов сразу заставляет придумывать зубодробильные конструкции.
Безусловно, простая попытка реализовать что-нибудь подобное здорово поднимает уровень
владения языком (иногда — и самооценку). Но в какой-то момент, после многочасовой возни
с очередной ошибкой, или непроходящим тестом, или крэшем компилятора руки опускаются,
хочется плюнуть и бросить, ибо силы бороться иссякают.
*/

Именно поэтому я за гомоиконность

Запостил: j123123 j123123, (Updated )

Комментарии (50) RSS

  • > 1.4 Генерация кода

    > Но это, как говаривал Барон, ещё не все. Однажды в мир разработки C++ пришёл clang со своим фронтендом (а чуть позже — с libtooling), и мир изменился, заиграл новыми красками. Появилась надежда. Ибо появился инструмент, позволяющий относительно просто (относительно!) анализировать исходные тексты на C++ и что-нибудь с результатами этого анализа делать. Появились (и стали набирать популярность) утилиты типа clang tidy, clang format, clang static analyser и прочие. А некоторые разработчики приспособили clang frontend для решения задач рефлексии. Так, скажем, работают упомянутые выше cppast (за авторством Jonathan Müller) и tinyrefl на её базе. Так работает автопрограммист, используемый в нашей компании для кодогенерации (или его open-source-аналог).

    > Разумеется, и до появления clang писались генераторы на основе исходного кода C++. Кто-то использовал для этого Python с самописными парсерами, кто-то разбирал C++ с помощью regexp'ов. Кто-то, как автор этой статьи, писал самопальный парсер на C++. Но, полагаю, с развитием инструментария это будет уходить в прошлое.

    > Идея проста. Берётся исходный текст на C++ (например, объявления структур), пропускается через clang frontend, и на основе полученного AST генерируется новый исходный текст.

    Именно поэтому.
    Ответить
  • > Это может выглядеть забавно, но сейчас уже заходит речь об интеграции в компилятор оптимизирующих JIT-движков. Потому как constexpr'ы как-то медленно вычисляются...

    Я уже не один раз высказывал эту гениальную мысль на страницах говнокода

    http://govnokod.ru/25397#comment460314
    http://govnokod.ru/25407#comment461860
    Ответить
  • > 3.1 Основы концепции
    > Макросы (C++), шаблоны (C++98), свойства типов и constexpr'ы (C++11), концепты (C++20) — с каждым новым стандартом и витком развития язык предоставляет разработчику всё больше информации о том, что творится в недрах компилятора: начиная от манипуляции на уровне лексем и заканчивая compile-time-вычислениями и декларативным описанием свойств пользовательских типов. Логичное завершение (или продолжение?) этой цепочки — предоставление разработчику возможности напрямую манипулировать процессом компиляции кода на уровне AST. И такое предложение уже есть.

    Ох б%?№^& сука... ну охуеть теперь. Лучше сделайте новый язык, а этот выкиньте нахуй. Сделайте диалект лиспа с байтоебством и без GC. Я довольно хуево себе представляю то, каким образом с текущим крестоговносинтаксисом вы буделе делать манипуляции с AST
    Ответить
    • > диалект лиспа с байтоёбством и без GC
      И с UB'ами во время конпеляции!

      Но это уже будут не кресты. Вся суть крестов - прикручивать к ним новую хуйню не ломая совместимость со старой. Это как игра про башню из кирпичиков.
      Ответить
      • > Это как игра про башню из кирпичиков.

        Как строить башню из брикетов спрессованного дерьма. http://toplivnye-brikety.mya5.ru/toplivnye-brikety-iz-navoza/

        Эту башню еще постоянно перекашивает под собственным весом, и стоит она на таком же самом фундаменте из говна. И даже если эту говноконструкцию идеально сбалансируют и стабилизируют - всё равно она останется говном и будет вонять
        Ответить
          • Никогда не видел, что происходит, когда к прочному клею приклеиваешь рыхлые материалы? Сам клеевой шов остаётся почти целым, рвётся приклеенный материал рядом со швом.
            Ответить
        • Башня из спресованного дерьма это веб а не С++

          PHP, JSON, JavaScript, CSS -- это все дерьмо
          Ответить
          • Вот хотя-бы на JSON не надо пиздеть.
            Ответить
            • jSON не типизированое дерьмо которое придумали смущиебы жабаскриптеры которые не слышали ни про IDE ни про статический анализ
              Ответить
              • А какой сейчас типизированное недерьмо популярно?
                Ответить
                • Твой вопрос не имеет смысла потому что недерьмо не может быть популярным. В современном программировании популярно только дерьмо, а уж в современном веб-программировании тем паче.
                  Ответить
            • блядь
              как можно в 2019 году делать язык с таким оператором

              v!??>
              Ответить
    • > манипуляции с AST
      В предложении про метаклассы это выглядело довольно просто - из constexpr блока можно позвать оператор -> {...} который высрет хуйню из скобок в родительский блок и раскроет в ней $переменные. Ну и оператор $, которым можно получить constexpr инфу о типе.

      Конечно как всегда с кучей ебанутых ограничений и костылей. Но они почти придумали лисповые макросы 🙂
      Ответить
      • З.Ы. В принципе, для решения практических задач типа сериализации, mock'ов и т.п. этого вполне хватит.
        Ответить
      • > Конечно как всегда с кучей ебанутых ограничений и костылей. Но они почти придумали лисповые макросы 🙂

        Или я нихуя не понял, или это говно никакого (или почти никакого) отношения к лисповым макросам не имеет.

        Вот представим себе некий гомоиконный язык, в котором нет циклов for но есть ite и goto. И допустим у нас будет функция, которая считает сумму чисел от 1 до 10
        ( (funcname sum1_10 (int) (void) )
        
          (newvar a (type int))
          (newvar sum (type int))
          (:= a 1)
          (:= sum 0)
          (jmplabel loop)
            (:= sum (+ sum a))
            (:= a (+ a 1))
          (ite   // if - then - else
            (<= a 10) (goto loop)
            () //nothing, end loop
          )
          (ret sum)
        )

        Ну и если захотим, можно впилить в язык цикл for, который будет трансформироваться в конструкцию с этим условием с goto и присвоением, типа вот:
        ( (funcname sum1_10 (int) (void) )
        
          (newvar a (type int))
          (newvar sum (type int))
          (:= sum 0)
          (for (:= a 1) (<= a 10) (:= a (+ a 1))
            (:= sum (+ sum a))
          )
          (ret sum)
        )

        и всё это достаточно легко будет делаться, мы просто рассматриваем нашу программу как связный список связных списков, больше нихуя нет, мы просто пишем код (макрос), который при вставке в код for вот с такими-то аргументами трансформируется/раскрывается вот в такой-то код, для этого "for" мы просто пишем код, который конструирует на основе аргументов какой-то новый код через связные списки связных списков и ... и все. Это - ПРОСТО.
        Когда же я читаю про метаклассы то это вообще хуйня какая-то. Классы какие-то, зачем мне вообще классы? Вот представим на минуту, что из крестов выпилили нахер for(), while() циклы, но зато есть if() и goto label, через эти метаклассы можно запилить for()? Если нет, при чем тут тогда лисповые макросы?
        Ответить
        • http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0707r3.pdf

          > A metaclass is written as a compile-time constexpr function that takes meta::type parameters, which are passed with reference semantics
          ...
          > In the latter form, it can be used to use the values or abstract state of objects of meta::type.
          ...
          > A pure base_class is a class that has no instance data, is not copyable, and whose a destructor is either public and virtual or protected and nonvirtual. Unlike an interface, it can have nonpublic and nonvirtual functions.
          ...

          блядь, сколько хуйни на ровном месте. Какие-то pure base_class, какие-то методы, классы, хуяссы, констэкспры, meta::type. ЗАЧЕМ? ЗАЧЕМ ЭТО ВСЁ? Как это соотносится с лисповыми макросами?
          Ответить
          • Они дали возможность заменить тело constexpr блока на сгенерённую этим блоком хуйню. До нормальных макросов было рукой подать. Но они вместо этого начали городить какую-то хуйню с метаклассами 🙁

            З.Ы. Я одну из первых версий пропозала читал, возможно сейчас там всё поменялось.
            Ответить
            • ШОК! Запрещенные секретные приемы C++ метапрограммирования с шаблонами, макросами и констэкспрами. Дедовский способ. Смотреть до конца!!!
              Ответить
              • Ученые открыли способ добавить гомоиконы в C++. Нужно всего лишь...
                Ответить
              • "шаблонами, макросами и констэкспрами" не нужны когда есть метаклассы.

                Ванга видит книгу "паттерны проектирования метаклассов", "библиотеки для быстрой разработки метаклассов", "стандарт с++30 и шаблоны метаклассов"
                Ответить
                • Наверняка будут какие-то особые случаи, где без препроцессорного программирования или тупо нельзя будет обойтись или слишком много метаклассо-шаблонного говна надо будет писать, который еще хрен поймешь и который будет компилироваться хер знает сколько
                  Ответить
        • Пока кто-то мечтает об обстрактных гомоиконах, в S" Forth" из слов потока управления достаточно:
          ahead —– отмечает безусловный переход вперёд;
          if —– отмечает условный переход вперёд;
          then —– разрешает переход вперёд;
          begin —– отмечает переход назад;
          until —– разрешает условный переход назад;
          again —– разрешает безусловный переход назад;
          cs-pick и cs-roll для работы со стеком потока управления.
          Всё остальное можно реализовать поверх них:
          : else  ( C: orig1 -- orig2 )
              postpone ahead  ( С: orig1 orig2 )  \ отметили переход вперёд
              1 cs-roll       ( C: orig2 orig1 )  \ поменяли ссылки на стеке местами
              postpone then   ( C: orig2 )        \ разрешили ссылку вперёд, 
          ; immediate
          
          : while  ( C: dest -- orig dest )
              postpone if  ( C: dest orig )  \ отметили переход вперёд
              1 cs-roll    ( C: orig dest )  \ поменяли ссылки местами
          ; immediate
          
          : repeat  ( C: orig dest -- )
              postpone again  ( C: orig )  \ разрешили переход назад
              postpone then   ( C: )       \ разрешили переход вперёд
          ; immediate
          
          
          .( test if else then:) cr
          : .sign  ( n -- )
              dup 0<
              if
                ." negative"
              else
                dup 0=
                if
                  ." zero"
                else
                  ." positive"
                then
              then drop cr ;
          
          -42 .sign
          0 .sign
          100500 .sign
          cr
          
          .( test begin while repeat:) cr
          : .count  ( u -- )
              begin
                dup
              while
                dup .
                1-
              repeat
              drop ." done." cr ;
          
          5 .count
          1 .count
          0 .count
          https://ideone.com/00PGzJ
          Ответить
  • > без расширения конпелятора
    > требует стороннюю утилиту
    Мне одному кажется, что это и есть расширение конпелятора?
    Ответить
    • Ну как бы эта утилита компилятором не является. Типа как PHP добавить в кресты как препроцессор - сам компилятор от этого никак не расширяется
      Ответить
      • Препроцессор не понимает синтаксис крестов. А тут именно расширение языка через жопу.
        Ответить
        • На PHP (если постараться) можно написать парсер/лексер плюсов. А на сишном препроцессоре - нет. Поэтому я за PHP
          Ответить
  • >Author of Compile-Time-Regular-Expressions Librar
    >We really need an allocation mechanism in constexpr. But I don't need to return the allocated object outside of a constexpr function

    Панни Дусикова, я вас хочу
    попросить прикрутить к этому всему ГУИ чтобы компилятор еще показывал мультики пока компилирует
    я такую игру джва года жду
    Ответить
      • Тогда придётся чем-нибудь подкармливать компилятор, чтобы досмотреть мультик. Дописывать говно в авральном режиме!
        Ответить
  • >ишется специального вида функция (называемая «метаклассом»), которая в compile-time позволяет управлять процессом компиляции

    ахахах ебать
    я такое в груви видал 10 лет назад
    там на этом АОП делали

    Божечки, почему программисты стабильно изобретают колесо и текут от этого?
    Ответить
    • А можно сделать шаблоны для метаклассов?

      ну штоб проще было писать
      Ответить
    • Ахахах, в S" Forth" ещё в 71 году можно было управлять процессом конпеляции и интерпретации. Там на этом любую идею из любых других языков реализовать можно (кстати, одна из реализаций ООП S" Mini-OOF" занимает всего 14 строчек).

      Божечки, почему программисты стабильно изобретают колесо и текут от этого?
      Ответить
        • Проверил: костыль некачественный, конструкция ненадежная. Отправил назад на доработку. Проверь.
          Ответить
              • Рекурсионно поработал с петушиной щёкой за твоей щекой, проверь.
                Ответить
                • File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                    File "<stdin>", line 1, in work_behind_rooster_cheek
                  RuntimeError: maximum recursion depth exceeded
                  Ответить
  • > универсальный сериализатор структур, написанный с помощью hana:

    Тут проблема не в отсутствии гомоиконности, а в том, что только полному отморозку придёт в голову использовать в качестве схемы данных крестомакросню:

    – Как нам распарсить этот бинарный блоб, г-н Рахитектов?
    – Для начала чекаутни ревизию fd3fgsf4 нашего проекта и грепни на 'BOOST_HANA_DEFINE_STRUCT(Sosnoolee'

    Надо чтобы ASN.1!
    Ответить
    • В общем, ничего удивительного: глупые задачи приводят к глупым решениям.
      Ответить
  • Я угадаю автора по говнокоду
    Ответить

Добавить комментарий

Где здесь C++, guest?!

    А не использовать ли нам bbcode?


    8