- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
// https://habr.com/ru/post/550442/
// Как компилятор C++ находит правильную функцию
// Вот так компилятор точно определяет, какую функцию следует вызвать:
// https://hsto.org/webt/mp/tb/5k/mptb5kheibrreqspserc4sfdfrs.png
// Эти шаги закреплены в стандарте C++. Каждый компилятор C++ должен следовать им,
// и все это происходит во время компиляции для каждого вызова функции. Оглядываясь
// назад, это очевидно, что должен быть такой алгоритм. Это единственный способ, которым
// C++ может поддерживать все вышеупомянутые возможности одновременно. Это то, что вы
// получите, если необходимо объединить их вместе.
// Я предполагаю, что общая цель алгоритма — «делать то, что ожидает программист»,
// и до некоторой степени он в этом преуспевает. Вы можете довольно далеко зайти,
// полностью игнорируя этот алгоритм. Но когда вы начинаете использовать все возможности
// C++, как при разработке библиотеки, то лучше знать эти правила.
Да, это конечно очень круто, только вот существует примерно 0 компиляторов, которые полностью корректно (т.е. в полном соответствии с Говностандартом) реализуют эту срань с вызовом правильной функции/метода с учетом всей хуйни.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51577 - этот баг висит еще 2011-12-16 и его так никто нихуя не пофиксил
И в Clang такого рода баги тоже есть.
какая безысходность )))
но кому нужен чупакабр?
на sohabr?
или как там называется куда сохраняют всё, что пидораший Мой Мир удаляет?
знаю только, что политика удалять интересные статьи чтобы не обидеть коллективного Усманова появилась за этот период
> Поиск имени по методам (Member name lookup) происходит, когда имя находится справа от токена . или ->, как в foo->bar. Этот тип поиска используется для поиска методов класса.
> Поиск квалифицированного имени (Qualified name lookup) происходит, когда имя содержит токен ::, например, std::sort. Этот тип имени является явным для компилятора. Часть справа от токена :: ищется только в области видимости, обозначенной в левой части.
> Поиск неквалифицированных имён (Unqualified name lookup) не является ни тем, ни другим. Когда компилятор видит неквалифицированное имя, например blast, он ищет совпадающие декларации функций в множестве различных областей в зависимости от контекста. Существует подробный набор правил, который точно определяет, где должен искать компилятор.
Квалифицированные-хуифицированные, понаприрумывали херни всякой. А почему они не сделали какой-нибудь метушни над AST (и чтоб с гомоиконностью), которая б уже использовалась для написания логики для подобного говна? Почему им проще захардкодить набор каких-то ебанутых правил, которые все равно никто нихера не знает, и даже в компиляторах их реализовывать не осиливают?
Может там им еще сделать чтобы функциям начислялись некие баллы жизнеспособности по некоторым ебанутым говноправилам, и чтоб выигрывала та функция, которая больше баллов набрала?
Лучше заставить их драться в рантайме! Какая пройдёт юнит-тесты и покажет больший пирфоманс -- та и более жизнеспособна.
Пускай компилятор сам угадывает что я имел ввиду
Зачем заставлять меня думать?!
Джве жизнеспособные функции находятся в центре кода 500х500 строчек, на расстоянии 20 строчек друг от друга. Но поскольку их джве...
А надежды у меня такой нет. Стирать память ради осиливания помойных крестов (если б существовала такая технология) я не желаю.
https://web.archive.org/web/20160320101324/http://www.sql.ru/forum/466654-7/s
> А вот знать C++ обязан каждый. Знать хотя бы для того, чтобы понимать, как делать нельзя. C++ - это идеальная коллекция антипаттернов в дизайне языков программирования.
Каждый раз, когда конкатенирую строки через плюсик или когда реверсирую вектор через std::reverse завидую сишникам
Бля, т.е. задачи с собеседований не бесполезны?! Зачем тебе это понадобилось, если не секрет?
Не, это хуета, вот в питоне ты можешь даже умножать строки на число:
разве не охуенно? Шах и мат, крестовики.
Кстати, ни в крестах, ни в питоне нельзя добавлять новые операторы. А в Haskell можно. Там даже можно указывать приоритет и ассоциативность: https://webhamster.ru/mytetrashare/index/mtb339/15559617440umt1hd5us
https://bugfactory.io/blog/custom-infix-operators-in-haskell/
Кресты и питон - говно!
Скукотища. Вон в coq можно объявить себе какое-нибудь s1 =[ cmd ]=> s2.
Правда Coq'у он всё равно, наверное, в этом плане уступает.
https://play.nim-lang.org/#ix=3ojq
Оно, конечно, не совсем универсально. Грамматику крестов не запилить, я думаю.
Если без шуток, то для скриптушни текстообрабатывающей это вполне нормальное желание
Вот нахуя есть какой-то https://en.cppreference.com/w/cpp/string/basic_string и какой-то https://en.cppreference.com/w/cpp/string/basic_string_view ? Почему это не какой-то там контейнер, типа std::array или std::vector? Зачем под это какая-то особая сущность? Почему хуйня для строк не является обычным контейнером?
Потому что она и должна являться особой сущностью? Или ты хочешь в обычный контейнер добавить методы для работы с символами (всякие там capitalize()/upper() и ня) и поддержку UTF8?
Другое дело, конячно, что в крестовых "строках" всего этого нят: чтобы понять, зачем нужен отдельный тип для строк, лучше посмотреть ня какой-нибудь Python.
Я хочу просто контейнер для байтиков (ну или кодепоинтов), с которым уже работают какие-то алгоритмы.
Вектор тут вполне норм если забить на совместимость с няшной.
std::getline vs istream::getline
А оно нинужно... Потому что из-за юникода понятие индекса жутко расплылось и всё равно придётся юзать итераторы с нужной сёмантикой как в icu.
В современных языках (включая перл, лол) есть понятие "символ", коий связан с кодпоинтом, и не зависит от кодировки.
из таких символов можно составлять строки.
А std::string ведь по сути и есть вектор чаров, только он знает про null в конце и умеет c_str генерить. Ну и наверное имеет всякие коснтрукторы типа иплисит из строкового литерала... или вектор тоже может?
У вектора нят перегрузок под литералы, но это можня легко исправить каким-нябудь "#define LITERAL_ITERATOR(x) std::begin(x), std::end(x) -> std::vector(LITERAL_ITERATOR("hello"))". Так, правда, нулевой символ в размер входить таки будет.
--чем отличается data и c_str
--тем, что у одного нул в конце
лол)
раньше data() возвращала массив чаров (ну или что там в строке) а после него был UB. А теперь там не UB, а гарантированно NULL?
З.Ы. Емнип, там с пустой строкой основная жопа была, на ней таки можно было соснуть UB'ца.
В порядке бреда — держать второй указатель ня нуль-терминированную строку и обновлять его ня каждом вызове c_str().
В порядке бреда можно и прокси-прокладку вернуть из c_str(), которая кастуется в const char* и держит временную нуль-терминированную копию...
А ну да, оно же должно жить до следующей модификации, а не до конца стейтмента...
Ну, в порядке бреда можно GC добавить.
Знаете анекдот про c_str кстати?
Было например так
Потом пришел мамки экстрактор, и сделал так
Так мы познакомились с понятием "временный объект, живующий до конца полного выражения", лол
foo(rand());
bar(rand());
писать
baz = rand();
foo(baz);
bar(baz);
прикол в том, что это не синтетика, встречал такое, когда функция с сайд эффектами действительно вынуждает дублировать код, а всё завёрнуто глубоко, и сначала не понимаешь, какого хуя перестало работать после рефакторинга.
В сишке и крестах есть еще такая проблема у различных джавушков, привыкших к тому, что экстрактить можно что угодно (либо ссылка скопируется, что нестрашно, либо примитив типа int, что тоже не страшно)
И пусть функции всегда pure, а процедуры всегда const, если явно не помечены как "non_const"
Вот и кеширование станет удобно делать: пока non_const не вызвал, результатат всех функций предсказуем))
В крестах хотя-бы есть const методы, которые как-бы официально обещают не менять состояние объекта (хотя могут наебать, конечно)
В остальном мейнстриме и такого нет
А потом придёт папкин новатор, скажет, что std::string_view — стильня и модня, и сделает:
Кстати, std::string_view — ня самом деле очень хорошая штука; пример того, как забили ня совместимость с сишкой и получили удобную и полезную вещь. А вот если бы попытались сохранить — получилось бы говно.
можно было сделать еще так
За одно познакомиться с понятием "живительная константная ссылка, продлевающая жизнь временному объекту"
или так
но тут наверное может случиться лишнее копирование
string_view это же просто "окошко" в настоящую строку, как бы ссылка на какой-то рендж внутри нее?
Продлевание жизни — это чрезвычайня опасная и хрупкая конструкция, някому ня рекомендую (см. https://abseil.io/tips/107).
> std::string s(std::string("hello") + std::string("world"));
В современных крестах это оптимальное* решение, лишних копирований ня будет.
*По соотношению "эффективнясть/(читаемость*простота*краткость)". Эффективнее будет взять std::ostringstream, и чем больше строк складывается — тем эффективнее.
> string_view это же просто "окошко" в настоящую строку, как бы ссылка на какой-то рендж внутри нее?
Да. Это указатель + размер.
Да, говно) Но справедливости ради, кое-что там тупо не скомпилируется (если const убрать например). Бьёрне явно запретил иметь модифицируемую ссылку на "неведомая временная хуита".
>В современных крестах это оптимальное
ну если компилятор доумкает не делать тут копирования, то вообще отлично
>std::ostringstream
да, но вдеь это не п олучится в одну строку
Кстати, чем это лучше string с ".append" ?
А где тут копирование? После плюса получается временный std::string, он попадает в std::string::string(std::string &&) и спокойня мувается. Вот лишние временные строки создаются, но точня так же, как и в оригиняле.
> Кстати, чем это лучше string с ".append" ?
Только внешним видом (куча << может выглядеть лучше кучи append()).
А по производительнясти оно сосёт: std::ostringstream::str() копирует итоговую строку. Говнодизайн стримов, да.
Кстати, отгадай без доки: как очистить стрим s из твоего примера, чтобы в нём ня осталось строки и можня было записывать новую?
точно) я не сообразил, что конструктор вызовется не копирующий, а мувающий, ведь объект-то временный, и больше не нужен.
В рамках этого конструктора string просто заберет себе чужой массив чаров скорее всего
>std::ostringstream::str() копирует итоговую строку
Это совершенно ожидаемо, иначе я бы написал str().append("хуй") и что было бы в стриме?
Вот кстати почему нету обертки для R/O строк?
Было бы удобно возвращать ей.. ну как такой R/O string_view
>как очистить стрим s из твоего примера,
А там нету чего-нить типа clear(), по аналогии со строкой?
Ты про стрим? В C++20 там сделали view(), да.
> А там нету чего-нить типа clear(), по аналогии со строкой?
clear() есть. Только он ня поможет ( ̄▽ ̄).
Да. На кой чорт он возвращает мне string без "const" ??
В const авось и append бы не было?
>clear() есть. Только он ня поможет ( ̄▽ ̄).
блядь
clear сбрасывает флаги состояния стрима.
А чтобы очистить стрим нужно... вызвать stringstream::str("") ?!
То есть str() без аргументов копирует строку, а с аргументами заменяет буфер новой строкой?!
Оно бы ня помогло. Строка же владеет указателем ня байтики, копировать всё равно придётся.
А вот std::string_view — как раз самое то.
> То есть str() без аргументов копирует строку, а с аргументами заменяет буфер новой строкой?!
Так точня ( ̄▽ ̄)ゞ!
Д — дизайн.
ну хотя бы у меня не было бы соблазна сделать append..
>Д — дизайн.
Я начинаю понимать, почему вы ругаете кресты)
Но я и в коде на других языках постоянно вижу говно в дизайне.
Например есть две реализации абстракций, одна из которых не работает в половине случаев.
Или есть метод, про который половина пользователей думает, что он выполняется на одном конкретном потоке, а другая -- что на любом.
А автор метода вообще не думал про такие вещи.
В крестах хотяб есть cppreference или https://www.cplusplus.com/ (который кстати для менее скилловых питухов даже удобнее, бо там всё разжевано)
А в коде нашего проекта документации может не быть вообще. "Надо просто подебажить", -- говорят коллеги
Это в копилку к erase, remove и empty.
Ого, не знал. Это не шутка?
В "PHP" так лучше не делать.
В "С++" так тоже лучше не делать. Там надо очень внимательно смотреть, что именно оно продлевает. Шаг влево и UB. Где-то тут кажется уже постили примеры.
Это появилось когда еще не было ни умных компиляторов, ни мувов.
Потому для примера выше реально было бы ненужное копирование.
Чтобы его избежать, стало можно иметь ссылку на временный объект.
Но если разрешить программисту изменять временный объект, то это будет совсем уже говнище, потому сделали такой костыль, чтобы его прочитать его на соседней строчке.
Вот опять-таки строки. Предположим, сделаю я особые царские строки без нуль-терминированной питушни. ну типа
И допустим будет у меня некая хуйня, типа new_uint8_vec(size_t len, uint8_t *data) которая делает новый вектор. И есть у меня функция конкатенации двух векторов, возвращающая третий и убирающей оригиналы
И если я потом воспользуюсь такой хуйней таким вот образом
То тут будет неоптимальная питушня, потому что будет новое выделение памяти на хипе, хотя тут можно было бы realloc()-нуть vec1 до размера a->len+b->len+sizeof(size_t) и туда докопировать хуйни из vec2. А в крестах я как-нибудь могу сделать такую хитрую питушню, чтобы если я делаю vec1 = vec_uint8_cat(vec1,vec2) то чтобы вызывалась такая вот особая функция, которая расширяет vec1 под нужные размеры, а не вызывает тупо vec_uint8_cat?
Ну так замени у себя в vec_uint8_cat() malloc ня realloc первого вектора. В чём проблема?
А что насчет такого типа оптимизаций http://www.ciselant.de/projects/gcc_printf/gcc_printf.html ?
Крестами такие оптимизации реализовать уже можно?
> Крестами такие оптимизации реализовать уже можно?
Конячня. Даже более того, крестами можня статически проверять формат и ня нарываться ня стандартные сишкобаги с перепутанными спецификаторами.
https://github.com/fmtlib/fmt
Хочу чтобы если у меня
то компилятор бы проанализировал строчку (точнее, AST)
И такой подумал бы "тааак, у нас тут такой-то паттерн, что мы vec1 и vec2 конкатенируем и присваиваем в vec1, ага, значит вместо "vec1 = vec_uint8_cat(vec1,vec2);" можно втулить vec_uint8_append(vec1,vec2), ведь у меня тут записано специальное правило, что если %a = vec_uint8_cat(%a,%b) то его можно заменить на vec_uint8_append(%a,%b), что я и делаю"
Зачем тут какие-то "методы"?
Нят, оптимизации, это, конячно, хорошо, но зачем такому компилятору программист?
Например, программист может ма-те-ма-тически описать свойство этого вектора, что это моноид, что вот такие-то операции можно упростить, сократив число аллокаций на хипе
Крестам до такого уровня абстракции как до Юпитера раком
Это имення то, что тебе нужня получить: вторая строка вызывает новую аллокацию, третья — реаллочит s1. Что ня так?
> Крестам до такого уровня абстракции как до Юпитера раком
Это правда. Ня крестах же программируют, а ня упражняются в эзотерике (ну, по большей части).
> Я не хочу явно ничего описывать, пусть оно там по каким-то правилам понимает
А я ня хочу код писать, хочу, чтобы мне просто деньги платили. И что?
А это тут к чему? Я указываю на отсутствие в крестах нормальных высокоуровневых фич, доказывая тезис "кресты - результат кривого подкостыливания сишки, который радикально ничего не меняет."
Шаблоны — это нярмальная высокоуровневая фича, радикальня отличающая кресты от сишки.
Нет, шаблоны это не нормальная высокоуровневая фича. Шаблонами нельзя прочитать AST функции и что-то там хитрое на основе этого сделать. Да и вообще, шаблоны задумывались не как хреновина для нормального метапрограммирования, а как достаточно узкая хрень, типа нагенерить функций add() для интов, флоатов, даблов и проч, но какого-то хрена (хотя ясно какого, больше ж не было ничего) их начали юзать для более сложных вещей, придумали какие-то SFINAE, рефлексию на говне и палках... тьфу. Это не нормальная высокоуровневая фича, это какая-то долбанутая срань, взяли какую-то хрень, для нормального метапрограммирования не предназначенную и начали писать какую-то невменяемую по своим масштабам шаблоносрань вперемешку с препроцессором и отдельными хаками для отдельных компиляторов (т.к. в одном компиляторе не работает вот эта часть говностандарта, вот в этом не работает та часть и так далее)
> C++ не предназначался для метапрограммирования шаблонов, но с тех пор, как технология TMP была открыта в начале 90-х годов, она оказалась настолько полезной, что, вероятно, и в сам язык, и в стандартную библиотеку будут включены расширения, облегчающие работу с TMP. Да, TMP было именно открыто, а не придумано. Средства, лежащие в основе TMP, появились в C++ вместе с шаблонами. Нужно было только, чтобы кто-то заметил, как они могут быть использованы изобретательным и неожиданным образом.
Вот только точня такой же риторикой можня "аргументировання" объявить плохим абсолютня что угодня. Ня сишке няльзя сделать свитч по строкам — сишка говно. Ня Хаскелле няльзя сделать мутабельные объекты без "костылей" с монядами — Хаскелль говно. Ня микроконтроллерах няльзя запустить Хром с сотней вкладок "Ютуба" — микроконтроллеры говно. И так далее.
Обсирать что-то правильня и по делу — сложно.
Да. Надо чтоб была метасишка с гомоиконами, где можно было б сделать свитч по строкам. Метасишка, расширяемая через особые DSL/EDSL
> Ня Хаскелле няльзя сделать мутабельные объекты без "костылей" с монядами — Хаскелль говно.
Да. Хаскель к тому же имеет жирный рантайм с GC - однозначно говно.
> Ня микроконтроллерах няльзя запустить Хром с сотней вкладок "Ютуба" — микроконтроллеры говно.
Нет, скорее тут Хром и "Ютуб" говно. Ну и обычные микроконтроллеры под такие тяжеловесные задачи не приспособлены. Можно сделать на заводе жирный контроллер со встроенными аппаратными декодерами, который Хром с сотней вкладок "Ютуба" вполне потянет.
Имення. Если X ня приспособлен под Y, то единственное, что можня сказать об X — то, что он ня приспособлен под Y.
Поэтому то, что шаблоны ня умеют обрабатывать AST, ня делает шаблоны говном. Это делает их ня умеющими обрабатывать AST.
Ну хорошо, допустим. А что должно быть не так с шаблонами, что делало бы их однозначно говном? Или говна вообще нет ни в чем?
Няумение играть ня скрипке ня может сделать из Васи плохого программиста. Плохим программистом Вася будет только тогда, когда он ня умеет программировать.
Вот, няпример, std::string — это однознячное говно, потому что это нечто вообще ня обладает методами, специфичными для строки. Оно ня умеет в Юникод, в нём нят всяких сахаров вида endswith()/startswith()/split()/join(), в нём нят методов для работы с капитализацией — это то, что мне реальня потребовалось в последние пару месяцев, и что мне пришлось велосипедить самой (кроме юникода).
А вот шаблоны свою задачу — няписание обобщённого кода — выполняют достаточня хорошо. То, что всякие сумасшедшие ня них пишут интерпретаторы брейнфака и страдают — проблема исключительня сумасшедших.
Нет. Недостаточно хорошо. Умение читать/писать AST в компилтайме имеет к возможностям написания обобщенного кода достаточно большое отношение, в шаблонах такой фичи нет. Так что на мой скромный взгляд, шаблоны - говно.
Если есть доступ к AST, у тебя автоматически есть и рефлексия/интроспекция. Какой смысл делать рефлексию/интроспекцию, но при этом без доступа к AST?
> В реальности как раз доступ к AST мне ня был нужен ни разу, в отличие от.
Если тебе конкретно не нужен, это не значит что не нужен вообще. Если есть некая библиотека для бигинтов, и есть код с этими бигинтами, и его можно через бином Ньютона заоптимизировать, то как это решаемо без доступа к AST?
Вот допустим по биному Ньютона можно получить, что (a+b)^3 = a^3 + 3*a^2*b + 3*a*b^2 + b^3
Где-то встречается код x = a^3 + 3*a^2*b + 3*a*b^2 + b^3
Я хочу чтоб заоптимизировалось в компилтайме в x = (a+b)^3
Как это решить без доступа в AST и возможности его перестраивать по месту?
Какой смысл использовать переусложнённый инструмент для решения простой задачи? Ты AST структур будешь ручками парсить, вместо простого "getFields<struct X>"?
> Если тебе конкретно не нужен, это не значит что не нужен вообще.
Нят, это знячит, что он ня нужен среднестатистической программистке ня крестах.
> Вот допустим по биному Ньютона можно получить
И дальше пошли абсолютно синтетические задачи, как обычня.
> Как это решить без доступа в AST и возможности его перестраивать по месту?
Профилируешь, видишь, что тут боттлнек, переписываешь формулу.
Возьми сложную математическую либу с кучей формул и сложных вычислений. Такие либы вполне себе существуют. К ним вполне могут быть применимы такие оптимизации.
> Профилируешь, видишь, что тут боттлнек, переписываешь формулу.
А если наиболее оптимальный с т.з. вычислений вариант окажется абсолютно нечитаемым, и по заоптимизированной формуле будет абсолютно неясен ее смысл? А если формула эта не одна, и переписывать их руками самым оптимальным образом - задача крайне сложная для человека?
А если этот боттлнек не в каком-то месте с какой-то формулой, а равномерно размазан по куче таких формул? Или так не бывает?
> А если наиболее оптимальный с т.з. вычислений вариант окажется абсолютно нечитаемым, и по заоптимизированной формуле будет абсолютно неясен ее смысл?
По любой формуле длиннее трёх символов абсолютня ня ясен её смысл, если она ня вынесена в метод с понятным именем.
> А если формула эта не одна, и переписывать их руками самым оптимальным образом - задача крайне сложная для человека?
Для этого существуют специализированные математические пакеты. Ты в своей волшебной либе бигинтов будешь реализовывать всю Wolfram Mathematica?
> А если этот боттлнек не в каком-то месте с какой-то формулой, а равномерно размазан по куче таких формул?
Тогда тебе нужня вбить их все в специализированный математический пакет.
Можно справляться лучше.
> По любой формуле длиннее трёх символов абсолютня ня ясен её смысл, если она ня вынесена в метод с понятным именем.
Смотря кому. Ма-те-матику может быть и понятно всё.
> Для этого существуют специализированные математические пакеты. Ты в своей волшебной либе бигинтов будешь реализовывать всю Wolfram Mathematica?
А эти специализированные математические пакеты точно заточены на выполнение таких трансформаций, чтобы для пирфоманса было лучше всего? Я вот не очень в этом уверен. Вряд ли Wolfram Mathematica умеет генерить какие-нибудь SIMD-интринсики и как-то хитро подгонять что-то под размер кеша какого-то там проца.
Да нет, вполне достаточня.
> Смотря кому. Ма-те-матику может быть и понятно всё.
А крутому математику и оптимизированная формула будет понятня.
> SIMD-интринсики
Ты нячал с бинома Ньютона, а теперь уже говоришь про интринсики. Но если уж ня то пошло, то няд оптимизациями такого уровня в gcc&clang бьётся огромное количество опытнейших программистов, и то до сих пор как-то ня очень получается. Ты всерьёз считаешь, что автор очередной велолибы для бигинтов сможет осилить качественную оптимизацию сложнее бинома Ньютона, которая ня только будет что-то оптимизировать, но ещё и ничего ня сломает?
Нет, математик вряд ли знает что-то про SIMD-интринсики.
> Ты нячал с бинома Ньютона, а теперь уже говоришь про интринсики.
Я нигде не утверждал, что речь идет только про бином Ньютона. Это был просто базовый пример. Без доступа к AST в рамках языка никакой подобной компилтайм-трансформации/оптимизации кода не сделать вообще, хоть там бином, хоть не бином. Обычные математические пакеты, типа вольфрам математики - они под оптимизирующие трансформации не затачивались, так что для решения таких задач нужно будет что-то специализированное городить.
> Ты всерьёз считаешь, что автор очередной велолибы для бигинтов сможет осилить качественную оптимизацию сложнее бинома Ньютона, которая ня только будет что-то оптимизировать, но ещё и ничего ня сломает?
Я думаю что если набрать толковых математиков-программистов, они вполне смогут сделать хорошую либу для такого рода трансформаций, которая ничего ломать не будет. Можно даже формально доказывать корректность подобных трансформаций через Coq.
Ня тот момент речь шла всё ещё про биномы Ньютона, но да, про интринсики он ня зняет.
> Я думаю что если набрать толковых математиков-программистов, они вполне смогут сделать хорошую либу для такого рода трансформаций, которая ничего ломать не будет.
Да, а если нябрать толковых экономистов-программистов, то можня построить коммунизм.
У тебя есть примеры таких либ в языках с гомоиконностью/доступом к AST?
Source-to-source трансляторы есть, например вот https://spiral.imperial.ac.uk/bitstream/10044/1/42498/1/Gao-X-2016-PhD-Thesis.pdf
> This thesis introduces a new technique, and its associated tool SOAP, to automatically perform source-to-source optimization of numerical programs, specifically targeting the trade-off among numerical accuracy, latency, and resource usage as a high-level synthesis flow for FPGA implementations.
Очевидно, что для source-to-source трансляции нужно как-то получить AST и что-то там трансформировать
В этой работе авторы используют подход "шланга": компилирует код (очень ограниченное подмножество сишки) в "metasemantic intermediate representation", оптимизируют его, после чего "раскукоживают" обратня в код. Причём, что интересно, весь код для оптимизации у них няписан ня Python, потому что ня Python писать подобные высокоуровневые преобразования очень удобня.
Никакой трансформации AST в этой работе нят.
> 2.1.2 Existing Tools for Source-to-Source Transformation
Гомоиконность/доступ к AST для этой работы вообще никак ня релевантны.
> Existing Tools
А где здесь библиотеки? Это просто либо компиляторы, либо standalone утилиты, работающие с IR. Как им поможет доступ к AST изнутри языка?
Это можно и для инструментации, и для оптимизации. Например, ROSE что-то там умеет в плане автораспараллеливания, ему можно скормить код на крестах и он может в ответ высрать код на крестах с всякими там "#pragma omp parallel for" для циклов
1.3 Problems that ROSE can address ROSE is a mechanism to build source-to-source analysis or optimization tools that operate directly on the source code of large scale applications. Example tools that have been built include:
•OpenMP translator,
•Array class abstraction optimizer,
•Source-to-source instrumenter,
•Loop analyzer,
•Symbolic complexity analyzer,
Вполне релевантны. Из кода получают AST, с AST делают некие преобразования и обратно выплевывают код. http://rosecompiler.org/uploads/ROSE-Tutorial.pdf#part.4 - вот тут что-то такое описывается.
> А где здесь библиотеки?
Тебе нужен пример, библиотеки, которую можно таким методом заоптимизировать? Или тебе нужен пример библиотеки, где официально сами разработчики применяют некие source-to-source оптимизирующие трансформации? Ну например вот https://engineering.purdue.edu/Cetus/cetusworkshop/papers/4-1.pdf
> ROSE is being used by several DOE projects to address the challenges of exascale computing. One of the projects, Thrify, is using ROSE to explore novel compiler analysis and optimization to take advantage of an exascale architecture with many-core chips specially designed to improve performance per watt. In another project, CODEX, an alternative simulator is used to support the analysis of kernels from DOE applications using other proposed exascale node architectures and possible future network connection topologies and hardware. In still another project, ROSE has been used to analyze example applications and extract the MPI us-age as an input code to support evaluation of message passing to support the network communication simulation
> Как им поможет доступ к AST изнутри языка?
Тогда это делалось бы через этот доступ к AST внутри самого языка, не требовалось бы получать AST из исходного кода специальной хренью и потом обратно генерировать синтаксически валидный код, работать надо было б на уровне AST. Это несколько удобнее.
Проблема в том, что всё тобою скинутое — это отдельные утилиты. Они берут исходный код, проводят няд ним изменения и выдают изменённый исходник обратно. Каким образом им может помочь доступ к AST во время компиляции?
> работать надо было б на уровне AST
Во-первых, каким образом скинутая тобой либа будет получать данные PGO во время компиляции?
Во-вторых, оптимизации подобного уровня (векторизация, снижение точности и так далее) няльзя делать "под капотом". Программист должен видеть, что получилось ня выходе, иняче его ждут незабываемые часы отладки. Совсем нядавно bormand рассказывала, как у него компилятор превратил цикл в самописном memcpy в вызов memcpy. Так что ещё более радикальная оптимизация кода должна проводиться исключительня в виде source-to-source, а не в виде "говнолиба перемешала AST так, что отлаживать это можня только под грибами".
Обоснование?
> Проблема в том, что всё тобою скинутое — это отдельные утилиты. Они берут исходный код, проводят няд ним изменения и выдают изменённый исходник обратно. Каким образом им может помочь доступ к AST во время компиляции?
Эти утилиты можно было бы написать на метаязыке, который бы выполнялся во время компиляции. Это мог бы быть например некий хитрый плагин к компилятору, который бы встраивался в процесс компиляции и делал нужные перестановки AST на каком-то этапе.
> Во-первых, каким образом скинутая тобой либа будет получать данные PGO во время компиляции?
Можно инклудить в компилтайм-либу накопленные данные профилирования в каком-то формате, этот файл может быть проанализирован на этапе компиляции, и потом там что-то можно трансформировать в самом коде.
> Во-вторых, оптимизации подобного уровня (векторизация, снижение точности и так далее) няльзя делать "под капотом". Программист должен видеть, что получилось ня выходе, иняче его ждут незабываемые часы отладки.
Если либой гарантируется сохранение наблюдаемого поведения и в либе нет никаких багов, то никаких часов отладки не требуется.
Кстати, а как с этим обстоят дела у крестошаблонного метапрограммирования? Программист обязательно должен видеть, во что трансформируется такая-то шаблонометушня?
> Так что ещё более радикальная оптимизация кода должна проводиться исключительня в виде source-to-source, а не в виде "говнолиба перемешала AST так, что отлаживать это можня только под грибами".
Если перемешивание AST точно не меняло наблюдаемого поведения, можешь отлаживать неперемешанный вариант. Если у тебя перемешанный вариант неправильно что-то считает, неперемешанный будет вести себя ровно так же.
Они работают с IR. AST им ня нужен.
> Эти утилиты можно было бы написать на метаязыке, который бы выполнялся во время компиляции. Это мог бы быть например некий хитрый плагин к компилятору, который бы встраивался в процесс компиляции и делал нужные перестановки AST.
А зачем, если ня Питоне эти утилиты писать быстрее и проще?
> Можно инклудить в компилтайм-либу накопленные данные профилирования в каком-то формате, этот файл может быть проанализирован на этапе компиляции, и потом там что-то можно трансформировать в самом коде.
И это замечательный пример того, как программисты, узнавшие про какой-то новый концепт, нячинают пытаться засунуть его в любое место, даже если в итоге получается переусложнённое говно.
> гарантируется сохранение наблюдаемого поведения и в либе нет никаких багов
Святая няивность!
Да, кстати, а как с сохранением наблюдаемого поведения дела обстоят у сброшенной тобой же утилиты, которая специальня снижает точность вычислений для оптимизации?
> можешь отлаживать неперемешанный вариант.
Программа крашнулась у пользователя. Дамп есть, сейчас отладим!.. Ой, нят, извините, этот дамп с оптимизированной версии, в которой AST перемешано до няузнавания, отладить это ня получится.
> Если у тебя перемешанный вариант неправильно что-то считает, неперемешанный будет вести себя ровно так же.
Очень смешно. Кстати, замена цикла ня memcpy тоже ня меняет наблюдаемого поведения.
> Кстати, а как с этим обстоят дела у крестошаблонного метапрограммирования?
Ня сильня хуже, чем у программы без шаблонов. В дебаг-символах все специализации шаблонов сохраняют имена, просто к ним добавляются аргументы шаблона. В крайнем случае можня сходить ня https://cppinsights.io и посмотреть, во что конкретня раскрывается конкретное шаблоноговно. С AST так ня сделаешь.
А этот IR откуда берется? Случайно не из AST? А если AST и IR на каком-то этапе это одно и то же?
> А зачем, если ня Питоне эти утилиты писать быстрее и проще?
Почему Clang-LLVM и GCC еще не переписали на питон?
> Святая няивность!
Так понятно что баги есть даже в компиляторах, и что?
> Да, кстати, а как с сохранением наблюдаемого поведения дела обстоят у сброшенной тобой же утилиты, которая специальня снижает точность вычислений для оптимизации?
Так ведь даже компиляторы C/C++ с точностью для FPU-вычислений хер знает что делают, и там ничего не гарантируется.
> Программа крашнулась у пользователя. Дамп есть, сейчас отладим!.. Ой, нят, извините, этот дамп с оптимизированной версии, в которой AST перемешано до няузнавания, отладить это ня получится.
Оптимизирующие компиляторы тоже отлично справляются с задачей перемешивания "AST" до неузнаваемости, и без дебаг-инфы там тоже все сложно будет.
>> Если у тебя перемешанный вариант неправильно что-то считает, неперемешанный будет вести себя ровно так же.
>Очень смешно.
Именно так и работают флаги оптимизации у всяких разных компиляторов, если нет UB и багов в компиляторе. Они делают программу быстрее, но поведение не меняется. Это смешно?
Почитай работу, откуда он там берётся. Но это, разумеется, совершення няважно, потому что в итоге авторы манипулируют не AST, а IR. Возможня, потому что умным дяденькам и тётенькам манипуляция AST няпрямую показалась слишком сложной.
> Почему Clang-LLVM и GCC еще не переписали на питон?
А почему утилита по твоей ссылке няписана на Питоне?
> Так понятно что баги есть даже в компиляторах, и что?
То, что ты тут размахиваешь либой, которая гарантирует няприкосновенность кода. В реальнясти такую гарантию может дать только либа, которая побайтово копирует код из одного файла в другой.
> Так ведь даже компиляторы C/C++
Проблема в том, что скинутая тобой либа нямерянно меняет поведение программы. Если бы оня это делала неявня, через AST — программисту было бы очень весело.
> и без дебаг-инфы там тоже все сложно будет.
Да. Проблема в том, что после работы твоей волшебной либы, перемешивающей AST, ня поможет даже дебаг-инфа.
> Именно так и работают флаги оптимизации у всяких разных компиляторов, если нет UB и багов в компиляторе. Они делают программу быстрее, но поведение не меняется.
Только вот проблема в том, что существенная часть ошибок в коде ня C/C++ — это имення UB. И даже сейчас UB может приводить к очень странным и трудно отлавливаемым багам. А твоя волшебная либа только ухудшает ситуацию.
А что если на каком-то этапе AST == IR и трансформации в таком абстрактном представлении где-то происходят? Или так не может быть?
> А почему утилита по твоей ссылке няписана на Питоне?
Ну хз, можно у автора спросить. Если что, могу дать другие ссылки на другие утилиты, которые написаны не на питоне.
> В реальнясти такую гарантию может дать только либа, которая побайтово копирует код из одного файла в другой.
Нет. Для начала надо формально доказать, что компилятор, который собирал эту либу, всё правильно скомпилировал, а еще что космическое излучение не повлияло на процесс, и что в процессоре нет аппаратных багов и еще куча всего можно понапридумывать.
> Проблема в том, что скинутая тобой либа нямерянно меняет поведение программы.
И что? Некоторые оптимизации тоже вполне намеренно меняют поведение программы. Например, -funsafe-math-optimizations
> Да. Проблема в том, что после работы твоей волшебной либы, перемешивающей AST, ня поможет даже дебаг-инфа.
Ну это смотря как устроена эта дебаг-инфа, там это всё можно как-нибудь учитывать, что такой-то преобразованный код соответствует такому-то непреобразованному. Еще можно попробовать эту дебаг-инфу как-нибудь перевести в такую форму, чтоб эта дебаг-инфа выглядела так, как если бы перестройки AST не происходило вовсе.
Тогда это очень сильно ограничивает манипуляции над AST. По сути, ничего кроме оптимизаций запилить невозможно.
Вот сгенерил ты во время конпеляции какую-нибудь сериализацию/десериализацию для структуры и тем самым поменял наблюдаемое поведение (добавил новое).
А ты ведь манипуляции над AST хочешь юзать для новых фич языка и т.п.
Если нужно новые фичи языка добавлять, не имеет смысла говорить о "неизменении наблюдаемого поведения" т.к. расширенный язык (условно говоря C++) не скомпилируется компилятором нерасширенного языка (условно говоря компилятором C). И никакого наблюдаемого поведения у некомпилирующейся программы нет, так что постановка вопроса некорректна.
Это скорее означает, что "простой" вариант с сохранением поведения тут не катит. И придётся как-то формализовывать эту фичу, описывать её взаимодействие с другими. Ну, то чем сейчас и занимаются комитеты. Только из-за зоопарка этих библиотек-расширений багов в реализации и недочётов в спеке будет на порядок больше.
А отлаживать неведомую херь тоже не особо весело.
А часто ли программист должен смотреть ассемблерный выхлоп из компилятора? Ну там ведь тоже куча всяких сложных трансформаций происходит, что-то куда-то заинлайнивается, loop-invariant code motion всякие происходят, loop unswitching, т.е. вместо кода типа
компилятор где-то в каком-то абстрактном говнопредставлении перетрансформирует это в
И потом компилятор это еще и наанроллит. Обязательно ли это все видеть?
Так в том-то и проблема, что вообще каким-либо образом отлаживать программу с покорёженным AST практически нявозможня. Потому что после изнясилования AST у тебя будет выполняться совершення ня то, что няписано в коде. И твои ошибки будут преобразовываться до няузнаваемости. А уж если в "оптимизирующей либе" будет баг...
примерно один раз в никогда и только если очень хочется сделать микрооптимизацию приколоченную к платформе
иначе не нужна эта якобы портабельная крестушня
Ну ещё иногда конпелятор генерит говно и приходится читать что он там высрал. Но это прям крайне редко.
ну это почти или даже за рамками задач обычного генерал-пурпоза прогармиста
вопрос доверия к инструменту как бы
Вместо проблем у тебя появляются метапроблемы.
И если не делать трансформации AST с помощью сахарка в языке (квазицитирования и сплайсов, как в TH), то через месяц читать свой мета-код становится очень интересно.
Вряд ли крестовые шаблоны в этом плане веселее.
Сравни типичное шаблоноговно (не из буста) с
https://github.com/k32/typerefl/blob/master/src/typerefl_trans.erl (и это ещё очень простая трансвормация)
Какая консистентность именования )))
К слову, даже на родине гомоикон в лиспе все почему-то стараются юзать квазицитирование а не гомоиконы... Хотя казалось бы.
Так что даже лисперам лень в чужих говноиконах копаться.
И при раскрытии могут порождать некий новый код? Вот например компилтайм-либа крестов для PCRE https://github.com/hanickadot/compile-time-regular-expressions - она что, ничего не порождает? Что вообще значит "порождает новый код"? BOOST_PP_REPEAT порождает или не порождает новый код? А что тогда порождает?
Не порождает. Исходный код всех функций написан заранее, из них просто собирается дерево. Если пробежаться по коду в отладчике (с выключеной оптимизацией, само собой), то помимо функций из этой библиотеки ты ничего нового не увидишь.
Нету там каких-то волшебных гомоикон, которые создают код из воздуха или что-то в нём меняют. И к счастью и к сожалению.
Демагогия какая-то. Следуя такой логике, тогда и обычный компилятор ничего не порождает, когда компилирует что-то из кода на Си в инструкции процессора. Ведь код компилятора написан заранее, компилируемый компилятором код написан заранее, из компилируемого кода собирается какое-то дерево и потом по каким-то известным правилам во что-то трансформируется.
В крестах через шаблоны вполне можно написать некий недокомпилятор, чтобы некая шаблоносрань принимала в себя строку, каким-то образом ее парсила и раскрывалась в некую хрень. Чем бы это на фундаментальном уровне отличалось от обычного компилирования?
Если провести аналогию с функциональщиной, крестовые шаблоны -- это просто композиция существующих крестовых функций, каждую из которых я могу прочитать в исходнике.
В отличие от макросов, которые могут что угодно высрать и наконкатенировать. В отличие от трансформаций AST, которые делают новые функции и структуры, которых в моём исходнике нет.
И что? Ну вот есть допустим некий крестовый шаблон, возьмем простейший вариант, без всякой сложной метушни
И где-то я использую эту хрень таким образом
Отчего бы мне не считать, что делая подобную хрень, я автоматически генерирую (порождаю) где-то функцию типа
?
Сейчас, увы, нет широко используемых и достаточно низкоуровневых языков с доступом к AST в компилтайме, чтобы там такая оптимизация была реально полезной.
Будут либы, которые напрямую работают с AST, и делая условный "getFields<struct X>" я как раз буду такую либу использовать. Но чтоб такие либы написать, нужен доступ к AST.
А что получилось в C/C++? Полуработающий Conan, в котором хрен чего найдешь, и поэтому один фиг надо ходить по гитхабу с черным мешком для мусора и собирать в него нужные говнолибы? Это лучше?
Я вот кстати посмотрел такую либу https://github.com/hanickadot/compile-time-regular-expressions - это вот регулярки через шаблоны в компилтайме, с запиленным в компилтайме LL(1) анализатором на шаблонах. И там еще вот такая генеренная шаблонная хрень из какого-то DESATOMAT
Да, нагенерить километры какой-то шаблонной хрени это прямо вот "хорошо и эффективно". На кой вообще делать кодогенерированную компилтайм-либу на шаблонах которая генерит регекспы в компилтайме, если сами регекспы можно сразу кодогенерировать?
Нязвать язык программирования говном можня только после обширного анялиза его нядостатков. То, что кресты ня могут решить эту задачу, ознячает лишь то, что они ня могут решить эту задачу (хотя в принципе, конячно, кресты — говно, с этим никто ня спорит).
Простыми словами: я купила машину, а в машине нят прикуривателя. Ознячает ли это, что машина — говно?
я сколько тут сижу вы столько тут анализируете недостатки с++
Парадокс говна («Говно», «Моча») — логический парадокс, сформулированный Евбулидом из Говнокода (IV век до н. э.)[1], связанный с неопределённостью предиката «быть говном»[2].
Слишком малый ресурс при слишком высокой цене — конячно, говно. А что такое малый ресурс и что такое высокая цена — тут уже каждый решает для себя.
Разрабы Boost программируют или упражняются в эзотерике?
Что-то не похоже
Компилтайм-метушня вполне может (и должна) быть zero-cost.
https://wandbox.org/permlink/BjVlfoT12mb8xQFp
https://wandbox.org/permlink/eBiqs8lco7J3IMww
Блядь, какое же говно. И все равно это будет недостаточно универсально.
А зачем мне надо выбирать, писать "x += y" или "x = y + z"? Ведь вполне может быть так, что из каких-то там шаблонов или макросов или смеси шаблонов и макросов раскрывается такая вот фигня вида "x = x + y" и мне надо чтоб оно там само это нашло и переписало в "x += y" для максимального пирфоманса.
Чтобы ясно выразить, что в первом случае ты хочешь сразу модифицировать x, а во втором — снячала сложить, а потом записать в x.
> Ведь вполне может быть
Ни разу ня видела таких шаблонов. Приведи пример из реального проекта, в котором такая оптимизация могла бы улучшить производительность.
А если я хочу получить нужный мне конечный результат максимально эффективным образом, а что оно там сначала и что потом делает - меня не волнует?
> Приведи пример из реального проекта, в котором такая оптимизация могла бы улучшить производительность.
Лично я таких проектов не знаю. Искать лень.
Тогда ты используешь только +=.
> Лично я таких проектов не знаю. Искать лень.
И я ня зняю. И с учётом крайней оторванности этой задачи от реальности — скорее всего, если такие проекты и есть, то встречается няобходимость в этом "автосворачивании операторов" раз на миллиард sloc.
А если у меня откуда-то синтезируется код с a = a + b и я хочу этот код преобразовать в a += b ?
Дык нет в крестах "синтеза кода откуда-то". Весь код уже написан тобой. Просто параметризуется немножко. Поэтому либо ты сам уже написал a += b либо там всегда и будет c = a + b, которое никуда не преобразовать.
Ну написан, и что? Вот есть макрос, допустим
#define SHIT(a, b, c) a = b + c
Если я его вызову как
Обколются своих макросов, а потом в жопы ебутся...
Охуеть.
Препроцессор с условием просто высрет это условие в код. Он же просто токенами ворочает. А условие, если оно не constexpr, будет выполнено уже в рантайме.
З.Ы. А #ifdef внутри макроса нельзя юзать, если ты о нём.
и если компилятор не докажет, что оно константа:)
Кстати, в няшной же нет constexpr?
Ключевого слова нет. А само понятие, типа "известная на этапе компиляции фигня" - есть.
так скомпилируется:
Так тоже скомпилируется в GCC и Clang, но это уже экстеншен:
warning: variably modified 'a' at file scope
А вот так нихуя не скомпилируется:
И так тоже не скомпилируется:
Значения енумов и метки в свиче ещё требуют "constexpr". В общем-то как и в крестах.
Это к щастю везде есть) Кажется, что "int i = 2 + 2" даже javac поймет
>И так тоже не скомпилируется:
хм.. а это не VLA?
VC не умеет VLA, но GCC то вроде должен уметь?
Хмм, ну да, с VLA оно скомпилируется, но оно не будет компилироваться, если эта хрень объявлена глобально. Глобальный массив не может быть VLA.
пушо стек еще как-то можно двигать в рантайме, а вот размер data и bss нужно знать заранее?
В C99 появился.
А вот в C89 (который был и в bolrand c++ 3) мало того, что не было VLA, так еще и все локальные переменные нужно было декларировать в начале тела функции.
То есть размер стекфрейма функции компилятор всегда мог посчитать перед началом функции.
Кcтати, а в С++ вместо VLA принято использовать vector, который всё хранит в куче? Или он может как-то читерить, и хранить на стеке через alloca?
согласен
Возможность объявлять переменные походу энкариджит говнокодеров высирать функции на 900 строк
if (cond) int a = 1; else double b = 1.0;
?
А он кстати во что скомпилится в с99?
Внихуя. Переменные же не используются (а использовать ты их не сможешь).
З.Ы. А, вообще не компилится, лол. Скобочки просит.
>sub rsp, 32
если добавить еще int, то будет 48
а потом пишет твою "a" в одно и тоже место
mov DWORD PTR [rbp-8], 1
add DWORD PTR [rbp-8], 2
ну тоись он пошел, посчитал размер стека, двиганул SP (предвроительно сохранив его в BP) и дальше жег
А что бы он делал с FPO кстати я не зна, надо проверит
То есть всё равно посчитал всё место, какое ему может понадобиться в любом из ветвлений, и отожрал стека, а потом, возможно, часть отожранного стека не юзал?
Это практически то же самое, что просто собрать все декларации, так как если бы они были написаны в начале функции, только синтаксически разрешить писать их не в начале, или я не прав?
попробуй
получишь
Единственный плюс "нового" подхода это ограничение видимости. Оно позволяет иметь "b" внутри каждой веточки своё.
Ну и вероятно деструкторы должны вызываться в случае С++.
Забавнее посомтреть что будет, если крутить стек в рантайме
VLA
начинаются игрища с стек поинтером
Удивительно другое!
Я заказал "-fomit-frame-pointer" чтобы посмотреть как питух будет изъебываться адресовать переменные от SP, которого он постоянно дрочит.
А он взял, и положил на эту опцию, и продолжил юзать BP.
При этом если сделать код без VLA, то -fomit-frame-pointer отключает BP, и переменные начинают адресоваться от SP.
Иными словами, FPO значит не "запрещаю тебе юзать BP" (как я до сего момента думал), а означает "разрешаю тебе не юзать BP, если хочешь"
А компилятор такой: ой, ну если бы ты не трогал SP в рантайме, то я бы воспользовался твоим предложением, а так засунь себе FPO в жопу, а я буду продолжать адресовать переменные на стеке от BP
Ну да, абсолютное большинство "оптимизирующих" опций — это рекомендации, а ня законы (прямо как Кодекс в PoTC \(★ω★)/).
FPO это разрешение компилятору юзать BP под свои нужны, бо у программиста есть символы.
Хотя наверное в x64 регистров уже так много, что смысл экономить на BP нет
Напоминает "record case" или variable records в паскале.
Там можно объявить запись с вариантами разблядовки типов, например
В итоге сайзоф такой записи будет исходя из размера самого ресурсоёмкого case, но не всей их суммой. Все case замапятся в одно и то же место в памяти и гарантированно влезут. В данном примере попытавшись изменить razmer_sisek у записи можно поломать его значение zarplata, потому что предполагается что юзаться кейсы должны независимо. Компилятор за этим не следит, ты сам в коде должен определить для себя, какой тебе от этой записи нужен кейс. Таким образом можно знатно сэкономить на спичках.
sizeof этой конструкции будет равен int (мы предпологаем, что int выравнивать не нужно).
Если ты положил туда i, то в "с" теперь UB, и наоборот.
Сам должен следить за тем, что положил.
Тоже такая вот экономия.
Там есть прикол в крестах с тем, что туда нельзя класть объекты с нетривиальным деструкторами, бо хуй знает, когда их вызывать.
Только в наш rsp по идее влезут ВСЕ объявленные переменные
Если ты в начале функции ты видишь все её перменные, то ты просто двигаешь stack pointer на нужное количество байт, и потом можешь их от него адресовывать.
Закончилась функция -- ты его обратно подвинул.
А если у тебя по ходу пьесы стек двигается на вычисляемое в рантайме количество байт (alloca, vla, или if (petuh) {int i..}, то тебе нужно как-то в рантайме понимать какого размера твой стек, и как это обратно всё потом двинуть, когда функция закочнится.
Наверное хорошо, если у тебя есть FramePointer (BP) который указывает на начало функции, от него можно хотя-бы наверное переменные адресовывать, а если нет?
Короче, написать такой компилятор труднее.
Так вижу. Но может дело и не в этом..
Алсо, стек (особенно во времена c89) было СОВСЕМ не резиновый. 16 килобайт или около того был он в паскале
Клангом для Си собирается (если как глобалки), а GCC уже не хочет это собирать.
Не, в этом случае всё жёстко. Не доказал -- не скомпилил.
Да. Если ты в макросне напишешь if (x) {y;} else {z;} то у тебя это условие в то место впихнется как код. Для тебя это новость?
Макросня работает на уровне токенов. Можешь считать её скриптом на PHP, который просто что-то там в тексте правит и копипастит. А в языке она ничерта не смыслит, ни в сишке ни в крестах.
Т.е. про == и if шаблонизатор ничего не знает, как PHP ничего не знает про <div>. Поэтому он их дословно копирует на выход.
a + b
то у a вызыавался бы append (Ну тоесть делался бы тот самый реаллок)?
Flexible_array_member кстати не очень нужен, когда есть шаблоны: туда же можно реальный размер передать, И потечь
> explicit MyVector
explicit нужен только для конструкторов, принимающих только один аргумент. Для других он ня имеет особого смысла.
У нас нет кодстайла для крестов, потому что на крестах в моем отделе три тупых утилиты написано
Я использую тот кодстайл, который форсит мне по умолчанию студия и R#, он более-ли-менее коньсистентен
Т.е. он эту хуйню всё-таки не смог пропихнуть в кодстайл? ;)
Я был за то, чтобы писать его во всех переменных. А другие были против.
Я добавлял, другие удаляли
Потом ввели общепродуктовый стиль, и разумеется ненужный final запретили
Речь только о локальных (автоматических) переменных конечно
А в котлине и TS "val" и "const" уже признаны хорошим тоном.
А вы помечаете переменные const при любой возможности?
Ну да. Читать легче.
Хотя по-хорошему const на переменных должен быть по-умолчанию чтобы не замусоривать код. В ocaml'е вроде так и сделали.
Слава богу, я уже давно почти всё JVMговно пишут на котлине, а там всё неизменяемое по умолчанию, само собой
До этого тоже доебывается, кстати
Ну про конст, имхо, есть смысл доебаться в джвух случаях где он пиздец как важен:
- const справа от функции
- const у данных, на которые указывают указатели и ссылки
Остальное -- это просто вкусовщина и подстраховка от ошибок. Никто не умрёт, если его не напишешь. Но ревьювить будет сложнее если функция большая (надо в уме доказывать, что в переменную не срут).
Это же мой любимый пример отсоса всех джав и сишарпов у крестов: const семантика:)
По сути это другой тип (с точки зрения джависта так точно).
А внутри метода иметь немутабельные переменные просто хорошо (например tslint ругается, если ты пометишь let то, что может быть const)*.
Забавно, что в котлине аргументы функции иммутабельны всегда: ты не можешь изменить то, что то тебе передали (только скопировать)
* https://palantir.github.io/tslint/rules/prefer-const/
- unqualified name lookup
- argument-dependent lookup
- member name lookup
- template argument deduction
- SFINAE
- implicit conversion
- constraints and concepts
- ranking of implicit conversion
- function template overloading
Типа
или лучше всё таки лямбду юзать и не выёбываться?
Можешь ещё с бустом повыёбываться: std::find_if(i, last, _1 > 2).
Потому что ты не умеешь его читать. Я думаю с опытом он нормально воспринимается.
А вот все эти bind2nd -- устаревшее говно, конечно. Для тривиальных случаев есть универсальный bind, в котором сразу понятно что куда попадёт. А для более сложных можно лямбду или функцию написать.
Как и большинство коллег. Именно это я и хотел сказать.
А теперь представь, что вокруг тебя математики, которым эти векторные операции и функции высшего порядка гораздо ближе, чем циклы. Для них J будет читаться не хуже обычных формул.
Для старой юниксбляди перл вполне читаем, питух с delphi бекграундом просто волосы на жопе рвет, и орет 'как вы на этом говне пишете вообще?'
>std::bind2nd(std::greater<int>(), 2)
?
З.Ы. Именно за это я не люблю STL. Он пытается косплеить функциональщину, но получается как у тех папуасов с карго-культом.
Ну всёж таки в STL была хоть какая-то ванаби-функциональщина еще в 2003-м. А например в жабе всё руками делали
лист компрехеншены правда тоже лямбды в каком-то смысле (но тоже малоудобные, лол)
Питон такой антируби
то есть круглые скобочки, а не кводратные
>Ну нету здесь никакой функциональщины
а в map и filter есть?
Ну тут не поспоришь.
Мне нравятся цепочки, которые есть в руби и в груви и частично в JS и в котлине и даже можно изъбнуться в перле.
А только в питоне принято всё расписывать вручную, потому что цепочек нет
Да. У тебя есть функция для одного элемента и она лифтится в функцию, которая обрабатывает много.
В совсем труъ функциональщине было бы так: (map f) list, но и map(f, list) тоже неплохо её косплеит.
а чем вот это не это?
Ну вот смотри, в map(do_all, list) ты описал ЧТО нужно сделать, не вдаваясь в детали реализации.
А в (do_all(x) for x in list) ты пишешь КАК это нужно делать, явно выписывая императивный цикл.
(do_all(x) for x in list)
можно было написать
(do_all in list)
то было бы оно?
Ну это тоже не функциональщина... Где здесь превращение do_all, который обрабатывает один элемент во что-то большее, что умеет обрабатывать много? А это важно для композиции, к примеру. Чтобы я мог связать несколько таких функций в один конвейер.
Как ты в твоём синтаксисе запишешь (map do_all) . (filter (> 42)) . (map preprocess)?
(do_all in list)
отличается от
(do_all, list) ?
>конвеер
Ну как-то так, наверное
(fuck_em_all in (do_all in list))
Но вообще это в питоне некрасиво сделано всё таки, что с itertools что без них.
Толь дело руби
Да, вот тут прям красиво закосплеили.
Но всё равно немного не то, конечно... Нету композябельности, нельзя заюзать эти операции как лего, собирая из мелких кубиков что-то интересное.
Т.е. в примере из хаскеля я могу добавить ещё какие-то фильтры и преобразования. Или даже сделать функцию, которая эти фильтры навешивает по параметрам. А потом запустить список на обработку получившейся функцией. Вот в чём суть труъ функциональщины.
А в примере из руби я просто выполняю одну операцию над списком. А потом выполняю вторую. Скукотища.
Но уже очень близко...
А строку туда просто пихнули, а рядом вон енумератор от 0 до 1000
Но я понимаю, что собрать конвреер, а потом его запустить было бы круче
Ну как это, цепочка начинается с en ;)
В принципе, можно сделать def compose(f, g) def res(x) f(g(x)) end res end.
И им уже соединять кусочки: chain = compose(cap, first_two). А потом запускать: chain foo.
Да, а map -- это фабричная функция. Так и живём.
Билдер это когда ты напихиваешь говна в коробочку, а потом просишь по нему что-то построить
вот std::stringstream или StringBuilder это строители
Это оно?
Х.з., а пайпы можно закомпозить друг с другом? Или только с нуля конструктором строятся?
Хотя... всё норм. pipe() это не новая сущность, просто функция для композиции функций. Ну тогда труъ.
Таких функций офердохуя, кстати: есть tap для сайдэффектов, например)
Я попытался принести RxJava к нам в проект (полагаю, там тоже самое), но мне сказали юзать котлиновские корутины и ченнелы.
А там всё таки императивщина: если ты хочешь из одного ченела в другой переложить, то ты должен писать цикл (хотя он и будет конечно ленивый, ибо suspendable функция)
Эм, а как они на JVM это сделали? Генерят класс со стейтмашинкой вместо функции? Или что-то хитрее?
Функция это класс, хранящий в себе свое состояние и свой "стек".
Его метод вызывает диспетчер. Метод завершается, когда встречает суспендбл вызов (разумеется, блокирующие вызовы типа read и sleep запрещены!)
Всё это обмазано сахаром, потому выглядит как будто ты отдельный процесс запустил
Или попробуй написать функцию, которая настраивает фильтры, а потом отдаёт эти фильтры в другую функцию, которая уже будет обрабатывать список. Не получается, выглядит как говно? А ведь это вполне практическая задачка, на которой императивные языки просто сосут.
Ты не можешь клеить куски этой цепочки во что-то более интересное, ты можешь только применять их к списку по одному за раз.
Вспоминается реактивное RxJS и иже с ними. Там ты можешь создавать папйпы, как угодно их соединять, и потом куда угодно подключать.
Причем это всё может быть ленивое
Ебучие гармошки вместо кода... Или разрабы просто не умеют его готовить?
ну вот я там привел пример
Не, гармошка -- это те 3 экрана кода, которые до )))))))))
ну может быть
Я обычно стараюсь генераторы, потому что они ленивы, и не создают в памяти лишний лист
Главное потом не пройтись по нему два раза случайно
но читать его не очень кмк
https://abseil.io/tips/108
Но почему не
?
DoStuffAsync же не имеет this
Но я всё равно не понимаю, на что расчитывали seasoned C++ engineers пися
> std::bind(&MyClass::OnDone, this)
что this как-то волшебным образом прибайндтися к OnDone?
https://i.redd.it/mleiaj2hucg31.png
Уильям Шекспир
Точно помню, что в одном приложении никакой пуш эппловский не использовался (он имеет смысл когад у тебя 100000 клиентов, когда он один, то можно пулить прямо с сервера)
Там ios нас будило, и мы рисовали нотификацию.
Но как именно работало уже не помню, давно очень было(
> можно пулить прямо с сервера
Ну и зря. Там же не в сервере проблема, а в батарейке клиента. Пуши экономят батарейку, оставляя только один полл, который и так уже есть в системе.
Лол, я нашел репу с тем говном)
Там было так:
UIBackgroundModes -> fetch стояло в Info.plist, и потом ios переодически нас будила, и дергала performFetchWithCompletionHandler
ну мы фетчили по http и создавали UILocalNotification
Пуши сейчас даже в браузерах есть. И юзать их вообще тривиально.
А вот подпись для него нужно было получать официально. Платили бабла эпплу, и их эппла звонил питух, и подтверждал!
Пишут, что можно зайти в свой девелопре аккаунт на эппле и зарегить там пуш
Пуши в браузерах ты сам делаешь со своего сервера же, нет "централизованного сервера пушей"
Или есть?
Вроде есть. Иначе у тебя браузер заебётся поллить десяток сайтов.
А разрабам похуй, конечно. Отправляют плейнтекстом.
Ты хочешь локально нотификацию показать? Типа висишь сервисом и показываешь Toast?
Кстати, фетч про который ты выше пишешь, это же тоже походу оптимизация батарейки? Чтобы твой сервис ходил в инет только в положенный таймслот вместе со всеми остальными, а потом девайс нормально спал с отключенной сетью.
Я прошу ios иногда меня разбудить, чтобы я мог что-то пофетчить.
Иос имеет право не будить меня когда нет батарейки, или когда там дорогой Интернет в роуминге
Но возможно этот API уже устарел.
А в андроиде есть WorkManager , который ты тоже можешь попросить чтобы тебя запускали только когда телефон заряжен или есть wifi итд
Ну это для каких-то больших загрузок, наверное. Когда какая-нибудь игрушка или навигатор хочет скачать гигабайт. Ради сообщений в мессенджере было бы глупо ждать вайфая.
(тру стори)
((там, правда, не роуминг был, а местная симка, но все равно бабки сожрало, с запасом же было положено. И еще не сразу понял, что баланс 0, испугался, что мобильная связь не работает, может, уже все рухнуло и мне возвращаться некуда))
Эм, да может конечно. У меня даже говнотифи так делало... Борьба с этим очень простая: тычешь в уведомление и говоришь "больше не показывать". И приложение с этим запретом ничего сделать не сможет.
А пуш -- это именно про оптимизацию доставки небольших пакетов от сервера. Ну и если тебе совсем влом пилить сервис -- можешь попросить, чтобы ось сама его показала когда получит. Тут, конечно, шифровать ты его не можешь иначе как ось без твоей помощи покажет.
И я отвечу: обсырают С++.
Прежде, чем обсирать его, переведите на няшную такую вот ненужную программу, написанную в терминах C++03 (а то и 98)
Не то чтобы подобные задачи я решал на работе, но это показывает, как много всего можно было делать из коробки еще 20 лет назад.
PS:
Текст взят отсюда:
https://www.youtube.com/watch?v=cBdIsUp6k7o
Когда Ричи хотел внести в C очередную фичу, Керниган говорил: "Если тебе нужен PL/1, ты знаешь, где его взять". Видимо, Страуструп не знал, где взять PL/1.
Какая ортогональность ))
А потом в каждом серьезном проекте ..
these subsets (сишные) are buried under an abstraction layer that contains about 50% of all Postfix source code, and that provides the foundation on which all Postfix programs are built. For example, the "vstring" primitive makes Postfix code resistant to buffer overflow
Сишке действительно не нужно иметь в стандартной библиотеке парсер XML, но писать одно и тоже в каждом проекте тоже не айс.
-------
Вообще какие есть варианты?
1. Насрать всё стандартную либу, и стать непереносимым.
2. Ничего не иметь в стандартной либе, писать всё с ноля, и ебанутьчся
3. Ничего не иметь в стандартной либе, сделать репу с "хорошими решениями" и стать "leftpad".
Кажется, все три варианта самые плохые
А это зависит. Для высокоуровневых скриптовых языков такой аргумент вполня себе валиден, потому что чем больше говна в стдлибе — тем проще и быстрее няписать говноскриптик, а скорость и простота няписания говноскриптиков — один из важных параметров скриптоязыка.
Вот у ме-ня возникла нядавня задача вытащить инфу из виндовых инсталляторов (которые msi). Я взяла Python, импортировала msilib и решила свою задачу за десять минут: максимальня быстро и безо всяких поисков нужных либ. Это хорошо и удобня.
Зачем? Зачем писать на крестах без стдлибы?
Не всегда есть выбор ;(
Она, к сожалению, неудачно спроектирована и слишком сильно завязана на сервисы ОС.
Вот lua везде работает, на любом C89 компиляторе.
Удачи с более сложными языками. Один из самых наивных факапов в дизайне крестострок.
Причем оно же, суко, может и скомпилироваться.
С русским не соснул же, чем немецкий хуже?
а ща проверю
Вообще настоящие строки должны содержать кодпоинты наверное, а не байтики
Просто не надо напяливать transform на строки, вот и всё. Им нужны свои алгоритмы и итераторы, как в том же icu.
А utf-8, utf-16, utf-32, какая-то другая кодировка -- это вообще непринципиально.
https://codepoints.net/U+00B4
То есть ситуация, когда при добавлении символа не изменяется их число, а просто меняетя предыдущий, там в порядке вещей.
Твой эсцет из той же области
Вот что я имел ввиду)
Но ты прав: работать с такими строками как векторами каких-то сущностей уже не получится
зы: всем хватит cp866 или koi8-r. Понапридумывали хуйни ненужной, блядь
Получится, но надо stateful алгоритмы. А transform он без состояния.
Всё таки крестостроки это такие обёртки вокруг массива чаров (точнее того, что там в traits), вообще почему они не спецификация вектора?:)
"настоящие" строки это совсем другое, ну вот icu наверное для того
Так вышло. Они же в крестах были изначально, задолго до STL. Ну и нолик там в конце, как в соседнем треде обсуждали.
> icu наверное для того
Угу. Оно и весит десятки мегабайт...
Ещё радует, что в турецком «i» переводится в «İ» вместо «I», а в «I» переводится «ı». То есть даже апкейс/лоукейс от «I» и «i» зависит от локали.
В греческом заглавная «сигма» одна (Σ), а строчных две (σ и ς). Вторая используется на конце слов. Т. е. для правильного лоукейса ещё нужно найти границы слов.
Однако, используют ли эту букву реально, я не в курсе.
А в совсем старых книгах в качестве заглавного «эсцета» использовали не «SS», а «SZ». Как эта питушня поддерживается софтом, я не знаю.
Река в единственном числе — Fluß, а во множественном — Flüsse. А ещё «ss» может случайно оказаться на стыке основ (первая заканчивается на «s», а вторая на «s» начинается), когда менять «SS» на «ß» ни в коем случае нельзя.
А ещё бывает мозговзрывающее слово «масштаб» (Maßstab).
https://ru.wikipedia.org/wiki/Реформа_немецкого_правописания_(1996)
Я никак не могу запомнить, в каких словах они поменяли «ß» на «ss», а в каких оставили.
Кстати, посмотри картинки в статье. Там и «ttt» есть.
– но очень хочется?
На самом деле мне пофигу, потому что чаще приходится переводить на русский. А немцы как-нибудь обойдутся без моего перевода, пусть языки учат.
мы практически точно знаем, что икарус работал в издательском деле в 90-x
у него работа связана с текстом и возможно переводами
интересно, что это за работа
а ты мне что?
Одно время их выходило по пять штук в год
знаю onenote, evernote
https://en.wikipedia.org/wiki/Comparison_of_note-taking_software
хотя забавно, что, когда я искал todoist и notion, мне показывало рекламу трелло с какого-то хуя
есть еще google tasks
– тогда джира это тоже заметки
https://d2k1ftgv7pobq7.cloudfront.net/meta/p/res/images/spirit/product/89d378b845766a8f0c48e955336266f8/board.png
в джире можно сделать такие же тудушки
в чём удобство трелло и неудобство джиры, особенно в контексте софта для заметок?
а остальное можно конечно
только я бы даже для туду, не говоря уже о других категориях, не стал бы пользоваться ни жирой, не треллой
совершенно из другой оперы софт
тут туду это тикет
какие-то мимолётные идеи, примитивная домашняя бухгалтерия, списки ссылок на пх, план поездок
туду это частный случай, не более
grep -P "^[uvwxyz]+$" usernames.txt
https://www.gnu.org/software/grep/manual/html_node/Matching-Control.html
А вот «*BSD» и «Solaris», возможно, в пролёте:
И «Занятая коробка» в пролёте:
https://www.busybox.net/downloads/BusyBox.html
В такую жопу её запихали
https://www.gnu.org/software/grep/manual/html_node/grep-Programs.html
> В такую жопу её запихали
Зачем? Зачем?
Если нет «man» у большинства комманд всегда есть свитч --help
https://www.gnu.org/software/grep/manual/html_node/grep-Programs.html#index-_002dP
К слову, можно вообще обойтись без знания иностранных языков. Некоторые программисты английского не знают, для них «if» и «for» — это иероглифы.
Удачи там с японским. В icu походу мегабайтный словарь японских слов для этого есть.
RabbitMQ
MSMQ
А еще бывает табличка в шареной базе данных)))
В NGK очередь на сканирование тредов так и работала.