1. C++ / Говнокод #27054

    0

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    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
    /* https://habr.com/ru/company/jugru/blog/524600/
    Давайте теперь поговорим о метаклассах, коль скоро ваш вопрос был в первую очередь о них.
    Для их реализации было необходимо три фундаментальных нововведения. Во-первых, программирование
    во время компиляции. На момент начала работы над метаклассами оно частично присутствовало в
    constexpr, но тогда оно было ещё сырое и не до конца обобщённое. Во-вторых, была необходима
    рефлексия, по которой тогда только-только появились первые предложения, и рассчитывать на неё
    было рискованно. В-третьих, нужна была генерация кода, создание исходного кода C++ во время
    компиляции — на тот момент в C++ этого ещё ни разу не делали.
    
    Но при наличии этих трёх предпосылок метаклассы становятся просто синтаксическим сахаром,
    который во время компиляции применяет функцию рефлексии и генерации кода. Поэтому в
    первоначальной статье по метаклассам (P0707) также написано об этих трёх вещах: рефлексии,
    полном программировании во время компиляции, то есть возможности выполнять любой код C++
    во время компиляции, и генерации кода C++; ничего этого на тот момент в языке не было.
    
    Самым важным шагом в этом направлении стало добавление программирования во время компиляции.
    Это значит, что вторая предпосылка метаклассов в C++20 почти закончена. Функции consteval
    с гарантированным выполнением во время компиляции на самом деле были предложены именно в
    статье, которую я только что упомянул. На основе моей статьи Эндрю Саттон (Andrew Sutton)
    сделал реализацию метаклассов в Clang, с помощью которой были написаны consteval и некоторые
    другие фичи C++20.
    
    В общем, с программированием во время компиляции дела обстоят хорошо. Что касается рефлексии,
    она входит в список семи приоритетов для C++23. Даже без учёта нарушений из-за COVID-19 я
    сомневаюсь, что рефлексию завершат к 2023 году, но ей точно будет уделяться много усилий.
    Это не может не радовать. Над генерацией сейчас тоже работают Дэвид Вандевурд и, опять-таки, Эндрю Саттон.
    
    Когда рефлексия, consteval и генерация станут частью стандарта, для добавления метаклассов
    будет достаточно заявки на пяти страницах, в которой мы просто поблагодарим за реализацию
    этих трёх предпосылок, и предложим добавить поверх них синтаксический сахар, который позволит
    во времени компиляции применять функцию к классу. В общем, в этой области сделано уже очень
    многое, но, как видите, это проект, требующий много лет для завершения. Мне пришлось разбить
    его на несколько более мелких заявок, чтобы вся работа не была забракована из-за одного
    неудачного сегмента. Несмотря на это, мы всегда учитывали конечную цель — метаклассы; и мы
    всегда ориентировались на определённый вариант использования.
    
    Легковесная обработка исключений — более новый проект, я впервые предложил её комитету в 2018 году.
    В отличие от метаклассов, на начальном этапе диалога прототипа ещё не было, и я хотел узнать, готов
    ли комитет вообще двигаться в этом направлении. С самого начала мы получили положительную реакцию,
    а также некоторые технические вопросы. В следующем году мы планируем начать работу над прототипом.
    Когда прототип будет готов и мы сможем ответить на эти технические вопросы, мы составим более подробную заявку.
    
    Наконец, нужно сказать ещё об одном проекте, обсуждение которого началось только в феврале этого года.
    Это было в Праге на встрече юзер-группы, её запись выложена на YouTube. Речь идёт о передаче параметров и
    инициализации. Здесь используется подмножество правил статического анализа, которые использовались для
    Lifetime. Я уже подготовил об этом статью (под номером 708), но прежде чем подать её комитету, мне необходимо
    будет создать прототип.
    */

    Почему это выглядит как вореции?

    Запостил: j123123, 24 Октября 2020

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

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

      > Любому другому конкуренту C++ нужно будет уделить совместимости значительно больше внимания, чем это делается сейчас. Я не говорю, что другой язык вообще не может занять место C++ без обратной совместимости, просто это будет значительно более долгий процесс.

      Между строк можно прочитать что-то типа "ну да C++ то еще говно, но ведь сколько кода на нем написано! Вы что, будете его весь переписывать???"
      Ответить
      • Надеяться, что какой-то язык сможет быть совместим с крестами, это как ожидать, что нигерийский принц пришлёт вам денег.
        Ответить
      • На самом деле, я всего одну либу могу вспомнить, которая хоть как-то взаимодействует с крестами без помощи со стороны крестов. Это биндинг Qt к питону, запиленный ценой неимоверной ёбли. А ведь Qt использует кресты довольно поверхностно и пытается держать стабильное ABI...

        В остальных случаях именно кресты мимикрируют под чужие интерфейсы - C, COM, JNI, PyObject, Lua и т.п.

        Совместимость же на уровне исходника - это вообще фентези какое-то, примерно как драконы и единороги.
        Ответить
    • > В общем, я хочу обратить ваше внимание на тот факт, что реализация прототипа уже в достаточной степени завершена и поэтому не требует много поддержки. Мы очень рады, что сообщество Clang заинтересовалось этой фичей, и благодарны за помощь тем, кто принимал предложения и запросы добавить эту фичу. Как я уже сказал, это реализация Clang; вместе с нашим продуктом также поставляется реализация от команды статического анализа Microsoft.

      Хочу обратить внимание, мы очень рады... тьфублядь. Что это за хуйня вообще? Точно как этот Гофман https://www.youtube.com/watch?v=ZngXFXKeYcU

      Теперь-то ясно, почему в стандарте крестоговна столько хуйни
      Ответить
      • Кроме того, я хочу пояснить, почему я считаю этот проект приоритетным. Это один из наиболее практичных проектов, потому что в нём нет места инженерным перипетиям, стилистическим конфликтам, большому числу неортодоксальных подходов. И я по возможности лично займусь им – я хочу как можно полнее прояснить для себя эту тему. Разумеется, проект будет не совсем таким, как раньше – он будет разделён на несколько отдельных проектов, среди которых будут те, которые я сам буду исследовать.

        Теперь, когда мы по очереди изложили свои мысли, перейдём к проекту. Мне хотелось бы, чтобы его сразу можно было смотреть на YouTube, и поэтому, если кто-то захочет добавить что- то от себя – пожалуйста. Что касается описанных обстоятельств, то они крайне важны. Я не первый год занимаюсь подобными проектами, и вы все знаете, что происходит при утечке информации. Поэтому мне кажется, что сейчас не время использовать этот метод. Это сделано специально, чтобы максимально обезопасить нас от разных негативных моментов. Есть люди, которые сейчас усиленно работают над этим проектом, но из-за технических сложностей они не смогут принять участия в его выполнении. Это, конечно, не снимает с них ответственности – эти ребята, безусловно, лучшие из лучших, и я хотел бы попросить у них прощения за то, что не даю им возможности сделать этот проект полностью реальным для остальных.

        #вореции #порфирьевич
        Ответить
    • > Давайте вспомним об одном из ключевых преимуществ C++: принципе нулевых накладных расходов, сформулированном Бьярне Страуструпом. Обратите внимание, что нулевые накладные расходы — это не то же самое, что нулевые издержки. Задача не в том, чтобы фича не занимала ресурсов вообще, а в том, чтобы нельзя было сделать всё то же самое более эффективно вручную, не пользуясь предлагаемой абстракцией.

      Насколько я знаю, на этот принцип давным-давно положен хер. Пример с корутинами (которые требуют хип) это неплохо показывает.
      Ответить
      • > Герб: В 2012 году в докладе на GoingNative я сравнивал размер стандартной библиотеки в C++, .NET и Java, и разница получилась в несколько порядков. Нам по-прежнему далеко в этом плане до этих языков. Так что я не думаю, что стоит переживать из-за чрезмерно большого размера стандартной библиотеки.
        >
        > Больше того, нам в неё хорошо бы ещё включить вещи вроде JSON и HTTP. Так что хотя в последнее время в неё добавляется много важных вещей, нам ещё есть куда расти

        Предлагаю еще включить XML, JS и PHP. Если серьезно, прежде чем включить HTTP, надо б для начала с сетью разобраться на разных платформах, а на конец 2020 года еще нихуя нет
        Ответить
      • >Я не думаю, что нам стоит наращивать стандартную библиотеку до размеров Java или .NET. Сейчас они сожалеют о том, что так раздули свои стандартные библиотеки, поскольку это требует дополнительных ресурсов и усложняет обучение языку.

        Именно поэтому я за Си.

        > И всё же наша библиотека ещё слишком маленькая.

        Для микроконтроллеров - нет.
        Ответить
        • Стандартную библиотеку надо пилить на части.
          Ответить
        • > Для микроконтроллеров - нет.

          Ну вот кстати да. В неё изначально натащили всякого говна про stdin и stdout, которое приходится выбрасывать целиком, вместе с полезными частями крестовой либы.

          А поддержка сети, json или функции бесселя тебе на контроллерах никак бы не помешали, они рантайм не раздувают если их не юзать. В отличие от std::cin.
          Ответить
          • Как много фич крестов отвалится, если у меня нет ни хипа, ни исключений?
            Ответить
            • Почти вся стандартная либа, лол. Кроме хедеров со всякой метушнёй ну и read-only алгоритмов.

              Плюс без рантайма ты потеряешь нетривиальные конструкторы у глобалок. И с этим придётся смириться либо самому эту механику восстанавливать.
              Ответить
              • Если сделать в крестовой функции нетривиальный инициализатор (или как эта хуйня называется, ну если вызывать функцию с сайд-эффектами) у статической переменной, компилятор нагенерит там какой-то питушни с мьютексами __cxa_guard_acquire, __cxa_guard_release - см. https://godbolt.org/z/Whdf7s пример (очевидно, чтоб два потока не влезли одновременно в такую-то функцию и не натворили хуйни). Почему не сделать особую опцию для компилятора типа "--у_меня_однопоточная_хуйня" чтоб такой питушни не происходило?

                Вообще, эта хуйня еще нужна для избежания рекурсивной инициализации, подробности тут https://manishearth.github.io/blog/2015/06/26/adventures-in-systems-programming-c-plus-plus-local-statics/ - но и для этого можно добавить опцию "--тут_нет_рекурсивной_инициализации" чтоб компилятор хуйни не генерил (еще компилятор теоретически может попробовать доказать, что рекурсивной инициализации в каком-то конкретном случае происходить не может в принципе, но компиляторы для этого видимо слишком тупые).
                Ответить
                • > какой-то питушни с мьютексами

                  -fno-threadsafe-statics разве не помогает?
                  Ответить
                  • someshit(unsigned char):
                            cmp     BYTE PTR guard variable for someshit(unsigned char)::b[rip], 0
                            movzx   eax, BYTE PTR someshit(unsigned char)::b[rip]
                            jne     .L5
                            movzx   eax, BYTE PTR huita()::a[rip]
                            mov     BYTE PTR guard variable for someshit(unsigned char)::b[rip], 1
                            add     eax, 1
                            mov     BYTE PTR huita()::a[rip], al
                    .L5:
                            add     eax, edi
                            mov     BYTE PTR someshit(unsigned char)::b[rip], al
                            ret

                    Не, всё равно какие-то гуарды вставляет. Хочу чтоб вообще без всей этой хуйни.
                    Ответить
                    • Дык на сишке у тебя тоже были бы эти гуарды! Только ты бы руками написал этот сраный флажок, который показывает что у тебя init() уже пройден.
                      Ответить
                      • На сишке я мог бы доказать, что такая-то функция вызовется вот в таком-то месте первый раз, а потом вызывать функцию без хуйни, которая проверяет, а не вызывал ли я ранее эту функцию. Например, так:

                        #include <inttypes.h>
                        
                        uint8_t glob_a = 255;
                        
                        uint8_t huita(void)
                        {
                          glob_a++;
                          return glob_a;
                        }
                        
                        uint8_t glob_b;
                        
                        uint8_t someshit_first_call(uint8_t a)
                        {
                          glob_b = huita();
                          glob_b += a;
                          return glob_b;
                        }
                        
                        uint8_t someshit(uint8_t a)
                        {
                          glob_b += a;
                          return glob_b;
                        }


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

                        Пример: https://godbolt.org/z/b9GbTx
                        Будь компилятор умнее, он бы мог сделать функцию, в которой проверка не производится. Хотя если компилятору разрешить ту функцию инлайнить, проверка этого гуарда была б только один раз, хоть что-то положитльное
                        Ответить
                        • > вызовется вот в таком-то месте первый раз

                          Ты можешь сделать глобальный инстанс класса и позвать у него init() явно (ну или таки восстановить механику глобальных конструкторов, она простая), а потом без всяких проверок звать остальные методы, которые юзают его поля.
                          Ответить
                        • Притом если компилятор будет инлайнить и флага -fno-threadsafe-statics не будет, он туда позаинлайнивает эту хуйню с __cxa_guard_acquire __cxa_guard_release несколько раз. Какой багор))) Какие нулевые издержки)))
                          Ответить
                        • > Будь компилятор умнее, он бы мог сделать функцию, в которой проверка не производится.
                          Как ты себе это представляешь?
                          Ответить
                          • А в чем проблема? Ну если у нас есть знания о том, что та функция вызывается раньше всех, а потом из той функции та, а та из той, мы можем построить некий граф достижимостей таких-то вызовов таких-то функций. И если нам известно (если мы можем доказать), что вот в таких-то местах такая-то функция будет вызываться точно не в первый раз, то в тех местах мы вызываем ту версию функции, в которой проверка гуардов (а не надо ли нам проинициализировать статическую переменную в первый раз?) не производится.
                            Ответить
                            • Графы достижимости функций - это уже к линкеру и линк-тайм оптимизациям.
                              Ответить
                              • Такое и в пределах одной единицы трансляции можно замутить, если функции статические и на них наружу указатели не пробрасываются.
                                Ответить
                                • Тратить N человеколет на разработку весьма сложной оптимизации, которая будет работать только для статических функций из единиц трансляции, сконьпелированных с «-fno-threadsafe-statics»* и при этом экономить ровно джве инструкции на каждый вызов?

                                  * И в которых есть статические пельменные, конечно.
                                  Ответить
                                  • Ты нихуя не понимаешь. Это очередной олень, который обосрался с выбором контроллера, не захотев переплатить 6 центов за модель с чуть большим объемом памяти. А так как на партии 30 штук это уже пиздец как выгодно, ему теперь надо решить, как сэкономить 2 инструкции.

                                    У меня тоже однажды был партнёр один, который "бля я только юдипи могу, стек тисипи не влезет". Хотя даже если бы сук на 1к рублей у него косты бы выросли (а не 6 центов) и он бы въебал девайс с поддержкой 4ГБ рам, а не хуйней на 8 килобайтов!, это было бы нормально. Обходите стороной таких мудаков, это не лечится
                                    Ответить
                                    • Простите за резкость, пригорело. Полгода делает фичу на 50 строк кода.

                                      Свой особенный мирок. Ходить в трусах на размер меньше, чем надо, и хвалиться об этом.
                                      Ответить
                                    • > У меня тоже однажды был партнёр один, который "бля я только юдипи могу, стек тисипи не влезет"

                                      UDP хватит всем.
                                      Ответить
                                  • Так-то вообще проблему можно радикально решить на фон-неймановских архитектурах, и даже без «-fno-threadsafe-statics» будет норм. Сначала функция будет со специальной хуйней типа мьютекса (крит. секции) и влезть туда может только один поток. Этот поток инициализирует переменную, а потом меняет временно права на сегмент с исполняемым кодом, и пропатчивает его нахуй, при этом убирает к херам критическую секцию и какие-либо проверки, вызывали ли мы хуйню первый или не первый раз. Ну и все прочие треды, которые уже успели влезть в ту функцию и уперлись лбом в крит. секцию - их надо как-то выпиздовать чтоб начали с самого начала функцию исполнять. Какими-то низкоуровневыми хаками это всё решается
                                    Ответить
                                    • > Какими-то низкоуровневыми хаками это всё решается

                                      Что только люди не делают, чтобы не юзать класс вместо функции.
                                      Ответить
                                    • Если уж извращаться, то лучше так - конпелятор втыкает в начало функции jmp на специальный кусок кода, который содержит критическую секцию, один из тредов заходит в неё, проводит инициализацию, заменяет jmp на реальный код и отпускает лочку.

                                      Только запатчить jmp надо очень аккуратно и атомарно. Чтобы другие треды либо успели его запрефетчить и ушли на лочку или уже увидели нормальный код.
                                      Ответить
                                      • А зачем jmp на специальный кусок, если специальный код с лочкой можно сразу в самой функции разместить, и потом тот код просто сам себя перезатрет? А то вот джампы всякие, неоптимально это. К тому же код для переписывания jmp будет потом в памяти зря валяться без дела. В общем, недостаточно оптимально.
                                        Ответить
                                        • > недостаточно оптимально

                                          Зато работать будет, в отличие от. Тем более этот кусок может быть один на все такие функции если заюзать call вместо jmp.

                                          > сам себя перезатрет

                                          Чем он блядь себя перезатрёт? Где он возьмёт инфу для этого? Из сети? С диска?
                                          Ответить
                                          • >Чем он блядь себя перезатрёт? Где он возьмёт инфу для этого? Из сети?

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

                                            Хотя конечно ясен хрен, что всё это крохоборство нахуй никому не всралось.
                                            Ответить
                                            • > на место себя

                                              Это вообще тухлая идея, имхо. Почему я пытался всего одну инструкцию затирать - jmp, call и т.п.? А потому что во время самомудификации у тебя соседние ядра в конвейер/кеш затянут половину старого кода, а потом внезапно продолжат исполнять новый. И кровь-кишки.

                                              С одной инструкцией это вроде бы должно прокатить т.к. ядро либо увидит jmp и съебёт из опасной зоны либо уже увидит новый код. Ну и разумеется этот jmp не должен пересекать границы кешлайна и должен быть перезаписан атомарно.
                                              Ответить
                                              • У 8088 нет никаких опасных зон. Именно поэтому я за «8088».
                                                Ответить
                                                • показать все, что скрытоvanished
                                                  Ответить
                                                  • > всегда стоило одинаково

                                                    Ага, таблички с таймингами команд ещё имели смысл, как сейчас на AVR.
                                                    Ответить
                                                    • показать все, что скрытоvanished
                                                      Ответить
                                                      • > высокоуровневую микрокодовую пиштуню

                                                        Ну на AVR и ARM Cortex более-менее честная низкоуровневая питушня. Хоть и слегка запайплайненная. И такты описаны, можешь считать.
                                                        Ответить
                                                        • показать все, что скрытоvanished
                                                          Ответить
                                                          • А то!

                                                            Хоть какое-то чувство контроля над железом. Ну и там нету недокументированной хуйни в духе ME.
                                                            Ответить
                                                            • А у меня вот что-то не стоит ни на что, кроме PC. А PC уже превратился во многом в платформу для запуска джаваскрипта.
                                                              Хоть строй машину времени, и лети в 1989-й год..
                                                              Ответить
                                                        • Ты кстати пробовал уже RISC-V?
                                                          Ответить
                                                          • Не, я из софткора только nios юзал.
                                                            Ответить
                                                            • Можешь аппаратный RISC-V купить, например Longan Nano какую-нибудь. GD32VF103 попиново совместим с STM32F103
                                                              Ответить
                                        • > код просто сам себя перезатрет
                                          А где в это время будет rip?
                                          Ответить
                                          • > А где в это время будет rip?
                                            Можно сделать исполняемый стек, в него насрать опкодами и выполнять их оттуда.
                                            Ответить
                                            • Ну если не нравится jmp - можно въебать брейкпоинт. Обработчик по табличке посмотрит что за функция, позовёт инициализацию и запатчит бряк на правильный байт. Обработчик один на всех, так что оверхеда считай нет. Ну и он в "холодной" памяти - когда все инициализации прошли, на пирфоманс никак не влияет.
                                              Ответить
                            • Начнём с того, что всё это будет работать исключительно до тех пор, пока включён флаг «-fno-threadsafe-statics» — то есть эта «оптимизация» джвух инструкций будет нужна трём поехавшим.

                              > мы можем построить некий граф достижимостей таких-то вызовов таких-то функций
                              Для примеров в пятнадцать строчек — да, можем. Для любых бульмень реальных проектов — уже нет.
                              Ответить
    • > Почему это выглядит как вореции?

      Многабукав. Автоматически вореции.
      Ответить
      • Тут дело не в "многабукв" а в каком-то ебаном синтаксическом мусоре. Вот всякое там "прежде всего хотелось бы", "в общем, давайте вспомним о..." и прочая подобная херня. Хотя для стандартизаторов такого ублюдского языка, ничего удивительного в этом нет. Краткость и читаемость никогда не была сильной стороной крестов.
        Какая профдеформация )))
        Ответить
        • Быть может, это просто ты настолько тупой и не начитанный?
          Ответить

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