Нашли или выдавили из себя код, который нельзя назвать нормальным,
на который без улыбки не взглянешь?
Не торопитесь его удалять или рефакторить, — запостите его на
говнокод.ру, посмеёмся вместе!
// https://habr.com/ru/post/550442/
// Как компилятор C++ находит правильную функцию
// Вот так компилятор точно определяет, какую функцию следует вызвать:
// https://hsto.org/webt/mp/tb/5k/mptb5kheibrreqspserc4sfdfrs.png
// Эти шаги закреплены в стандарте C++. Каждый компилятор C++ должен следовать им,
// и все это происходит во время компиляции для каждого вызова функции. Оглядываясь
// назад, это очевидно, что должен быть такой алгоритм. Это единственный способ, которым
// C++ может поддерживать все вышеупомянутые возможности одновременно. Это то, что вы
// получите, если необходимо объединить их вместе.
// Я предполагаю, что общая цель алгоритма — «делать то, что ожидает программист»,
// и до некоторой степени он в этом преуспевает. Вы можете довольно далеко зайти,
// полностью игнорируя этот алгоритм. Но когда вы начинаете использовать все возможности
// C++, как при разработке библиотеки, то лучше знать эти правила.
Да, это конечно очень круто, только вот существует примерно 0 компиляторов, которые полностью корректно (т.е. в полном соответствии с Говностандартом) реализуют эту срань с вызовом правильной функции/метода с учетом всей хуйни.
я в целом не в курсе изменений, всегда считал их рыгаловкой
знаю только, что политика удалять интересные статьи чтобы не обидеть коллективного Усманова появилась за этот период
> Как видно из блок-схемы, существует три основных типа поиска имени, каждый со своим собственным набором правил.
> Поиск имени по методам (Member name lookup) происходит, когда имя находится справа от токена . или ->, как в foo->bar. Этот тип поиска используется для поиска методов класса.
> Поиск квалифицированного имени (Qualified name lookup) происходит, когда имя содержит токен ::, например, std::sort. Этот тип имени является явным для компилятора. Часть справа от токена :: ищется только в области видимости, обозначенной в левой части.
> Поиск неквалифицированных имён (Unqualified name lookup) не является ни тем, ни другим. Когда компилятор видит неквалифицированное имя, например blast, он ищет совпадающие декларации функций в множестве различных областей в зависимости от контекста. Существует подробный набор правил, который точно определяет, где должен искать компилятор.
Квалифицированные-хуифицированные, понаприрумывали херни всякой. А почему они не сделали какой-нибудь метушни над AST (и чтоб с гомоиконностью), которая б уже использовалась для написания логики для подобного говна? Почему им проще захардкодить набор каких-то ебанутых правил, которые все равно никто нихера не знает, и даже в компиляторах их реализовывать не осиливают?
Когда подстановка аргументов шаблона терпит неудачу, шаблон функции просто удаляется из списка кандидатов -- но в какой-то момент истории С++ программисты поняли, что это возможность, которую они могут использовать! Это открытие привело к целому набору самостоятельных методов метапрограммирования, которые вместе именуются SFINAE (substitution failure is not an error).
> В самом деле, если одна из вышеперечисленных функций была бы единственной жизнеспособной, она могла быть той, которая в результате и обработает вызов функции. Но поскольку их две, компилятор должен делать то, что он делает всегда, когда имеются несколько жизнеспособных функций: он должен определить, какая из них является лучшей жизнеспособной функцией (best viable function). Чтобы быть наиболее жизнеспособной функцией, одна из них должна «побеждать» над всеми остальными жизнеспособными функциями, как определено последовательностью правил разрешения конфликтов.
Может там им еще сделать чтобы функциям начислялись некие баллы жизнеспособности по некоторым ебанутым говноправилам, и чтоб выигрывала та функция, которая больше баллов набрала?
Если там потом какая-то верификация как в coq, то в общем-то норм решение. Зачем писать говно вручную, если можно потратить это время на написание хорошей спеки и документации.
Не, ну если мне сотрут память, и я забуду о всей хуйне в крестах, может быть тогда я бы стал писать на крестах. Но это надо чтоб я не полез с самого начала искать хуйню в крестах, надо чтоб я изучил кресты достаточно сильно и прошел некую точку невозврата, ну чтоб я достаточно сильно изнасиловал себе мозг крестоговном, и мне эта ублюдочная помойная дрянь начала бы нравиться, и тогда недостатки крестоговна (о которых я узнаю уже из опыта) воспринимались бы уже не так критично, (типа я ведь уже проебал столько времени на осиливания этой питушни, ну подумаешь, ну ничего, это все не так уж плохо).
А надежды у меня такой нет. Стирать память ради осиливания помойных крестов (если б существовала такая технология) я не желаю.
> Зачем под это какая-то особая сущность? Почему някня для строк не является обычным контейнером?
Потому что она и должна являться особой сущностью? Или ты хочешь в обычный контейнер добавить методы для работы с символами (всякие там capitalize()/upper() и ня) и поддержку UTF8?
Другое дело, конячно, что в крестовых "строках" всего этого нят: чтобы понять, зачем нужен отдельный тип для строк, лучше посмотреть ня какой-нибудь Python.
Были бы в крестах были extension method'ы какие-нябудь — было бы нярмальное решение. А использовать свободные функции для любых мелочей, включая получение символов по индексу — такое себе удовольствие.
Сишные строки это не строки, а обёртки вокруг char traits по сути
В современных языках (включая перл, лол) есть понятие "символ", коий связан с кодпоинтом, и не зависит от кодировки.
из таких символов можно составлять строки.
А std::string ведь по сути и есть вектор чаров, только он знает про null в конце и умеет c_str генерить. Ну и наверное имеет всякие коснтрукторы типа иплисит из строкового литерала... или вектор тоже может?
std::string просто няявно добавляет \0 в конец и не считает его в size(). Поэтому c_str() в современных крестах ня нужен, достаточня простого data(), как и во всех остальных протяжённых контейнярах.
У вектора нят перегрузок под литералы, но это можня легко исправить каким-нябудь "#define LITERAL_ITERATOR(x) std::begin(x), std::end(x) -> std::vector(LITERAL_ITERATOR("hello"))". Так, правда, нулевой символ в размер входить таки будет.
data() это принятый среди контрейнеров метод, возвращающий массив, а c_str это специфичный для стринга метод, возвращатющий массив в нулом в конце для интеропа с сишкой. Так ведь?
--чем отличается data и c_str
--тем, что у одного нул в конце
Мой любимый экстракт это вместо
foo(rand());
bar(rand());
писать
baz = rand();
foo(baz);
bar(baz);
прикол в том, что это не синтетика, встречал такое, когда функция с сайд эффектами действительно вынуждает дублировать код, а всё завёрнуто глубоко, и сначала не понимаешь, какого хуя перестало работать после рефакторинга.
В идеальном языке идемпотентные функции должны бы как-нить помечаться, чтобы было сразу понятно можно их так экстрактить, или нет.
В сишке и крестах есть еще такая проблема у различных джавушков, привыкших к тому, что экстрактить можно что угодно (либо ссылка скопируется, что нестрашно, либо примитив типа int, что тоже не страшно)
Не в тему, но я люблю когда функция с префиксом "bool Is..." на самом деле не конст, и с побочным эффектом. Удаляешь её спокойно как неиспользуемую - а потом оказывается багор, она нужна, но без результата.
Кстати, std::string_view — ня самом деле очень хорошая штука; пример того, как забили ня совместимость с сишкой и получили удобную и полезную вещь. А вот если бы попытались сохранить — получилось бы говно.
> можно было сделать еще так
Продлевание жизни — это чрезвычайня опасная и хрупкая конструкция, някому ня рекомендую (см. https://abseil.io/tips/107).
> std::string s(std::string("hello") + std::string("world"));
В современных крестах это оптимальное* решение, лишних копирований ня будет.
*По соотношению "эффективнясть/(читаемость*простота*краткость)". Эффективнее будет взять std::ostringstream, и чем больше строк складывается — тем эффективнее.
> string_view это же просто "окошко" в настоящую строку, как бы ссылка на какой-то рендж внутри нее?
Да. Это указатель + размер.
>https://abseil.io/tips/107
Да, говно) Но справедливости ради, кое-что там тупо не скомпилируется (если const убрать например). Бьёрне явно запретил иметь модифицируемую ссылку на "неведомая временная хуита".
>В современных крестах это оптимальное
ну если компилятор доумкает не делать тут копирования, то вообще отлично
>std::ostringstream
да, но вдеь это не п олучится в одну строку
> ну если компилятор доумкает не делать тут копирования, то вообще отлично
А где тут копирование? После плюса получается временный std::string, он попадает в std::string::string(std::string &&) и спокойня мувается. Вот лишние временные строки создаются, но точня так же, как и в оригиняле.
> Кстати, чем это лучше string с ".append" ?
Только внешним видом (куча << может выглядеть лучше кучи append()).
А по производительнясти оно сосёт: std::ostringstream::str() копирует итоговую строку. Говнодизайн стримов, да.
Кстати, отгадай без доки: как очистить стрим s из твоего примера, чтобы в нём ня осталось строки и можня было записывать новую?
> Да. На кой чорт он возвращает мне string без "const" ??
Оно бы ня помогло. Строка же владеет указателем ня байтики, копировать всё равно придётся.
А вот std::string_view — как раз самое то.
> То есть str() без аргументов копирует строку, а с аргументами заменяет буфер новой строкой?!
Так точня ( ̄▽ ̄)ゞ!
Д — дизайн.
>. Строка же владеет указателем ня байтики, копировать всё равно придётся.
ну хотя бы у меня не было бы соблазна сделать append..
>Д — дизайн.
Я начинаю понимать, почему вы ругаете кресты)
Но я и в коде на других языках постоянно вижу говно в дизайне.
Например есть две реализации абстракций, одна из которых не работает в половине случаев.
Или есть метод, про который половина пользователей думает, что он выполняется на одном конкретном потоке, а другая -- что на любом.
А автор метода вообще не думал про такие вещи.
В крестах хотяб есть cppreference или https://www.cplusplus.com/ (который кстати для менее скилловых питухов даже удобнее, бо там всё разжевано)
А в коде нашего проекта документации может не быть вообще. "Надо просто подебажить", -- говорят коллеги
Ого, не знал. Это не шутка?
В "PHP" так лучше не делать.
1 <?php
2
3 function kok() {
4 return 1;
5 }
6
7 $x = kok();
8
9 $a = &$x;
10 $b = &kok(); //PHP Notice: Only variables should be assigned by reference in /home/fFwofd/prog.php on line 10
В "С++" так тоже лучше не делать. Там надо очень внимательно смотреть, что именно оно продлевает. Шаг влево и UB. Где-то тут кажется уже постили примеры.
Это появилось когда еще не было ни умных компиляторов, ни мувов.
Потому для примера выше реально было бы ненужное копирование.
Чтобы его избежать, стало можно иметь ссылку на временный объект.
Но если разрешить программисту изменять временный объект, то это будет совсем уже говнище, потому сделали такой костыль, чтобы его прочитать его на соседней строчке.
З.Ы. А, ну и да, костыльное няшное наследие с нулл-терминатором же. На векторе оно бы совсем кишками наружу получилось, была бы путаница между размером и длиной. Самое главное отличие строки от вектора в крестах, на самом деле.
Вот да, кресты - результат кривого подкостыливания сишки, который радикально ничего не меняет.
Вот опять-таки строки. Предположим, сделаю я особые царские строки без нуль-терминированной питушни. ну типа
struct uint8_vec
{
size_t len; // в байтах
uint8_t data[]; // сами байтики как https://en.wikipedia.org/wiki/Flexible_array_member
// такой хрени в крестах по стандарту нет кстати, кресты опять обделались
};
И допустим будет у меня некая хуйня, типа new_uint8_vec(size_t len, uint8_t *data) которая делает новый вектор. И есть у меня функция конкатенации двух векторов, возвращающая третий и убирающей оригиналы
struct uint8_vec * vec_uint8_cat(struct uint8_vec * a, struct uint8_vec *b)
{
struct uint8_vec * newvec = xmalloc(a->len+b->len+sizeof(size_t));
newvec->len = a->len+b->len;
memcpy... // байтики из a и b копируем в newvec
memcpy... // лень писать
free(a); free(b);
return newvec;
}
И если я потом воспользуюсь такой хуйней таким вот образом
То тут будет неоптимальная питушня, потому что будет новое выделение памяти на хипе, хотя тут можно было бы realloc()-нуть vec1 до размера a->len+b->len+sizeof(size_t) и туда докопировать хуйни из vec2. А в крестах я как-нибудь могу сделать такую хитрую питушню, чтобы если я делаю vec1 = vec_uint8_cat(vec1,vec2) то чтобы вызывалась такая вот особая функция, которая расширяет vec1 под нужные размеры, а не вызывает тупо vec_uint8_cat?
> то чтобы вызывалась такая вот особая функция, которая расширяет vec1 под нужные размеры, а не вызывает тупо vec_uint8_cat?
Ну так замени у себя в vec_uint8_cat() malloc ня realloc первого вектора. В чём проблема?
Я ничего заменять не хочу. Пусть оно само понимает, что вот раз у меня vec1 = cat(vec1,vec2) то тут надо не вызывать cat а вызвать другую функцию, которая vec1 расширит и туда докопирует vec2
> Крестами такие оптимизации реализовать уже можно?
Конячня. Даже более того, крестами можня статически проверять формат и ня нарываться ня стандартные сишкобаги с перепутанными спецификаторами. https://github.com/fmtlib/fmt
то компилятор бы проанализировал строчку (точнее, AST)
vec1 = vec_uint8_cat(vec1,vec2);
И такой подумал бы "тааак, у нас тут такой-то паттерн, что мы 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), что я и делаю"
Ты хочешь, чтобы компилятор пони-мал, что делает cat(), и что его можня заменить в одном случае ня одно, в другом — ня другое, а в третьем — ня append(), и чтобы это всё ещё и сторонние аллокаторы поддерживало?
Нят, оптимизации, это, конячно, хорошо, но зачем такому компилятору программист?
> Нят, оптимизации, это, конячно, хорошо, но зачем такому компилятору программист?
Например, программист может ма-те-ма-тически описать свойство этого вектора, что это моноид, что вот такие-то операции можно упростить, сократив число аллокаций на хипе
Крестам до такого уровня абстракции как до Юпитера раком
Это имення то, что тебе нужня получить: вторая строка вызывает новую аллокацию, третья — реаллочит s1. Что ня так?
> Крестам до такого уровня абстракции как до Юпитера раком
Это правда. Ня крестах же программируют, а ня упражняются в эзотерике (ну, по большей части).
Разве "s1 += s2" и "s1 = s1 + s2" не откомпилируются в совершенно разную питушню? Я не хочу явно ничего описывать, пусть оно там по каким-то правилам понимает, что "s1 += s2" и "s1 = s1 + s2" это та же фигня. Если видит "s1 = s1 + s2" - пусть компилирует так, как если бы там было "s1 += s2"
> А я ня хочу код писать, хочу, чтобы мне просто деньги платили. И что?
А это тут к чему? Я указываю на отсутствие в крестах нормальных высокоуровневых фич, доказывая тезис "кресты - результат кривого подкостыливания сишки, который радикально ничего не меняет."
> Шаблоны — это нярмальная высокоуровневая фича, радикальня отличающая кресты от сишки.
Нет, шаблоны это не нормальная высокоуровневая фича. Шаблонами нельзя прочитать AST функции и что-то там хитрое на основе этого сделать. Да и вообще, шаблоны задумывались не как хреновина для нормального метапрограммирования, а как достаточно узкая хрень, типа нагенерить функций add() для интов, флоатов, даблов и проч, но какого-то хрена (хотя ясно какого, больше ж не было ничего) их начали юзать для более сложных вещей, придумали какие-то SFINAE, рефлексию на говне и палках... тьфу. Это не нормальная высокоуровневая фича, это какая-то долбанутая срань, взяли какую-то хрень, для нормального метапрограммирования не предназначенную и начали писать какую-то невменяемую по своим масштабам шаблоносрань вперемешку с препроцессором и отдельными хаками для отдельных компиляторов (т.к. в одном компиляторе не работает вот эта часть говностандарта, вот в этом не работает та часть и так далее)
> C++ не предназначался для метапрограммирования шаблонов, но с тех пор, как технология TMP была открыта в начале 90-х годов, она оказалась настолько полезной, что, вероятно, и в сам язык, и в стандартную библиотеку будут включены расширения, облегчающие работу с TMP. Да, TMP было именно открыто, а не придумано. Средства, лежащие в основе TMP, появились в C++ вместе с шаблонами. Нужно было только, чтобы кто-то заметил, как они могут быть использованы изобретательным и неожиданным образом.
Как обычня, вся твоя аргументация сводится к тому, что если ня X няльзя сделать Y, то X — плохо.
Вот только точня такой же риторикой можня "аргументировання" объявить плохим абсолютня что угодня. Ня сишке няльзя сделать свитч по строкам — сишка говно. Ня Хаскелле няльзя сделать мутабельные объекты без "костылей" с монядами — Хаскелль говно. Ня микроконтроллерах няльзя запустить Хром с сотней вкладок "Ютуба" — микроконтроллеры говно. И так далее.
> Ня сишке няльзя сделать свитч по строкам — сишка говно.
Да. Надо чтоб была метасишка с гомоиконами, где можно было б сделать свитч по строкам. Метасишка, расширяемая через особые DSL/EDSL
> Ня Хаскелле няльзя сделать мутабельные объекты без "костылей" с монядами — Хаскелль говно.
Да. Хаскель к тому же имеет жирный рантайм с GC - однозначно говно.
> Ня микроконтроллерах няльзя запустить Хром с сотней вкладок "Ютуба" — микроконтроллеры говно.
Нет, скорее тут Хром и "Ютуб" говно. Ну и обычные микроконтроллеры под такие тяжеловесные задачи не приспособлены. Можно сделать на заводе жирный контроллер со встроенными аппаратными декодерами, который Хром с сотней вкладок "Ютуба" вполне потянет.
> Ну и обычные микроконтроллеры под такие тяжеловесные задачи не приспособлены
Имення. Если X ня приспособлен под Y, то единственное, что можня сказать об X — то, что он ня приспособлен под Y.
Поэтому то, что шаблоны ня умеют обрабатывать AST, ня делает шаблоны говном. Это делает их ня умеющими обрабатывать AST.
Говном X делает то, что X плохо выполняет задачу, для которой X преднязнячен.
Няумение играть ня скрипке ня может сделать из Васи плохого программиста. Плохим программистом Вася будет только тогда, когда он ня умеет программировать.
Вот, няпример, std::string — это однознячное говно, потому что это нечто вообще ня обладает методами, специфичными для строки. Оно ня умеет в Юникод, в нём нят всяких сахаров вида endswith()/startswith()/split()/join(), в нём нят методов для работы с капитализацией — это то, что мне реальня потребовалось в последние пару месяцев, и что мне пришлось велосипедить самой (кроме юникода).
А вот шаблоны свою задачу — няписание обобщённого кода — выполняют достаточня хорошо. То, что всякие сумасшедшие ня них пишут интерпретаторы брейнфака и страдают — проблема исключительня сумасшедших.
> А вот шаблоны свою задачу — няписание обобщённого кода — выполняют достаточня хорошо.
Нет. Недостаточно хорошо. Умение читать/писать AST в компилтайме имеет к возможностям написания обобщенного кода достаточно большое отношение, в шаблонах такой фичи нет. Так что на мой скромный взгляд, шаблоны - говно.
Большинство задач, возникающих при няписании обобщённого кода, шаблоны решают хорошо и эффективня. Корнер-кейсы по большей части возникают из-за отсутствия рефлексии/интроспекции, а ня доступа к AST. В реальности как раз доступ к AST мне ня был нужен ни разу, в отличие от.
> Корнер-кейсы по большей части возникают из-за отсутствия рефлексии/интроспекции, а ня доступа к 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?
Какой смысл использовать переусложнённый инструмент для решения простой задачи? Ты AST структур будешь ручками парсить, вместо простого "getFields<struct X>"?
> Если тебе конкретно не нужен, это не значит что не нужен вообще.
Нят, это знячит, что он ня нужен среднестатистической программистке ня крестах.
> Вот допустим по биному Ньютона можно получить
И дальше пошли абсолютно синтетические задачи, как обычня.
> Как это решить без доступа в AST и возможности его перестраивать по месту?
Профилируешь, видишь, что тут боттлнек, переписываешь формулу.
> И дальше пошли абсолютно синтетические задачи, как обычня.
Возьми сложную математическую либу с кучей формул и сложных вычислений. Такие либы вполне себе существуют. К ним вполне могут быть применимы такие оптимизации.
> Профилируешь, видишь, что тут боттлнек, переписываешь формулу.
А если наиболее оптимальный с т.з. вычислений вариант окажется абсолютно нечитаемым, и по заоптимизированной формуле будет абсолютно неясен ее смысл? А если формула эта не одна, и переписывать их руками самым оптимальным образом - задача крайне сложная для человека?
А если этот боттлнек не в каком-то месте с какой-то формулой, а равномерно размазан по куче таких формул? Или так не бывает?
И все эти либы вполне себе справляются без волшебных модификаций AST.
> А если наиболее оптимальный с т.з. вычислений вариант окажется абсолютно нечитаемым, и по заоптимизированной формуле будет абсолютно неясен ее смысл?
По любой формуле длиннее трёх символов абсолютня ня ясен её смысл, если она ня вынесена в метод с понятным именем.
> А если формула эта не одна, и переписывать их руками самым оптимальным образом - задача крайне сложная для человека?
Для этого существуют специализированные математические пакеты. Ты в своей волшебной либе бигинтов будешь реализовывать всю Wolfram Mathematica?
> А если этот боттлнек не в каком-то месте с какой-то формулой, а равномерно размазан по куче таких формул?
Тогда тебе нужня вбить их все в специализированный математический пакет.
> И все эти либы вполне себе справляются без волшебных модификаций AST.
Можно справляться лучше.
> По любой формуле длиннее трёх символов абсолютня ня ясен её смысл, если она ня вынесена в метод с понятным именем.
Смотря кому. Ма-те-матику может быть и понятно всё.
> Для этого существуют специализированные математические пакеты. Ты в своей волшебной либе бигинтов будешь реализовывать всю Wolfram Mathematica?
А эти специализированные математические пакеты точно заточены на выполнение таких трансформаций, чтобы для пирфоманса было лучше всего? Я вот не очень в этом уверен. Вряд ли Wolfram Mathematica умеет генерить какие-нибудь SIMD-интринсики и как-то хитро подгонять что-то под размер кеша какого-то там проца.
> Можно справляться лучше.
Да нет, вполне достаточня.
> Смотря кому. Ма-те-матику может быть и понятно всё.
А крутому математику и оптимизированная формула будет понятня.
> SIMD-интринсики
Ты нячал с бинома Ньютона, а теперь уже говоришь про интринсики. Но если уж ня то пошло, то няд оптимизациями такого уровня в gcc&clang бьётся огромное количество опытнейших программистов, и то до сих пор как-то ня очень получается. Ты всерьёз считаешь, что автор очередной велолибы для бигинтов сможет осилить качественную оптимизацию сложнее бинома Ньютона, которая ня только будет что-то оптимизировать, но ещё и ничего ня сломает?
> А крутому математику и оптимизированная формула будет понятня.
Нет, математик вряд ли знает что-то про SIMD-интринсики.
> Ты нячал с бинома Ньютона, а теперь уже говоришь про интринсики.
Я нигде не утверждал, что речь идет только про бином Ньютона. Это был просто базовый пример. Без доступа к AST в рамках языка никакой подобной компилтайм-трансформации/оптимизации кода не сделать вообще, хоть там бином, хоть не бином. Обычные математические пакеты, типа вольфрам математики - они под оптимизирующие трансформации не затачивались, так что для решения таких задач нужно будет что-то специализированное городить.
> Ты всерьёз считаешь, что автор очередной велолибы для бигинтов сможет осилить качественную оптимизацию сложнее бинома Ньютона, которая ня только будет что-то оптимизировать, но ещё и ничего ня сломает?
Я думаю что если набрать толковых математиков-программистов, они вполне смогут сделать хорошую либу для такого рода трансформаций, которая ничего ломать не будет. Можно даже формально доказывать корректность подобных трансформаций через Coq.
> Нет, математик вряд ли знает что-то про SIMD-интринсики.
Ня тот момент речь шла всё ещё про биномы Ньютона, но да, про интринсики он ня зняет.
> Я думаю что если набрать толковых математиков-программистов, они вполне смогут сделать хорошую либу для такого рода трансформаций, которая ничего ломать не будет.
Да, а если нябрать толковых экономистов-программистов, то можня построить коммунизм.
У тебя есть примеры таких либ в языках с гомоиконностью/доступом к AST?
> 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 и что-то там трансформировать
A new method is proposed and carried out in SOAP that performs general numerical
program transformation for the trade-off optimization among accuracy, and two resource
related metrics, LUT and DSP utilizations. To optimize a numerical program, it starts by
abstracting the program into a MIR, which we designed to extract the essence of executing
the program, and removes unnecessary informations such as temporary variables,
interleaving of non-dependent statement, etc. The MIR is then optimized efficiently by
discovering a wide range of equivalent trade-off implementations of the original MIR.
An optimized MIR can then be chosen to be translated into a numerical program.
В этой работе авторы используют подход "шланга": компилирует код (очень ограниченное подмножество сишки) в "metasemantic intermediate representation", оптимизируют его, после чего "раскукоживают" обратня в код. Причём, что интересно, весь код для оптимизации у них няписан ня Python, потому что ня Python писать подобные высокоуровневые преобразования очень удобня.
> Our goal is to develop a framework will allow to perform of source code transformations based on performance analysis tools metrics.
Гомоиконность/доступ к AST для этой работы вообще никак ня релевантны.
> Existing Tools
А где здесь библиотеки? Это просто либо компиляторы, либо standalone утилиты, работающие с IR. Как им поможет доступ к AST изнутри языка?
> Это какие-то утилиты для инструментации промежуточного кода типа джавьего ломбока и AspectJ и типа того, как ябло в llvmный код добавляло ARC?
Это можно и для инструментации, и для оптимизации. Например, 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:
Тебе нужен пример, библиотеки, которую можно таким методом заоптимизировать? Или тебе нужен пример библиотеки, где официально сами разработчики применяют некие 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 и багов в компиляторе. Они делают программу быстрее, но поведение не меняется. Это смешно?
> А этот IR откуда берется? Случайно не из AST?
Почитай работу, откуда он там берётся. Но это, разумеется, совершення няважно, потому что в итоге авторы манипулируют не AST, а IR. Возможня, потому что умным дяденькам и тётенькам манипуляция AST няпрямую показалась слишком сложной.
> Почему Clang-LLVM и GCC еще не переписали на питон?
А почему утилита по твоей ссылке няписана на Питоне?
> Так понятно что баги есть даже в компиляторах, и что?
То, что ты тут размахиваешь либой, которая гарантирует няприкосновенность кода. В реальнясти такую гарантию может дать только либа, которая побайтово копирует код из одного файла в другой.
> Так ведь даже компиляторы C/C++
Проблема в том, что скинутая тобой либа нямерянно меняет поведение программы. Если бы оня это делала неявня, через AST — программисту было бы очень весело.
> и без дебаг-инфы там тоже все сложно будет.
Да. Проблема в том, что после работы твоей волшебной либы, перемешивающей AST, ня поможет даже дебаг-инфа.
> Именно так и работают флаги оптимизации у всяких разных компиляторов, если нет UB и багов в компиляторе. Они делают программу быстрее, но поведение не меняется.
Только вот проблема в том, что существенная часть ошибок в коде ня C/C++ — это имення UB. И даже сейчас UB может приводить к очень странным и трудно отлавливаемым багам. А твоя волшебная либа только ухудшает ситуацию.
> Но это, разумеется, совершення няважно, потому что в итоге авторы манипулируют не AST, а IR.
А что если на каком-то этапе AST == IR и трансформации в таком абстрактном представлении где-то происходят? Или так не может быть?
> А почему утилита по твоей ссылке няписана на Питоне?
Ну хз, можно у автора спросить. Если что, могу дать другие ссылки на другие утилиты, которые написаны не на питоне.
> В реальнясти такую гарантию может дать только либа, которая побайтово копирует код из одного файла в другой.
Нет. Для начала надо формально доказать, что компилятор, который собирал эту либу, всё правильно скомпилировал, а еще что космическое излучение не повлияло на процесс, и что в процессоре нет аппаратных багов и еще куча всего можно понапридумывать.
> Проблема в том, что скинутая тобой либа нямерянно меняет поведение программы.
И что? Некоторые оптимизации тоже вполне намеренно меняют поведение программы. Например, -funsafe-math-optimizations
> Да. Проблема в том, что после работы твоей волшебной либы, перемешивающей AST, ня поможет даже дебаг-инфа.
Ну это смотря как устроена эта дебаг-инфа, там это всё можно как-нибудь учитывать, что такой-то преобразованный код соответствует такому-то непреобразованному. Еще можно попробовать эту дебаг-инфу как-нибудь перевести в такую форму, чтоб эта дебаг-инфа выглядела так, как если бы перестройки AST не происходило вовсе.
> А ты ведь манипуляции над AST хочешь юзать для новых фич языка и т.п.
Если нужно новые фичи языка добавлять, не имеет смысла говорить о "неизменении наблюдаемого поведения" т.к. расширенный язык (условно говоря C++) не скомпилируется компилятором нерасширенного языка (условно говоря компилятором C). И никакого наблюдаемого поведения у некомпилирующейся программы нет, так что постановка вопроса некорректна.
Да, но это ведь не означает, что можно нагенерить хуйни и юзер будет доволен.
Это скорее означает, что "простой" вариант с сохранением поведения тут не катит. И придётся как-то формализовывать эту фичу, описывать её взаимодействие с другими. Ну, то чем сейчас и занимаются комитеты. Только из-за зоопарка этих библиотек-расширений багов в реализации и недочётов в спеке будет на порядок больше.
> Программист должен видеть, что получилось ня выходе, иняче его ждут незабываемые часы отладки.
А часто ли программист должен смотреть ассемблерный выхлоп из компилятора? Ну там ведь тоже куча всяких сложных трансформаций происходит, что-то куда-то заинлайнивается, loop-invariant code motion всякие происходят, loop unswitching, т.е. вместо кода типа
int i, w, x[1000], y[1000];
for (i = 0; i < 1000; i++) {
x[i] += y[i];
if (w)
y[i] = 0;
}
компилятор где-то в каком-то абстрактном говнопредставлении перетрансформирует это в
int i, w, x[1000], y[1000];
if (w) {
for (i = 0; i < 1000; i++) {
x[i] += y[i];
y[i] = 0;
}
} else {
for (i = 0; i < 1000; i++) {
x[i] += y[i];
}
}
И потом компилятор это еще и наанроллит. Обязательно ли это все видеть?
> А часто ли программист должен смотреть ассемблерный выхлоп из компилятора?
Так в том-то и проблема, что вообще каким-либо образом отлаживать программу с покорёженным AST практически нявозможня. Потому что после изнясилования AST у тебя будет выполняться совершення ня то, что няписано в коде. И твои ошибки будут преобразовываться до няузнаваемости. А уж если в "оптимизирующей либе" будет баг...
> программист должен смотреть ассемблерный
примерно один раз в никогда и только если очень хочется сделать микрооптимизацию приколоченную к платформе
иначе не нужна эта якобы портабельная крестушня
Я баловался с TH и написал в прод несколько питушень с трансформацией AST на Erlang, и могу сказать, что метушня — это совсем не весело.
Вместо проблем у тебя появляются метапроблемы.
И если не делать трансформации AST с помощью сахарка в языке (квазицитирования и сплайсов, как в TH), то через месяц читать свой мета-код становится очень интересно.
В списке требований MELPA (репа для elisp-пакетов) есть требование не юзать, сука, макросы без нужды.
Так что даже лисперам лень в чужих говноиконах копаться.
> Крестовые шаблоны не порождают новый код и не удаляют старый. Они просто раскрываются.
И при раскрытии могут порождать некий новый код? Вот например компилтайм-либа крестов для PCRE https://github.com/hanickadot/compile-time-regular-expressions - она что, ничего не порождает? Что вообще значит "порождает новый код"? BOOST_PP_REPEAT порождает или не порождает новый код? А что тогда порождает?
Не порождает. Исходный код всех функций написан заранее, из них просто собирается дерево. Если пробежаться по коду в отладчике (с выключеной оптимизацией, само собой), то помимо функций из этой библиотеки ты ничего нового не увидишь.
Нету там каких-то волшебных гомоикон, которые создают код из воздуха или что-то в нём меняют. И к счастью и к сожалению.
> Не порождает. Исходный код всех функций написан заранее, из них просто собирается дерево.
Демагогия какая-то. Следуя такой логике, тогда и обычный компилятор ничего не порождает, когда компилирует что-то из кода на Си в инструкции процессора. Ведь код компилятора написан заранее, компилируемый компилятором код написан заранее, из компилируемого кода собирается какое-то дерево и потом по каким-то известным правилам во что-то трансформируется.
В крестах через шаблоны вполне можно написать некий недокомпилятор, чтобы некая шаблоносрань принимала в себя строку, каким-то образом ее парсила и раскрывалась в некую хрень. Чем бы это на фундаментальном уровне отличалось от обычного компилирования?
Если провести аналогию с функциональщиной, крестовые шаблоны -- это просто композиция существующих крестовых функций, каждую из которых я могу прочитать в исходнике.
В отличие от макросов, которые могут что угодно высрать и наконкатенировать. В отличие от трансформаций AST, которые делают новые функции и структуры, которых в моём исходнике нет.
> Если провести аналогию с функциональщиной, крестовые шаблоны -- это просто композиция существующих крестовых функций, каждую из которых я могу прочитать в исходнике.
И что? Ну вот есть допустим некий крестовый шаблон, возьмем простейший вариант, без всякой сложной метушни
template <typename T>
T add_crap (T a, T b)
{
return a + b;
}
И где-то я использую эту хрень таким образом
auto func_ptr = add_crap<int>;
Отчего бы мне не считать, что делая подобную хрень, я автоматически генерирую (порождаю) где-то функцию типа
Ну можно и так считать... Тут важно, что double add_crap_foobar(int a, float z) { return pow(a, z); } он никогда не сгенерит из того шаблона. С этим ты согласен?
> тебя просят показать пример либы в языке с доступом к аст где это дало какую-то полезную оптимизацию типа той что ты описываешь.
Сейчас, увы, нет широко используемых и достаточно низкоуровневых языков с доступом к AST в компилтайме, чтобы там такая оптимизация была реально полезной.
> Ты AST структур будешь ручками парсить, вместо простого "getFields<struct X>"?
Будут либы, которые напрямую работают с AST, и делая условный "getFields<struct X>" я как раз буду такую либу использовать. Но чтоб такие либы написать, нужен доступ к AST.
Подход "дайте программистам удочку, а они сами няделают либы ня все случаи жизни" в реальнясти, увы, ня работает. Посмотри, во что превратился nodejs + npm.
> Подход "дайте программистам удочку, а они сами няделают либы ня все случаи жизни" в реальнясти, увы, ня работает. Посмотри, во что превратился nodejs + npm.
А что получилось в C/C++? Полуработающий Conan, в котором хрен чего найдешь, и поэтому один фиг надо ходить по гитхабу с черным мешком для мусора и собирать в него нужные говнолибы? Это лучше?
> Большинство задач, возникающих при няписании обобщённого кода, шаблоны решают хорошо и эффективня.
Я вот кстати посмотрел такую либу https://github.com/hanickadot/compile-time-regular-expressions - это вот регулярки через шаблоны в компилтайме, с запиленным в компилтайме LL(1) анализатором на шаблонах. И там еще вот такая генеренная шаблонная хрень из какого-то DESATOMAT
// https://github.com/hanickadot/compile-time-regular-expressions/blob/main/include/ctre/pcre.hpp
using _others = ctll::neg_set<'!','"','$','\x28','\x29','*','+',',','-','.','/',':','<','=','>','?','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','a','b','c','d','e','f','g','h','0','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\x7B','|','\x7D','1','2','3','4','5','6','7','8','9'>;
static constexpr auto rule(s, ctll::term<'\\'>) -> ctll::push<ctll::anything, backslash, repeat, string2, content2>;
static constexpr auto rule(s, ctll::term<'['>) -> ctll::push<ctll::anything, c, repeat, string2, content2>;
...
Да, нагенерить километры какой-то шаблонной хрени это прямо вот "хорошо и эффективно". На кой вообще делать кодогенерированную компилтайм-либу на шаблонах которая генерит регекспы в компилтайме, если сами регекспы можно сразу кодогенерировать?
Вот например есть задача https://govnokod.ru/27403#comment626280 которая средствами внутри крестов вообще никак не решается, даже в самом-самом последнем говностандарте, и решается только какими-то внешними костылями-препроцессорами. Означает ли это, что кресты - говно? А что должно означать?
> Означает ли это, что кресты - говно?
Нязвать язык программирования говном можня только после обширного анялиза его нядостатков. То, что кресты ня могут решить эту задачу, ознячает лишь то, что они ня могут решить эту задачу (хотя в принципе, конячно, кресты — говно, с этим никто ня спорит).
Простыми словами: я купила машину, а в машине нят прикуривателя. Ознячает ли это, что машина — говно?
Может если я куплю молоток, забью им пару гвоздей и он после этого нахрен сломается, то молоток не говно, это просто он так хреново устроен, малый ресурс забивания гвоздей?
https://ru.wikipedia.org/wiki/Парадокс_кучи Парадокс говна («Говно», «Моча») — логический парадокс, сформулированный Евбулидом из Говнокода (IV век до н. э.)[1], связанный с неопределённостью предиката «быть говном»[2].
Слишком малый ресурс при слишком высокой цене — конячно, говно. А что такое малый ресурс и что такое высокая цена — тут уже каждый решает для себя.
А зачем мне надо выбирать, писать "x += y" или "x = y + z"? Ведь вполне может быть так, что из каких-то там шаблонов или макросов или смеси шаблонов и макросов раскрывается такая вот фигня вида "x = x + y" и мне надо чтоб оно там само это нашло и переписало в "x += y" для максимального пирфоманса.
> А зачем мне надо выбирать, писать "x += y" или "x = y + z"?
Чтобы ясно выразить, что в первом случае ты хочешь сразу модифицировать x, а во втором — снячала сложить, а потом записать в x.
> Ведь вполне может быть
Ни разу ня видела таких шаблонов. Приведи пример из реального проекта, в котором такая оптимизация могла бы улучшить производительность.
> А если я хочу получить нужный мне конечный результат максимально эффективным образом, а что оно там сначала и что потом делает - меня не волнует?
Тогда ты используешь только +=.
> Лично я таких проектов не знаю. Искать лень.
И я ня зняю. И с учётом крайней оторванности этой задачи от реальности — скорее всего, если такие проекты и есть, то встречается няобходимость в этом "автосворачивании операторов" раз на миллиард sloc.
Дык нет в крестах "синтеза кода откуда-то". Весь код уже написан тобой. Просто параметризуется немножко. Поэтому либо ты сам уже написал a += b либо там всегда и будет c = a + b, которое никуда не преобразовать.
Препроцессор с условием просто высрет это условие в код. Он же просто токенами ворочает. А условие, если оно не constexpr, будет выполнено уже в рантайме.
З.Ы. А #ifdef внутри макроса нельзя юзать, если ты о нём.
Тока аллока был необязателен, а vla уже стал частью стандарта.
В C99 появился.
А вот в C89 (который был и в bolrand c++ 3) мало того, что не было VLA, так еще и все локальные переменные нужно было декларировать в начале тела функции.
То есть размер стекфрейма функции компилятор всегда мог посчитать перед началом функции.
Кcтати, а в С++ вместо VLA принято использовать vector, который всё хранит в куче? Или он может как-то читерить, и хранить на стеке через alloca?
То есть всё равно посчитал всё место, какое ему может понадобиться в любом из ветвлений, и отожрал стека, а потом, возможно, часть отожранного стека не юзал?
Это практически то же самое, что просто собрать все декларации, так как если бы они были написаны в начале функции, только синтаксически разрешить писать их не в начале, или я не прав?
#include <random>
void foo() {
int i = rand();
if (i % 100500) {
long int a = 1, b = 1, c = 1, d = 1;
int q = 0;
a += 2;
printf("neg %d %d %d %d", a,b,c,d);
} else {
double b = 1.0;
b += 2.0;
printf("pos %f", b);
}
}
получишь
sub rsp, 80
Единственный плюс "нового" подхода это ограничение видимости. Оно позволяет иметь "b" внутри каждой веточки своё.
Ну и вероятно деструкторы должны вызываться в случае С++.
Забавнее посомтреть что будет, если крутить стек в рантайме
VLA
int i = rand();
int j[(int)i];
начинаются игрища с стек поинтером
imul rax, rax, 16
sub rsp, rax
mov rax, rsp
Удивительно другое!
Я заказал "-fomit-frame-pointer" чтобы посмотреть как питух будет изъебываться адресовать переменные от SP, которого он постоянно дрочит.
А он взял, и положил на эту опцию, и продолжил юзать BP.
При этом если сделать код без VLA, то -fomit-frame-pointer отключает BP, и переменные начинают адресоваться от SP.
Иными словами, FPO значит не "запрещаю тебе юзать BP" (как я до сего момента думал), а означает "разрешаю тебе не юзать BP, если хочешь"
А компилятор такой: ой, ну если бы ты не трогал SP в рантайме, то я бы воспользовался твоим предложением, а так засунь себе FPO в жопу, а я буду продолжать адресовать переменные на стеке от BP
> значит не "запрещаю тебе юзать BP"
Ну да, абсолютное большинство "оптимизирующих" опций — это рекомендации, а ня законы (прямо как Кодекс в PoTC \(★ω★)/).
Напоминает "record case" или variable records в паскале.
Там можно объявить запись с вариантами разблядовки типов, например
Type
Sex = (baba, mojeek);
Hair = (lysy, volosaty);
Chelovek = Record
age: Integer;
hair: Hair,
case Sex of
baba: (razmer_sisek: Integer, ebalo: Kartinka);
mojeek: (zarplata: Double, dlinna_huya: Byte);
end;
В итоге сайзоф такой записи будет исходя из размера самого ресурсоёмкого case, но не всей их суммой. Все case замапятся в одно и то же место в памяти и гарантированно влезут. В данном примере попытавшись изменить razmer_sisek у записи можно поломать его значение zarplata, потому что предполагается что юзаться кейсы должны независимо. Компилятор за этим не следит, ты сам в коде должен определить для себя, какой тебе от этой записи нужен кейс. Таким образом можно знатно сэкономить на спичках.
Ну вот ты компилятор.
Если ты в начале функции ты видишь все её перменные, то ты просто двигаешь stack pointer на нужное количество байт, и потом можешь их от него адресовывать.
Закончилась функция -- ты его обратно подвинул.
А если у тебя по ходу пьесы стек двигается на вычисляемое в рантайме количество байт (alloca, vla, или if (petuh) {int i..}, то тебе нужно как-то в рантайме понимать какого размера твой стек, и как это обратно всё потом двинуть, когда функция закочнится.
Наверное хорошо, если у тебя есть FramePointer (BP) который указывает на начало функции, от него можно хотя-бы наверное переменные адресовывать, а если нет?
Короче, написать такой компилятор труднее.
Так вижу. Но может дело и не в этом..
Алсо, стек (особенно во времена c89) было СОВСЕМ не резиновый. 16 килобайт или около того был он в паскале
Макросня работает на уровне токенов. Можешь считать её скриптом на PHP, который просто что-то там в тексте правит и копипастит. А в языке она ничерта не смыслит, ни в сишке ни в крестах.
Это-то я понимаю, просто те полтора часа своей жизни, что я имел дело с реальным кодом на си, оставили у меня впечатление, что макрос с ифом может по условию превратиться либо в один код, либо в другой, и на уровне токенов делать подмену. Про то что она умеет срать на уровне токенов реалтаймовыми условиями я не ведал.
Не, там вообще всё тупо. Аргументы он может подставлять, конкатенировать и превращать в строковый литерал. В общем-то и всё. Никаких других операций над ними нет (хотя в бусте выебнулись и сделали на основе этого арифметику и функциональщину, лол).
Т.е. про == и if шаблонизатор ничего не знает, как PHP ничего не знает про <div>. Поэтому он их дословно копирует на выход.
Ага, ну значит правильно ты #ifdef помянул, из-за него у меня такое впечатление и сложилось. Заебись, и он ничего не выберет, поставит как есть, а дальше уже компилятор либо оптимизнет константное условие, либо вкомпилит рантаймовое как есть. Ясно понятно.
Есть общий кодстайл для всей компании. Но ты не обязан его придерживаться, в свой проект можно коммитить любое говно. В нашем проекте 3 разработчика, и мы уже между собой договариваемся чокак, но дополнительного кодстайла у нас как такового нету, есть несколько устных договорённостей нигде не закреплённых )
Ну про конст, имхо, есть смысл доебаться в джвух случаях где он пиздец как важен:
- const справа от функции
- 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
Потому что ты не умеешь его читать. Я думаю с опытом он нормально воспринимается.
А вот все эти bind2nd -- устаревшее говно, конечно. Для тривиальных случаев есть универсальный bind, в котором сразу понятно что куда попадёт. А для более сложных можно лямбду или функцию написать.
А теперь представь, что вокруг тебя математики, которым эти векторные операции и функции высшего порядка гораздо ближе, чем циклы. Для них J будет читаться не хуже обычных формул.
Нет, потому что там есть ебаная lambda. Чем lambda с двоеточием лучше стрелочной функции понять трудно, обычно таким макаром дизайнеры языка как раз помечают места, которые не предполагается сильно абьюзить. Зразу типа замечаешь, что код вербозный. То есть для питона лямбды - это так, просто чтобы было, блять.
Ну вот лист компрехеншоны пиздатые, это питонизм знатный. Они может и не самые удобные, зато в одном стиле с отстальным языком, заебись. Выражены теми ключевыми словами, что уже есть, без спецсимволов и йухни.
Компрехеншены в общем-то ничего нового не дают, разве что пару строчек на out = [] да out.append(x) экономят (ну или yield x). Это даже не функциональщина, банальный императивный цикл, немножко посыпанный сахарком.
В общем это всё говёное говно, конечно.
Мне нравятся цепочки, которые есть в руби и в груви и частично в JS и в котлине и даже можно изъбнуться в перле.
А только в питоне принято всё расписывать вручную, потому что цепочек нет
Ну это тоже не функциональщина... Где здесь превращение do_all, который обрабатывает один элемент во что-то большее, что умеет обрабатывать много? А это важно для композиции, к примеру. Чтобы я мог связать несколько таких функций в один конвейер.
Как ты в твоём синтаксисе запишешь (map do_all) . (filter (> 42)) . (map preprocess)?
Но всё равно немного не то, конечно... Нету композябельности, нельзя заюзать эти операции как лего, собирая из мелких кубиков что-то интересное.
Т.е. в примере из хаскеля я могу добавить ещё какие-то фильтры и преобразования. Или даже сделать функцию, которая эти фильтры навешивает по параметрам. А потом запустить список на обработку получившейся функцией. Вот в чём суть труъ функциональщины.
А в примере из руби я просто выполняю одну операцию над списком. А потом выполняю вторую. Скукотища.
ну я тоже могу собрать, а потом запустить, хотя конечно это не так красиво
class Enumerator
def first_two
first 2
end
def cap
map(&:capitalize)
end
end
def sobral_prover(en)
en.cap.first_two
end
foo = %w[Once there was a captain brave].freeze.lazy
bar = (0..1000).lazy.map(&:to_s)
puts sobral_prover foo
puts sobral_prover bar
//вот есть пайп
const anotherPipe = pipe(map<number, string>(n => `Num: ${n}`));
function createSuperPipe(): UnaryFunction<Observable<number>, Observable<string>> {
return pipe(
filter<number>(n => n % 2 === 0),
filter(n => n > 7),
map<number, number>(n => n * 10),
anotherPipe); //вот я его пихнул в другой пайп
}
Верно: внутрь pipe я могу пихнуть свою функцию, ведь filter и map это обычные функции, я могу такую же написать.
Таких функций офердохуя, кстати: есть tap для сайдэффектов, например)
Я попытался принести RxJava к нам в проект (полагаю, там тоже самое), но мне сказали юзать котлиновские корутины и ченнелы.
А там всё таки императивщина: если ты хочешь из одного ченела в другой переложить, то ты должен писать цикл (хотя он и будет конечно ленивый, ибо suspendable функция)
З.Ы. Вот напиши, к примеру, чтобы реверс можно было включать и отключать. Тебе для этого придётся разорвать цепочку и въебать иф.
Или попробуй написать функцию, которая настраивает фильтры, а потом отдаёт эти фильтры в другую функцию, которая уже будет обрабатывать список. Не получается, выглядит как говно? А ведь это вполне практическая задачка, на которой императивные языки просто сосут.
Ты не можешь клеить куски этой цепочки во что-то более интересное, ты можешь только применять их к списку по одному за раз.
А оно и прибиндится. У крестовых функций высшего порядка есть перегрузки для указателей ня методы, так что и bind, и invoke, и apply прекрасно понимают this.
struct X {
int x;
void foo()
{
std::cout << "X(" << x << ")::foo()" << std::endl;
}
std::function<void()> get_callback()
{
return std::bind(&X::foo, this);
}
};
int main()
{
auto x = X(16);
auto f = x.get_callback();
f();
}
Нотификацию может выдать и само приоложение. А оно может получать пуш от эппла или переодически чего-то запрашивать в фоне и рисовать нотификаций
Точно помню, что в одном приложении никакой пуш эппловский не использовался (он имеет смысл когад у тебя 100000 клиентов, когда он один, то можно пулить прямо с сервера)
Там ios нас будило, и мы рисовали нотификацию.
Но как именно работало уже не помню, давно очень было(
Там небось надо было что-то регистрировать у эппла?
Лол, я нашел репу с тем говном)
Там было так:
UIBackgroundModes -> fetch стояло в Info.plist, и потом ios переодически нас будила, и дергала performFetchWithCompletionHandler
ну мы фетчили по http и создавали UILocalNotification
Ну они правда ещё собирают все твои пароли, смс, состояние банковского счета сбербанк онлайн, парсят все что могут, и хранят в гугле или эпл, но вообще да, они экономят батарейку. А ещё иногда падают или приходят неадекватно поздно.
Заставляет, смс я могу получить и на нокиа 3310, и он меня уведомит. Я не уверен до конца, но что-то мне подсказывает, что современное ведро, чтобы издать бздыньк по приходу смс и показать пуш, прогонит хотя бы его урезанный до многоточия текст через гугл сервис.
А приложение умеет без пуш-сервиса просто слать в ведре уведомления? Можно и без енд ту енд, можно вообще не слать ничего никуда, а просто показать уведомление, ведь инициатором-то пуша является часто само твоё же локальное приложение. но гугл с этим борется, насколько я знаю. Чтобы не было нежелательных уведомлений.
Кстати, фетч про который ты выше пишешь, это же тоже походу оптимизация батарейки? Чтобы твой сервис ходил в инет только в положенный таймслот вместе со всеми остальными, а потом девайс нормально спал с отключенной сетью.
Ну это для каких-то больших загрузок, наверное. Когда какая-нибудь игрушка или навигатор хочет скачать гигабайт. Ради сообщений в мессенджере было бы глупо ждать вайфая.
У меня так месячный лимит трафика за день просрался... Сначала убунта обновилась, потом винда, потом стим решил игрушки обновить. Х.з. как народ на мобильном инете сидит.
((там, правда, не роуминг был, а местная симка, но все равно бабки сожрало, с запасом же было положено. И еще не сразу понял, что баланс 0, испугался, что мобильная связь не работает, может, уже все рухнуло и мне возвращаться некуда))
Само по себе нет. В батарейку упрётся если ты сам будешь поллить сервер по своему таймеру. Можешь вообще пустой пуш себе кинуть с сервера, а когда получишь -- забрать полные данные самостоятельно и показать их нотификацией.
> без пуш-сервиса просто слать в ведре уведомления
Эм, да может конечно. У меня даже говнотифи так делало... Борьба с этим очень простая: тычешь в уведомление и говоришь "больше не показывать". И приложение с этим запретом ничего сделать не сможет.
А пуш -- это именно про оптимизацию доставки небольших пакетов от сервера. Ну и если тебе совсем влом пилить сервис -- можешь попросить, чтобы ось сама его показала когда получит. Тут, конечно, шифровать ты его не можешь иначе как ось без твоей помощи покажет.
Смски кстати идут через вендора только если оба телефона от него и интернет есть. От банка скорее всего по-нормальному через опсоса придёт, как на кнопочном.
Для начала перепиши это все на крестах без крестовой стдлибы. Или ты считаешь валидным аргумент типа "язык X лучше языка Y потому что в языке X в стандартной библиотеке реализована хуйня для Z, а в языке X такой хуйни не реализовано"?
Сишка это вообще не про "куча хуйни в стандартной либе", там как раз специально избегали добавлять кучу хуйни.
Когда Ричи хотел внести в 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 и решила свою задачу за десять минут: максимальня быстро и безо всяких поисков нужных либ. Это хорошо и удобня.
Меня ещё радует, что немцы разрешают разрывать сочетание «ck» при переносе строк, но в этом случае заменяют его на «k-k».
Ещё радует, что в турецком «i» переводится в «İ» вместо «I», а в «I» переводится «ı». То есть даже апкейс/лоукейс от «I» и «i» зависит от локали.
В греческом заглавная «сигма» одна (Σ), а строчных две (σ и ς). Вторая используется на конце слов. Т. е. для правильного лоукейса ещё нужно найти границы слов.
Река в единственном числе — Fluß, а во множественном — Flüsse. А ещё «ss» может случайно оказаться на стыке основ (первая заканчивается на «s», а вторая на «s» начинается), когда менять «SS» на «ß» ни в коем случае нельзя.
А ещё бывает мозговзрывающее слово «масштаб» (Maßstab).
- Я так раньше никогда не делала. Мне понравилось. А тебее? - сказала она после того, как я влил в неё свой заряд и, уставший, уселся прямо на ковролин на полу кабинета.
-G
--basic-regexp
Interpret patterns as basic regular expressions (BREs). This is the default.
-E
--extended-regexp
Interpret patterns as extended regular expressions (EREs). (-E is specified by POSIX.)
-F
--fixed-strings
Interpret patterns as fixed strings, not regular expressions. (-F is specified by POSIX.)
-P
--perl-regexp
Interpret patterns as Perl-compatible regular expressions (PCREs). PCRE support is here to stay, but consider this option experimental when combined with the -z (--null-data) option, and note that ‘grep -P’ may warn of unimplemented features. See Other Options.
gologub # 0
какая безысходность )))
Desktop # 0 ⇈
bormand # 0 ⇈
Desktop # 0 ⇈
но кому нужен чупакабр?
gologub # 0 ⇈
на sohabr?
или как там называется куда сохраняют всё, что пидораший Мой Мир удаляет?
bormand # 0 ⇈
gologub # 0 ⇈
bormand # 0 ⇈
gologub # 0 ⇈
знаю только, что политика удалять интересные статьи чтобы не обидеть коллективного Усманова появилась за этот период
j123123 # 0
> Поиск имени по методам (Member name lookup) происходит, когда имя находится справа от токена . или ->, как в foo->bar. Этот тип поиска используется для поиска методов класса.
> Поиск квалифицированного имени (Qualified name lookup) происходит, когда имя содержит токен ::, например, std::sort. Этот тип имени является явным для компилятора. Часть справа от токена :: ищется только в области видимости, обозначенной в левой части.
> Поиск неквалифицированных имён (Unqualified name lookup) не является ни тем, ни другим. Когда компилятор видит неквалифицированное имя, например blast, он ищет совпадающие декларации функций в множестве различных областей в зависимости от контекста. Существует подробный набор правил, который точно определяет, где должен искать компилятор.
Квалифицированные-хуифицированные, понаприрумывали херни всякой. А почему они не сделали какой-нибудь метушни над AST (и чтоб с гомоиконностью), которая б уже использовалась для написания логики для подобного говна? Почему им проще захардкодить набор каких-то ебанутых правил, которые все равно никто нихера не знает, и даже в компиляторах их реализовывать не осиливают?
bormand # 0 ⇈
j123123 # 0 ⇈
Может там им еще сделать чтобы функциям начислялись некие баллы жизнеспособности по некоторым ебанутым говноправилам, и чтоб выигрывала та функция, которая больше баллов набрала?
bormand # 0 ⇈
Лучше заставить их драться в рантайме! Какая пройдёт юнит-тесты и покажет больший пирфоманс -- та и более жизнеспособна.
Desktop # 0 ⇈
MAKAKA # 0 ⇈
Пускай компилятор сам угадывает что я имел ввиду
Зачем заставлять меня думать?!
j123123 # 0 ⇈
bormand # 0 ⇈
JloJle4Ka # 0 ⇈
Джве жизнеспособные функции находятся в центре кода 500х500 строчек, на расстоянии 20 строчек друг от друга. Но поскольку их джве...
Desktop # 0
j123123 # 0 ⇈
Desktop # 0 ⇈
j123123 # 0 ⇈
А надежды у меня такой нет. Стирать память ради осиливания помойных крестов (если б существовала такая технология) я не желаю.
bormand # 0 ⇈
j123123 # 0 ⇈
https://web.archive.org/web/20160320101324/http://www.sql.ru/forum/466654-7/s
> А вот знать C++ обязан каждый. Знать хотя бы для того, чтобы понимать, как делать нельзя. C++ - это идеальная коллекция антипаттернов в дизайне языков программирования.
MAKAKA # 0 ⇈
Каждый раз, когда конкатенирую строки через плюсик или когда реверсирую вектор через std::reverse завидую сишникам
Desktop # 0 ⇈
MAKAKA # 0 ⇈
bormand # 0 ⇈
Бля, т.е. задачи с собеседований не бесполезны?! Зачем тебе это понадобилось, если не секрет?
MAKAKA # 0 ⇈
j123123 # 0 ⇈
Не, это хуета, вот в питоне ты можешь даже умножать строки на число:
разве не охуенно? Шах и мат, крестовики.
JloJle4Ka # 0 ⇈
j123123 # 0 ⇈
Кстати, ни в крестах, ни в питоне нельзя добавлять новые операторы. А в Haskell можно. Там даже можно указывать приоритет и ассоциативность: https://webhamster.ru/mytetrashare/index/mtb339/15559617440umt1hd5us
https://bugfactory.io/blog/custom-infix-operators-in-haskell/
Кресты и питон - говно!
bormand # 0 ⇈
Скукотища. Вон в coq можно объявить себе какое-нибудь s1 =[ cmd ]=> s2.
KoWe4Ka_l7porpaMMep # 0 ⇈
Правда Coq'у он всё равно, наверное, в этом плане уступает.
https://play.nim-lang.org/#ix=3ojq
bormand # 0 ⇈
Оно, конечно, не совсем универсально. Грамматику крестов не запилить, я думаю.
Desktop # 0 ⇈
MAKAKA # 0 ⇈
Если без шуток, то для скриптушни текстообрабатывающей это вполне нормальное желание
vistefan # 0 ⇈
MAKAKA # 0 ⇈
j123123 # 0 ⇈
Вот нахуя есть какой-то https://en.cppreference.com/w/cpp/string/basic_string и какой-то https://en.cppreference.com/w/cpp/string/basic_string_view ? Почему это не какой-то там контейнер, типа std::array или std::vector? Зачем под это какая-то особая сущность? Почему хуйня для строк не является обычным контейнером?
bormand # 0 ⇈
PolinaAksenova # 0 ⇈
Потому что она и должна являться особой сущностью? Или ты хочешь в обычный контейнер добавить методы для работы с символами (всякие там capitalize()/upper() и ня) и поддержку UTF8?
Другое дело, конячно, что в крестовых "строках" всего этого нят: чтобы понять, зачем нужен отдельный тип для строк, лучше посмотреть ня какой-нибудь Python.
bormand # 0 ⇈
Я хочу просто контейнер для байтиков (ну или кодепоинтов), с которым уже работают какие-то алгоритмы.
Вектор тут вполне норм если забить на совместимость с няшной.
PolinaAksenova # 0 ⇈
MAKAKA # 0 ⇈
std::getline vs istream::getline
bormand # 0 ⇈
А оно нинужно... Потому что из-за юникода понятие индекса жутко расплылось и всё равно придётся юзать итераторы с нужной сёмантикой как в icu.
MAKAKA # 0 ⇈
В современных языках (включая перл, лол) есть понятие "символ", коий связан с кодпоинтом, и не зависит от кодировки.
из таких символов можно составлять строки.
А std::string ведь по сути и есть вектор чаров, только он знает про null в конце и умеет c_str генерить. Ну и наверное имеет всякие коснтрукторы типа иплисит из строкового литерала... или вектор тоже может?
PolinaAksenova # 0 ⇈
У вектора нят перегрузок под литералы, но это можня легко исправить каким-нябудь "#define LITERAL_ITERATOR(x) std::begin(x), std::end(x) -> std::vector(LITERAL_ITERATOR("hello"))". Так, правда, нулевой символ в размер входить таки будет.
MAKAKA # 0 ⇈
--чем отличается data и c_str
--тем, что у одного нул в конце
лол)
PolinaAksenova # 0 ⇈
MAKAKA # 0 ⇈
раньше data() возвращала массив чаров (ну или что там в строке) а после него был UB. А теперь там не UB, а гарантированно NULL?
PolinaAksenova # 0 ⇈
MAKAKA # 0 ⇈
guest # 0 ⇈
bormand # 0 ⇈
З.Ы. Емнип, там с пустой строкой основная жопа была, на ней таки можно было соснуть UB'ца.
PolinaAksenova # 0 ⇈
В порядке бреда — держать второй указатель ня нуль-терминированную строку и обновлять его ня каждом вызове c_str().
bormand # 0 ⇈
В порядке бреда можно и прокси-прокладку вернуть из c_str(), которая кастуется в const char* и держит временную нуль-терминированную копию...
PolinaAksenova # 0 ⇈
bormand # 0 ⇈
А ну да, оно же должно жить до следующей модификации, а не до конца стейтмента...
Ну, в порядке бреда можно GC добавить.
MAKAKA # 0 ⇈
Знаете анекдот про c_str кстати?
Было например так
Потом пришел мамки экстрактор, и сделал так
Так мы познакомились с понятием "временный объект, живующий до конца полного выражения", лол
vistefan # 0 ⇈
foo(rand());
bar(rand());
писать
baz = rand();
foo(baz);
bar(baz);
прикол в том, что это не синтетика, встречал такое, когда функция с сайд эффектами действительно вынуждает дублировать код, а всё завёрнуто глубоко, и сначала не понимаешь, какого хуя перестало работать после рефакторинга.
MAKAKA # 0 ⇈
В сишке и крестах есть еще такая проблема у различных джавушков, привыкших к тому, что экстрактить можно что угодно (либо ссылка скопируется, что нестрашно, либо примитив типа int, что тоже не страшно)
vistefan # 0 ⇈
MAKAKA # 0 ⇈
И пусть функции всегда pure, а процедуры всегда const, если явно не помечены как "non_const"
Вот и кеширование станет удобно делать: пока non_const не вызвал, результатат всех функций предсказуем))
В крестах хотя-бы есть const методы, которые как-бы официально обещают не менять состояние объекта (хотя могут наебать, конечно)
В остальном мейнстриме и такого нет
guest # 0 ⇈
PolinaAksenova # 0 ⇈
А потом придёт папкин новатор, скажет, что std::string_view — стильня и модня, и сделает:
Кстати, std::string_view — ня самом деле очень хорошая штука; пример того, как забили ня совместимость с сишкой и получили удобную и полезную вещь. А вот если бы попытались сохранить — получилось бы говно.
MAKAKA # 0 ⇈
можно было сделать еще так
За одно познакомиться с понятием "живительная константная ссылка, продлевающая жизнь временному объекту"
или так
но тут наверное может случиться лишнее копирование
string_view это же просто "окошко" в настоящую строку, как бы ссылка на какой-то рендж внутри нее?
PolinaAksenova # 0 ⇈
Продлевание жизни — это чрезвычайня опасная и хрупкая конструкция, някому ня рекомендую (см. https://abseil.io/tips/107).
> std::string s(std::string("hello") + std::string("world"));
В современных крестах это оптимальное* решение, лишних копирований ня будет.
*По соотношению "эффективнясть/(читаемость*простота*краткость)". Эффективнее будет взять std::ostringstream, и чем больше строк складывается — тем эффективнее.
> string_view это же просто "окошко" в настоящую строку, как бы ссылка на какой-то рендж внутри нее?
Да. Это указатель + размер.
MAKAKA # 0 ⇈
Да, говно) Но справедливости ради, кое-что там тупо не скомпилируется (если const убрать например). Бьёрне явно запретил иметь модифицируемую ссылку на "неведомая временная хуита".
>В современных крестах это оптимальное
ну если компилятор доумкает не делать тут копирования, то вообще отлично
>std::ostringstream
да, но вдеь это не п олучится в одну строку
Кстати, чем это лучше string с ".append" ?
PolinaAksenova # 0 ⇈
А где тут копирование? После плюса получается временный std::string, он попадает в std::string::string(std::string &&) и спокойня мувается. Вот лишние временные строки создаются, но точня так же, как и в оригиняле.
> Кстати, чем это лучше string с ".append" ?
Только внешним видом (куча << может выглядеть лучше кучи append()).
А по производительнясти оно сосёт: std::ostringstream::str() копирует итоговую строку. Говнодизайн стримов, да.
Кстати, отгадай без доки: как очистить стрим s из твоего примера, чтобы в нём ня осталось строки и можня было записывать новую?
MAKAKA # 0 ⇈
точно) я не сообразил, что конструктор вызовется не копирующий, а мувающий, ведь объект-то временный, и больше не нужен.
В рамках этого конструктора string просто заберет себе чужой массив чаров скорее всего
>std::ostringstream::str() копирует итоговую строку
Это совершенно ожидаемо, иначе я бы написал str().append("хуй") и что было бы в стриме?
Вот кстати почему нету обертки для R/O строк?
Было бы удобно возвращать ей.. ну как такой R/O string_view
>как очистить стрим s из твоего примера,
А там нету чего-нить типа clear(), по аналогии со строкой?
PolinaAksenova # 0 ⇈
Ты про стрим? В C++20 там сделали view(), да.
> А там нету чего-нить типа clear(), по аналогии со строкой?
clear() есть. Только он ня поможет ( ̄▽ ̄).
MAKAKA # 0 ⇈
Да. На кой чорт он возвращает мне string без "const" ??
В const авось и append бы не было?
>clear() есть. Только он ня поможет ( ̄▽ ̄).
блядь
clear сбрасывает флаги состояния стрима.
А чтобы очистить стрим нужно... вызвать stringstream::str("") ?!
То есть str() без аргументов копирует строку, а с аргументами заменяет буфер новой строкой?!
PolinaAksenova # 0 ⇈
Оно бы ня помогло. Строка же владеет указателем ня байтики, копировать всё равно придётся.
А вот std::string_view — как раз самое то.
> То есть str() без аргументов копирует строку, а с аргументами заменяет буфер новой строкой?!
Так точня ( ̄▽ ̄)ゞ!
Д — дизайн.
MAKAKA # 0 ⇈
ну хотя бы у меня не было бы соблазна сделать append..
>Д — дизайн.
Я начинаю понимать, почему вы ругаете кресты)
Но я и в коде на других языках постоянно вижу говно в дизайне.
Например есть две реализации абстракций, одна из которых не работает в половине случаев.
Или есть метод, про который половина пользователей думает, что он выполняется на одном конкретном потоке, а другая -- что на любом.
А автор метода вообще не думал про такие вещи.
В крестах хотяб есть cppreference или https://www.cplusplus.com/ (который кстати для менее скилловых питухов даже удобнее, бо там всё разжевано)
А в коде нашего проекта документации может не быть вообще. "Надо просто подебажить", -- говорят коллеги
bormand # 0 ⇈
Это в копилку к erase, remove и empty.
guest # 0 ⇈
Ого, не знал. Это не шутка?
В "PHP" так лучше не делать.
bormand # 0 ⇈
В "С++" так тоже лучше не делать. Там надо очень внимательно смотреть, что именно оно продлевает. Шаг влево и UB. Где-то тут кажется уже постили примеры.
MAKAKA # 0 ⇈
Это появилось когда еще не было ни умных компиляторов, ни мувов.
Потому для примера выше реально было бы ненужное копирование.
Чтобы его избежать, стало можно иметь ссылку на временный объект.
Но если разрешить программисту изменять временный объект, то это будет совсем уже говнище, потому сделали такой костыль, чтобы его прочитать его на соседней строчке.
guest # 0 ⇈
guest # 0 ⇈
bormand # 0 ⇈
PolinaAksenova # 0 ⇈
j123123 # 0 ⇈
Вот опять-таки строки. Предположим, сделаю я особые царские строки без нуль-терминированной питушни. ну типа
И допустим будет у меня некая хуйня, типа 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?
PolinaAksenova # 0 ⇈
Ну так замени у себя в vec_uint8_cat() malloc ня realloc первого вектора. В чём проблема?
j123123 # 0 ⇈
PolinaAksenova # 0 ⇈
j123123 # 0 ⇈
А что насчет такого типа оптимизаций http://www.ciselant.de/projects/gcc_printf/gcc_printf.html ?
Крестами такие оптимизации реализовать уже можно?
PolinaAksenova # 0 ⇈
> Крестами такие оптимизации реализовать уже можно?
Конячня. Даже более того, крестами можня статически проверять формат и ня нарываться ня стандартные сишкобаги с перепутанными спецификаторами.
https://github.com/fmtlib/fmt
j123123 # 0 ⇈
Хочу чтобы если у меня
то компилятор бы проанализировал строчку (точнее, 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), что я и делаю"
Зачем тут какие-то "методы"?
PolinaAksenova # 0 ⇈
Нят, оптимизации, это, конячно, хорошо, но зачем такому компилятору программист?
j123123 # 0 ⇈
Например, программист может ма-те-ма-тически описать свойство этого вектора, что это моноид, что вот такие-то операции можно упростить, сократив число аллокаций на хипе
Крестам до такого уровня абстракции как до Юпитера раком
PolinaAksenova # 0 ⇈
Это имення то, что тебе нужня получить: вторая строка вызывает новую аллокацию, третья — реаллочит s1. Что ня так?
> Крестам до такого уровня абстракции как до Юпитера раком
Это правда. Ня крестах же программируют, а ня упражняются в эзотерике (ну, по большей части).
j123123 # 0 ⇈
PolinaAksenova # 0 ⇈
> Я не хочу явно ничего описывать, пусть оно там по каким-то правилам понимает
А я ня хочу код писать, хочу, чтобы мне просто деньги платили. И что?
j123123 # 0 ⇈
А это тут к чему? Я указываю на отсутствие в крестах нормальных высокоуровневых фич, доказывая тезис "кресты - результат кривого подкостыливания сишки, который радикально ничего не меняет."
PolinaAksenova # 0 ⇈
Шаблоны — это нярмальная высокоуровневая фича, радикальня отличающая кресты от сишки.
j123123 # 0 ⇈
Нет, шаблоны это не нормальная высокоуровневая фича. Шаблонами нельзя прочитать AST функции и что-то там хитрое на основе этого сделать. Да и вообще, шаблоны задумывались не как хреновина для нормального метапрограммирования, а как достаточно узкая хрень, типа нагенерить функций add() для интов, флоатов, даблов и проч, но какого-то хрена (хотя ясно какого, больше ж не было ничего) их начали юзать для более сложных вещей, придумали какие-то SFINAE, рефлексию на говне и палках... тьфу. Это не нормальная высокоуровневая фича, это какая-то долбанутая срань, взяли какую-то хрень, для нормального метапрограммирования не предназначенную и начали писать какую-то невменяемую по своим масштабам шаблоносрань вперемешку с препроцессором и отдельными хаками для отдельных компиляторов (т.к. в одном компиляторе не работает вот эта часть говностандарта, вот в этом не работает та часть и так далее)
> C++ не предназначался для метапрограммирования шаблонов, но с тех пор, как технология TMP была открыта в начале 90-х годов, она оказалась настолько полезной, что, вероятно, и в сам язык, и в стандартную библиотеку будут включены расширения, облегчающие работу с TMP. Да, TMP было именно открыто, а не придумано. Средства, лежащие в основе TMP, появились в C++ вместе с шаблонами. Нужно было только, чтобы кто-то заметил, как они могут быть использованы изобретательным и неожиданным образом.
PolinaAksenova # 0 ⇈
Вот только точня такой же риторикой можня "аргументировання" объявить плохим абсолютня что угодня. Ня сишке няльзя сделать свитч по строкам — сишка говно. Ня Хаскелле няльзя сделать мутабельные объекты без "костылей" с монядами — Хаскелль говно. Ня микроконтроллерах няльзя запустить Хром с сотней вкладок "Ютуба" — микроконтроллеры говно. И так далее.
Обсирать что-то правильня и по делу — сложно.
j123123 # 0 ⇈
Да. Надо чтоб была метасишка с гомоиконами, где можно было б сделать свитч по строкам. Метасишка, расширяемая через особые DSL/EDSL
> Ня Хаскелле няльзя сделать мутабельные объекты без "костылей" с монядами — Хаскелль говно.
Да. Хаскель к тому же имеет жирный рантайм с GC - однозначно говно.
> Ня микроконтроллерах няльзя запустить Хром с сотней вкладок "Ютуба" — микроконтроллеры говно.
Нет, скорее тут Хром и "Ютуб" говно. Ну и обычные микроконтроллеры под такие тяжеловесные задачи не приспособлены. Можно сделать на заводе жирный контроллер со встроенными аппаратными декодерами, который Хром с сотней вкладок "Ютуба" вполне потянет.
PolinaAksenova # 0 ⇈
Имення. Если X ня приспособлен под Y, то единственное, что можня сказать об X — то, что он ня приспособлен под Y.
Поэтому то, что шаблоны ня умеют обрабатывать AST, ня делает шаблоны говном. Это делает их ня умеющими обрабатывать AST.
j123123 # 0 ⇈
Ну хорошо, допустим. А что должно быть не так с шаблонами, что делало бы их однозначно говном? Или говна вообще нет ни в чем?
PolinaAksenova # 0 ⇈
Няумение играть ня скрипке ня может сделать из Васи плохого программиста. Плохим программистом Вася будет только тогда, когда он ня умеет программировать.
Вот, няпример, std::string — это однознячное говно, потому что это нечто вообще ня обладает методами, специфичными для строки. Оно ня умеет в Юникод, в нём нят всяких сахаров вида endswith()/startswith()/split()/join(), в нём нят методов для работы с капитализацией — это то, что мне реальня потребовалось в последние пару месяцев, и что мне пришлось велосипедить самой (кроме юникода).
А вот шаблоны свою задачу — няписание обобщённого кода — выполняют достаточня хорошо. То, что всякие сумасшедшие ня них пишут интерпретаторы брейнфака и страдают — проблема исключительня сумасшедших.
j123123 # 0 ⇈
Нет. Недостаточно хорошо. Умение читать/писать AST в компилтайме имеет к возможностям написания обобщенного кода достаточно большое отношение, в шаблонах такой фичи нет. Так что на мой скромный взгляд, шаблоны - говно.
PolinaAksenova # 0 ⇈
j123123 # 0 ⇈
Если есть доступ к 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 и возможности его перестраивать по месту?
PolinaAksenova # 0 ⇈
Какой смысл использовать переусложнённый инструмент для решения простой задачи? Ты AST структур будешь ручками парсить, вместо простого "getFields<struct X>"?
> Если тебе конкретно не нужен, это не значит что не нужен вообще.
Нят, это знячит, что он ня нужен среднестатистической программистке ня крестах.
> Вот допустим по биному Ньютона можно получить
И дальше пошли абсолютно синтетические задачи, как обычня.
> Как это решить без доступа в AST и возможности его перестраивать по месту?
Профилируешь, видишь, что тут боттлнек, переписываешь формулу.
j123123 # 0 ⇈
Возьми сложную математическую либу с кучей формул и сложных вычислений. Такие либы вполне себе существуют. К ним вполне могут быть применимы такие оптимизации.
> Профилируешь, видишь, что тут боттлнек, переписываешь формулу.
А если наиболее оптимальный с т.з. вычислений вариант окажется абсолютно нечитаемым, и по заоптимизированной формуле будет абсолютно неясен ее смысл? А если формула эта не одна, и переписывать их руками самым оптимальным образом - задача крайне сложная для человека?
А если этот боттлнек не в каком-то месте с какой-то формулой, а равномерно размазан по куче таких формул? Или так не бывает?
PolinaAksenova # 0 ⇈
> А если наиболее оптимальный с т.з. вычислений вариант окажется абсолютно нечитаемым, и по заоптимизированной формуле будет абсолютно неясен ее смысл?
По любой формуле длиннее трёх символов абсолютня ня ясен её смысл, если она ня вынесена в метод с понятным именем.
> А если формула эта не одна, и переписывать их руками самым оптимальным образом - задача крайне сложная для человека?
Для этого существуют специализированные математические пакеты. Ты в своей волшебной либе бигинтов будешь реализовывать всю Wolfram Mathematica?
> А если этот боттлнек не в каком-то месте с какой-то формулой, а равномерно размазан по куче таких формул?
Тогда тебе нужня вбить их все в специализированный математический пакет.
j123123 # 0 ⇈
Можно справляться лучше.
> По любой формуле длиннее трёх символов абсолютня ня ясен её смысл, если она ня вынесена в метод с понятным именем.
Смотря кому. Ма-те-матику может быть и понятно всё.
> Для этого существуют специализированные математические пакеты. Ты в своей волшебной либе бигинтов будешь реализовывать всю Wolfram Mathematica?
А эти специализированные математические пакеты точно заточены на выполнение таких трансформаций, чтобы для пирфоманса было лучше всего? Я вот не очень в этом уверен. Вряд ли Wolfram Mathematica умеет генерить какие-нибудь SIMD-интринсики и как-то хитро подгонять что-то под размер кеша какого-то там проца.
PolinaAksenova # 0 ⇈
Да нет, вполне достаточня.
> Смотря кому. Ма-те-матику может быть и понятно всё.
А крутому математику и оптимизированная формула будет понятня.
> SIMD-интринсики
Ты нячал с бинома Ньютона, а теперь уже говоришь про интринсики. Но если уж ня то пошло, то няд оптимизациями такого уровня в gcc&clang бьётся огромное количество опытнейших программистов, и то до сих пор как-то ня очень получается. Ты всерьёз считаешь, что автор очередной велолибы для бигинтов сможет осилить качественную оптимизацию сложнее бинома Ньютона, которая ня только будет что-то оптимизировать, но ещё и ничего ня сломает?
j123123 # 0 ⇈
Нет, математик вряд ли знает что-то про SIMD-интринсики.
> Ты нячал с бинома Ньютона, а теперь уже говоришь про интринсики.
Я нигде не утверждал, что речь идет только про бином Ньютона. Это был просто базовый пример. Без доступа к AST в рамках языка никакой подобной компилтайм-трансформации/оптимизации кода не сделать вообще, хоть там бином, хоть не бином. Обычные математические пакеты, типа вольфрам математики - они под оптимизирующие трансформации не затачивались, так что для решения таких задач нужно будет что-то специализированное городить.
> Ты всерьёз считаешь, что автор очередной велолибы для бигинтов сможет осилить качественную оптимизацию сложнее бинома Ньютона, которая ня только будет что-то оптимизировать, но ещё и ничего ня сломает?
Я думаю что если набрать толковых математиков-программистов, они вполне смогут сделать хорошую либу для такого рода трансформаций, которая ничего ломать не будет. Можно даже формально доказывать корректность подобных трансформаций через Coq.
PolinaAksenova # 0 ⇈
Ня тот момент речь шла всё ещё про биномы Ньютона, но да, про интринсики он ня зняет.
> Я думаю что если набрать толковых математиков-программистов, они вполне смогут сделать хорошую либу для такого рода трансформаций, которая ничего ломать не будет.
Да, а если нябрать толковых экономистов-программистов, то можня построить коммунизм.
У тебя есть примеры таких либ в языках с гомоиконностью/доступом к AST?
j123123 # 0 ⇈
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 и что-то там трансформировать
PolinaAksenova # 0 ⇈
В этой работе авторы используют подход "шланга": компилирует код (очень ограниченное подмножество сишки) в "metasemantic intermediate representation", оптимизируют его, после чего "раскукоживают" обратня в код. Причём, что интересно, весь код для оптимизации у них няписан ня Python, потому что ня Python писать подобные высокоуровневые преобразования очень удобня.
Никакой трансформации AST в этой работе нят.
j123123 # 0 ⇈
> 2.1.2 Existing Tools for Source-to-Source Transformation
PolinaAksenova # 0 ⇈
Гомоиконность/доступ к AST для этой работы вообще никак ня релевантны.
> Existing Tools
А где здесь библиотеки? Это просто либо компиляторы, либо standalone утилиты, работающие с IR. Как им поможет доступ к AST изнутри языка?
MAKAKA # 0 ⇈
j123123 # 0 ⇈
Это можно и для инструментации, и для оптимизации. Например, 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,
j123123 # 0 ⇈
Вполне релевантны. Из кода получают 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. Это несколько удобнее.
PolinaAksenova # 0 ⇈
Проблема в том, что всё тобою скинутое — это отдельные утилиты. Они берут исходный код, проводят няд ним изменения и выдают изменённый исходник обратно. Каким образом им может помочь доступ к AST во время компиляции?
> работать надо было б на уровне AST
Во-первых, каким образом скинутая тобой либа будет получать данные PGO во время компиляции?
Во-вторых, оптимизации подобного уровня (векторизация, снижение точности и так далее) няльзя делать "под капотом". Программист должен видеть, что получилось ня выходе, иняче его ждут незабываемые часы отладки. Совсем нядавно bormand рассказывала, как у него компилятор превратил цикл в самописном memcpy в вызов memcpy. Так что ещё более радикальная оптимизация кода должна проводиться исключительня в виде source-to-source, а не в виде "говнолиба перемешала AST так, что отлаживать это можня только под грибами".
j123123 # 0 ⇈
Обоснование?
> Проблема в том, что всё тобою скинутое — это отдельные утилиты. Они берут исходный код, проводят няд ним изменения и выдают изменённый исходник обратно. Каким образом им может помочь доступ к AST во время компиляции?
Эти утилиты можно было бы написать на метаязыке, который бы выполнялся во время компиляции. Это мог бы быть например некий хитрый плагин к компилятору, который бы встраивался в процесс компиляции и делал нужные перестановки AST на каком-то этапе.
> Во-первых, каким образом скинутая тобой либа будет получать данные PGO во время компиляции?
Можно инклудить в компилтайм-либу накопленные данные профилирования в каком-то формате, этот файл может быть проанализирован на этапе компиляции, и потом там что-то можно трансформировать в самом коде.
> Во-вторых, оптимизации подобного уровня (векторизация, снижение точности и так далее) няльзя делать "под капотом". Программист должен видеть, что получилось ня выходе, иняче его ждут незабываемые часы отладки.
Если либой гарантируется сохранение наблюдаемого поведения и в либе нет никаких багов, то никаких часов отладки не требуется.
Кстати, а как с этим обстоят дела у крестошаблонного метапрограммирования? Программист обязательно должен видеть, во что трансформируется такая-то шаблонометушня?
> Так что ещё более радикальная оптимизация кода должна проводиться исключительня в виде source-to-source, а не в виде "говнолиба перемешала AST так, что отлаживать это можня только под грибами".
Если перемешивание AST точно не меняло наблюдаемого поведения, можешь отлаживать неперемешанный вариант. Если у тебя перемешанный вариант неправильно что-то считает, неперемешанный будет вести себя ровно так же.
PolinaAksenova # 0 ⇈
Они работают с IR. AST им ня нужен.
> Эти утилиты можно было бы написать на метаязыке, который бы выполнялся во время компиляции. Это мог бы быть например некий хитрый плагин к компилятору, который бы встраивался в процесс компиляции и делал нужные перестановки AST.
А зачем, если ня Питоне эти утилиты писать быстрее и проще?
> Можно инклудить в компилтайм-либу накопленные данные профилирования в каком-то формате, этот файл может быть проанализирован на этапе компиляции, и потом там что-то можно трансформировать в самом коде.
И это замечательный пример того, как программисты, узнавшие про какой-то новый концепт, нячинают пытаться засунуть его в любое место, даже если в итоге получается переусложнённое говно.
> гарантируется сохранение наблюдаемого поведения и в либе нет никаких багов
Святая няивность!
Да, кстати, а как с сохранением наблюдаемого поведения дела обстоят у сброшенной тобой же утилиты, которая специальня снижает точность вычислений для оптимизации?
> можешь отлаживать неперемешанный вариант.
Программа крашнулась у пользователя. Дамп есть, сейчас отладим!.. Ой, нят, извините, этот дамп с оптимизированной версии, в которой AST перемешано до няузнавания, отладить это ня получится.
> Если у тебя перемешанный вариант неправильно что-то считает, неперемешанный будет вести себя ровно так же.
Очень смешно. Кстати, замена цикла ня memcpy тоже ня меняет наблюдаемого поведения.
> Кстати, а как с этим обстоят дела у крестошаблонного метапрограммирования?
Ня сильня хуже, чем у программы без шаблонов. В дебаг-символах все специализации шаблонов сохраняют имена, просто к ним добавляются аргументы шаблона. В крайнем случае можня сходить ня https://cppinsights.io и посмотреть, во что конкретня раскрывается конкретное шаблоноговно. С AST так ня сделаешь.
j123123 # 0 ⇈
А этот IR откуда берется? Случайно не из AST? А если AST и IR на каком-то этапе это одно и то же?
> А зачем, если ня Питоне эти утилиты писать быстрее и проще?
Почему Clang-LLVM и GCC еще не переписали на питон?
> Святая няивность!
Так понятно что баги есть даже в компиляторах, и что?
> Да, кстати, а как с сохранением наблюдаемого поведения дела обстоят у сброшенной тобой же утилиты, которая специальня снижает точность вычислений для оптимизации?
Так ведь даже компиляторы C/C++ с точностью для FPU-вычислений хер знает что делают, и там ничего не гарантируется.
> Программа крашнулась у пользователя. Дамп есть, сейчас отладим!.. Ой, нят, извините, этот дамп с оптимизированной версии, в которой AST перемешано до няузнавания, отладить это ня получится.
Оптимизирующие компиляторы тоже отлично справляются с задачей перемешивания "AST" до неузнаваемости, и без дебаг-инфы там тоже все сложно будет.
>> Если у тебя перемешанный вариант неправильно что-то считает, неперемешанный будет вести себя ровно так же.
>Очень смешно.
Именно так и работают флаги оптимизации у всяких разных компиляторов, если нет UB и багов в компиляторе. Они делают программу быстрее, но поведение не меняется. Это смешно?
PolinaAksenova # 0 ⇈
Почитай работу, откуда он там берётся. Но это, разумеется, совершення няважно, потому что в итоге авторы манипулируют не AST, а IR. Возможня, потому что умным дяденькам и тётенькам манипуляция AST няпрямую показалась слишком сложной.
> Почему Clang-LLVM и GCC еще не переписали на питон?
А почему утилита по твоей ссылке няписана на Питоне?
> Так понятно что баги есть даже в компиляторах, и что?
То, что ты тут размахиваешь либой, которая гарантирует няприкосновенность кода. В реальнясти такую гарантию может дать только либа, которая побайтово копирует код из одного файла в другой.
> Так ведь даже компиляторы C/C++
Проблема в том, что скинутая тобой либа нямерянно меняет поведение программы. Если бы оня это делала неявня, через AST — программисту было бы очень весело.
> и без дебаг-инфы там тоже все сложно будет.
Да. Проблема в том, что после работы твоей волшебной либы, перемешивающей AST, ня поможет даже дебаг-инфа.
> Именно так и работают флаги оптимизации у всяких разных компиляторов, если нет UB и багов в компиляторе. Они делают программу быстрее, но поведение не меняется.
Только вот проблема в том, что существенная часть ошибок в коде ня C/C++ — это имення UB. И даже сейчас UB может приводить к очень странным и трудно отлавливаемым багам. А твоя волшебная либа только ухудшает ситуацию.
j123123 # 0 ⇈
А что если на каком-то этапе AST == IR и трансформации в таком абстрактном представлении где-то происходят? Или так не может быть?
> А почему утилита по твоей ссылке няписана на Питоне?
Ну хз, можно у автора спросить. Если что, могу дать другие ссылки на другие утилиты, которые написаны не на питоне.
> В реальнясти такую гарантию может дать только либа, которая побайтово копирует код из одного файла в другой.
Нет. Для начала надо формально доказать, что компилятор, который собирал эту либу, всё правильно скомпилировал, а еще что космическое излучение не повлияло на процесс, и что в процессоре нет аппаратных багов и еще куча всего можно понапридумывать.
> Проблема в том, что скинутая тобой либа нямерянно меняет поведение программы.
И что? Некоторые оптимизации тоже вполне намеренно меняют поведение программы. Например, -funsafe-math-optimizations
> Да. Проблема в том, что после работы твоей волшебной либы, перемешивающей AST, ня поможет даже дебаг-инфа.
Ну это смотря как устроена эта дебаг-инфа, там это всё можно как-нибудь учитывать, что такой-то преобразованный код соответствует такому-то непреобразованному. Еще можно попробовать эту дебаг-инфу как-нибудь перевести в такую форму, чтоб эта дебаг-инфа выглядела так, как если бы перестройки AST не происходило вовсе.
bormand # 0 ⇈
Тогда это очень сильно ограничивает манипуляции над AST. По сути, ничего кроме оптимизаций запилить невозможно.
Вот сгенерил ты во время конпеляции какую-нибудь сериализацию/десериализацию для структуры и тем самым поменял наблюдаемое поведение (добавил новое).
А ты ведь манипуляции над AST хочешь юзать для новых фич языка и т.п.
j123123 # 0 ⇈
Если нужно новые фичи языка добавлять, не имеет смысла говорить о "неизменении наблюдаемого поведения" т.к. расширенный язык (условно говоря C++) не скомпилируется компилятором нерасширенного языка (условно говоря компилятором C). И никакого наблюдаемого поведения у некомпилирующейся программы нет, так что постановка вопроса некорректна.
bormand # 0 ⇈
Это скорее означает, что "простой" вариант с сохранением поведения тут не катит. И придётся как-то формализовывать эту фичу, описывать её взаимодействие с другими. Ну, то чем сейчас и занимаются комитеты. Только из-за зоопарка этих библиотек-расширений багов в реализации и недочётов в спеке будет на порядок больше.
А отлаживать неведомую херь тоже не особо весело.
j123123 # 0 ⇈
А часто ли программист должен смотреть ассемблерный выхлоп из компилятора? Ну там ведь тоже куча всяких сложных трансформаций происходит, что-то куда-то заинлайнивается, loop-invariant code motion всякие происходят, loop unswitching, т.е. вместо кода типа
компилятор где-то в каком-то абстрактном говнопредставлении перетрансформирует это в
И потом компилятор это еще и наанроллит. Обязательно ли это все видеть?
PolinaAksenova # 0 ⇈
Так в том-то и проблема, что вообще каким-либо образом отлаживать программу с покорёженным AST практически нявозможня. Потому что после изнясилования AST у тебя будет выполняться совершення ня то, что няписано в коде. И твои ошибки будут преобразовываться до няузнаваемости. А уж если в "оптимизирующей либе" будет баг...
gologub # 0 ⇈
примерно один раз в никогда и только если очень хочется сделать микрооптимизацию приколоченную к платформе
иначе не нужна эта якобы портабельная крестушня
bormand # 0 ⇈
Ну ещё иногда конпелятор генерит говно и приходится читать что он там высрал. Но это прям крайне редко.
gologub # 0 ⇈
ну это почти или даже за рамками задач обычного генерал-пурпоза прогармиста
вопрос доверия к инструменту как бы
CHayT # 0 ⇈
Вместо проблем у тебя появляются метапроблемы.
И если не делать трансформации AST с помощью сахарка в языке (квазицитирования и сплайсов, как в TH), то через месяц читать свой мета-код становится очень интересно.
j123123 # 0 ⇈
Вряд ли крестовые шаблоны в этом плане веселее.
CHayT # 0 ⇈
Сравни типичное шаблоноговно (не из буста) с
https://github.com/k32/typerefl/blob/master/src/typerefl_trans.erl (и это ещё очень простая трансвормация)
CHayT # 0 ⇈
CHayT # 0 ⇈
Какая консистентность именования )))
bormand # 0 ⇈
К слову, даже на родине гомоикон в лиспе все почему-то стараются юзать квазицитирование а не гомоиконы... Хотя казалось бы.
CHayT # 0 ⇈
Так что даже лисперам лень в чужих говноиконах копаться.
j123123 # 0 ⇈
И при раскрытии могут порождать некий новый код? Вот например компилтайм-либа крестов для PCRE https://github.com/hanickadot/compile-time-regular-expressions - она что, ничего не порождает? Что вообще значит "порождает новый код"? BOOST_PP_REPEAT порождает или не порождает новый код? А что тогда порождает?
bormand # 0 ⇈
Не порождает. Исходный код всех функций написан заранее, из них просто собирается дерево. Если пробежаться по коду в отладчике (с выключеной оптимизацией, само собой), то помимо функций из этой библиотеки ты ничего нового не увидишь.
Нету там каких-то волшебных гомоикон, которые создают код из воздуха или что-то в нём меняют. И к счастью и к сожалению.
j123123 # 0 ⇈
Демагогия какая-то. Следуя такой логике, тогда и обычный компилятор ничего не порождает, когда компилирует что-то из кода на Си в инструкции процессора. Ведь код компилятора написан заранее, компилируемый компилятором код написан заранее, из компилируемого кода собирается какое-то дерево и потом по каким-то известным правилам во что-то трансформируется.
В крестах через шаблоны вполне можно написать некий недокомпилятор, чтобы некая шаблоносрань принимала в себя строку, каким-то образом ее парсила и раскрывалась в некую хрень. Чем бы это на фундаментальном уровне отличалось от обычного компилирования?
bormand # 0 ⇈
Если провести аналогию с функциональщиной, крестовые шаблоны -- это просто композиция существующих крестовых функций, каждую из которых я могу прочитать в исходнике.
В отличие от макросов, которые могут что угодно высрать и наконкатенировать. В отличие от трансформаций AST, которые делают новые функции и структуры, которых в моём исходнике нет.
j123123 # 0 ⇈
И что? Ну вот есть допустим некий крестовый шаблон, возьмем простейший вариант, без всякой сложной метушни
И где-то я использую эту хрень таким образом
Отчего бы мне не считать, что делая подобную хрень, я автоматически генерирую (порождаю) где-то функцию типа
?
bormand # 0 ⇈
CHayT # 0 ⇈
j123123 # 0 ⇈
vistefan # 0 ⇈
j123123 # 0 ⇈
Сейчас, увы, нет широко используемых и достаточно низкоуровневых языков с доступом к AST в компилтайме, чтобы там такая оптимизация была реально полезной.
CkpunmoBbIu_nemyx # 0 ⇈
j123123 # 0 ⇈
Будут либы, которые напрямую работают с AST, и делая условный "getFields<struct X>" я как раз буду такую либу использовать. Но чтоб такие либы написать, нужен доступ к AST.
PolinaAksenova # 0 ⇈
j123123 # 0 ⇈
А что получилось в C/C++? Полуработающий Conan, в котором хрен чего найдешь, и поэтому один фиг надо ходить по гитхабу с черным мешком для мусора и собирать в него нужные говнолибы? Это лучше?
j123123 # 0 ⇈
Я вот кстати посмотрел такую либу https://github.com/hanickadot/compile-time-regular-expressions - это вот регулярки через шаблоны в компилтайме, с запиленным в компилтайме LL(1) анализатором на шаблонах. И там еще вот такая генеренная шаблонная хрень из какого-то DESATOMAT
Да, нагенерить километры какой-то шаблонной хрени это прямо вот "хорошо и эффективно". На кой вообще делать кодогенерированную компилтайм-либу на шаблонах которая генерит регекспы в компилтайме, если сами регекспы можно сразу кодогенерировать?
j123123 # 0 ⇈
PolinaAksenova # 0 ⇈
Нязвать язык программирования говном можня только после обширного анялиза его нядостатков. То, что кресты ня могут решить эту задачу, ознячает лишь то, что они ня могут решить эту задачу (хотя в принципе, конячно, кресты — говно, с этим никто ня спорит).
Простыми словами: я купила машину, а в машине нят прикуривателя. Ознячает ли это, что машина — говно?
bootcamp_dropout # 0 ⇈
я сколько тут сижу вы столько тут анализируете недостатки с++
MAKAKA # 0 ⇈
j123123 # 0 ⇈
PolinaAksenova # 0 ⇈
Парадокс говна («Говно», «Моча») — логический парадокс, сформулированный Евбулидом из Говнокода (IV век до н. э.)[1], связанный с неопределённостью предиката «быть говном»[2].
Слишком малый ресурс при слишком высокой цене — конячно, говно. А что такое малый ресурс и что такое высокая цена — тут уже каждый решает для себя.
gologub # 0 ⇈
j123123 # 0 ⇈
Разрабы Boost программируют или упражняются в эзотерике?
PolinaAksenova # 0 ⇈
j123123 # 0 ⇈
Что-то не похоже
PolinaAksenova # 0 ⇈
vistefan # 0 ⇈
j123123 # 0 ⇈
Компилтайм-метушня вполне может (и должна) быть zero-cost.
PolinaAksenova # 0 ⇈
MAKAKA # 0 ⇈
vistefan # 0 ⇈
vistefan # 0 ⇈
j123123 # 0 ⇈
https://wandbox.org/permlink/BjVlfoT12mb8xQFp
j123123 # 0 ⇈
https://wandbox.org/permlink/eBiqs8lco7J3IMww
Блядь, какое же говно. И все равно это будет недостаточно универсально.
PolinaAksenova # 0 ⇈
j123123 # 0 ⇈
А зачем мне надо выбирать, писать "x += y" или "x = y + z"? Ведь вполне может быть так, что из каких-то там шаблонов или макросов или смеси шаблонов и макросов раскрывается такая вот фигня вида "x = x + y" и мне надо чтоб оно там само это нашло и переписало в "x += y" для максимального пирфоманса.
PolinaAksenova # 0 ⇈
Чтобы ясно выразить, что в первом случае ты хочешь сразу модифицировать x, а во втором — снячала сложить, а потом записать в x.
> Ведь вполне может быть
Ни разу ня видела таких шаблонов. Приведи пример из реального проекта, в котором такая оптимизация могла бы улучшить производительность.
j123123 # 0 ⇈
А если я хочу получить нужный мне конечный результат максимально эффективным образом, а что оно там сначала и что потом делает - меня не волнует?
> Приведи пример из реального проекта, в котором такая оптимизация могла бы улучшить производительность.
Лично я таких проектов не знаю. Искать лень.
PolinaAksenova # 0 ⇈
Тогда ты используешь только +=.
> Лично я таких проектов не знаю. Искать лень.
И я ня зняю. И с учётом крайней оторванности этой задачи от реальности — скорее всего, если такие проекты и есть, то встречается няобходимость в этом "автосворачивании операторов" раз на миллиард sloc.
j123123 # 0 ⇈
А если у меня откуда-то синтезируется код с a = a + b и я хочу этот код преобразовать в a += b ?
bormand # 0 ⇈
Дык нет в крестах "синтеза кода откуда-то". Весь код уже написан тобой. Просто параметризуется немножко. Поэтому либо ты сам уже написал a += b либо там всегда и будет c = a + b, которое никуда не преобразовать.
j123123 # 0 ⇈
Ну написан, и что? Вот есть макрос, допустим
#define SHIT(a, b, c) a = b + c
Если я его вызову как
bormand # 0 ⇈
Обколются своих макросов, а потом в жопы ебутся...
vistefan # 0 ⇈
Охуеть.
bormand # 0 ⇈
Препроцессор с условием просто высрет это условие в код. Он же просто токенами ворочает. А условие, если оно не constexpr, будет выполнено уже в рантайме.
З.Ы. А #ifdef внутри макроса нельзя юзать, если ты о нём.
MAKAKA # 0 ⇈
и если компилятор не докажет, что оно константа:)
Кстати, в няшной же нет constexpr?
j123123 # 0 ⇈
Ключевого слова нет. А само понятие, типа "известная на этапе компиляции фигня" - есть.
так скомпилируется:
Так тоже скомпилируется в GCC и Clang, но это уже экстеншен:
warning: variably modified 'a' at file scope
А вот так нихуя не скомпилируется:
И так тоже не скомпилируется:
bormand # 0 ⇈
Значения енумов и метки в свиче ещё требуют "constexpr". В общем-то как и в крестах.
MAKAKA # 0 ⇈
Это к щастю везде есть) Кажется, что "int i = 2 + 2" даже javac поймет
>И так тоже не скомпилируется:
хм.. а это не VLA?
VC не умеет VLA, но GCC то вроде должен уметь?
j123123 # 0 ⇈
Хмм, ну да, с VLA оно скомпилируется, но оно не будет компилироваться, если эта хрень объявлена глобально. Глобальный массив не может быть VLA.
MAKAKA # 0 ⇈
пушо стек еще как-то можно двигать в рантайме, а вот размер data и bss нужно знать заранее?
PolinaAksenova # 0 ⇈
MAKAKA # 0 ⇈
В C99 появился.
А вот в C89 (который был и в bolrand c++ 3) мало того, что не было VLA, так еще и все локальные переменные нужно было декларировать в начале тела функции.
То есть размер стекфрейма функции компилятор всегда мог посчитать перед началом функции.
Кcтати, а в С++ вместо VLA принято использовать vector, который всё хранит в куче? Или он может как-то читерить, и хранить на стеке через alloca?
vistefan # 0 ⇈
MAKAKA # 0 ⇈
согласен
Возможность объявлять переменные походу энкариджит говнокодеров высирать функции на 900 строк
vistefan # 0 ⇈
if (cond) int a = 1; else double b = 1.0;
?
А он кстати во что скомпилится в с99?
bormand # 0 ⇈
Внихуя. Переменные же не используются (а использовать ты их не сможешь).
З.Ы. А, вообще не компилится, лол. Скобочки просит.
vistefan # 0 ⇈
MAKAKA # 0 ⇈
>sub rsp, 32
если добавить еще int, то будет 48
а потом пишет твою "a" в одно и тоже место
mov DWORD PTR [rbp-8], 1
add DWORD PTR [rbp-8], 2
ну тоись он пошел, посчитал размер стека, двиганул SP (предвроительно сохранив его в BP) и дальше жег
А что бы он делал с FPO кстати я не зна, надо проверит
vistefan # 0 ⇈
То есть всё равно посчитал всё место, какое ему может понадобиться в любом из ветвлений, и отожрал стека, а потом, возможно, часть отожранного стека не юзал?
Это практически то же самое, что просто собрать все декларации, так как если бы они были написаны в начале функции, только синтаксически разрешить писать их не в начале, или я не прав?
guest # 0 ⇈
попробуй
получишь
Единственный плюс "нового" подхода это ограничение видимости. Оно позволяет иметь "b" внутри каждой веточки своё.
Ну и вероятно деструкторы должны вызываться в случае С++.
Забавнее посомтреть что будет, если крутить стек в рантайме
VLA
начинаются игрища с стек поинтером
Удивительно другое!
Я заказал "-fomit-frame-pointer" чтобы посмотреть как питух будет изъебываться адресовать переменные от SP, которого он постоянно дрочит.
А он взял, и положил на эту опцию, и продолжил юзать BP.
При этом если сделать код без VLA, то -fomit-frame-pointer отключает BP, и переменные начинают адресоваться от SP.
Иными словами, FPO значит не "запрещаю тебе юзать BP" (как я до сего момента думал), а означает "разрешаю тебе не юзать BP, если хочешь"
А компилятор такой: ой, ну если бы ты не трогал SP в рантайме, то я бы воспользовался твоим предложением, а так засунь себе FPO в жопу, а я буду продолжать адресовать переменные на стеке от BP
PolinaAksenova # 0 ⇈
Ну да, абсолютное большинство "оптимизирующих" опций — это рекомендации, а ня законы (прямо как Кодекс в PoTC \(★ω★)/).
MAKAKA # 0 ⇈
FPO это разрешение компилятору юзать BP под свои нужны, бо у программиста есть символы.
Хотя наверное в x64 регистров уже так много, что смысл экономить на BP нет
vistefan # 0 ⇈
Напоминает "record case" или variable records в паскале.
Там можно объявить запись с вариантами разблядовки типов, например
Type
Sex = (baba, mojeek);
Hair = (lysy, volosaty);
Chelovek = Record
age: Integer;
hair: Hair,
case Sex of
baba: (razmer_sisek: Integer, ebalo: Kartinka);
mojeek: (zarplata: Double, dlinna_huya: Byte);
end;
В итоге сайзоф такой записи будет исходя из размера самого ресурсоёмкого case, но не всей их суммой. Все case замапятся в одно и то же место в памяти и гарантированно влезут. В данном примере попытавшись изменить razmer_sisek у записи можно поломать его значение zarplata, потому что предполагается что юзаться кейсы должны независимо. Компилятор за этим не следит, ты сам в коде должен определить для себя, какой тебе от этой записи нужен кейс. Таким образом можно знатно сэкономить на спичках.
MAKAKA # 0 ⇈
sizeof этой конструкции будет равен int (мы предпологаем, что int выравнивать не нужно).
Если ты положил туда i, то в "с" теперь UB, и наоборот.
Сам должен следить за тем, что положил.
Тоже такая вот экономия.
Там есть прикол в крестах с тем, что туда нельзя класть объекты с нетривиальным деструкторами, бо хуй знает, когда их вызывать.
Только в наш rsp по идее влезут ВСЕ объявленные переменные
MAKAKA # 0 ⇈
Если ты в начале функции ты видишь все её перменные, то ты просто двигаешь stack pointer на нужное количество байт, и потом можешь их от него адресовывать.
Закончилась функция -- ты его обратно подвинул.
А если у тебя по ходу пьесы стек двигается на вычисляемое в рантайме количество байт (alloca, vla, или if (petuh) {int i..}, то тебе нужно как-то в рантайме понимать какого размера твой стек, и как это обратно всё потом двинуть, когда функция закочнится.
Наверное хорошо, если у тебя есть FramePointer (BP) который указывает на начало функции, от него можно хотя-бы наверное переменные адресовывать, а если нет?
Короче, написать такой компилятор труднее.
Так вижу. Но может дело и не в этом..
Алсо, стек (особенно во времена c89) было СОВСЕМ не резиновый. 16 килобайт или около того был он в паскале
gologub # 0 ⇈
MAKAKA # 0 ⇈
gologub # 0 ⇈
j123123 # 0 ⇈
Клангом для Си собирается (если как глобалки), а GCC уже не хочет это собирать.
bormand # 0 ⇈
Не, в этом случае всё жёстко. Не доказал -- не скомпилил.
MAKAKA # 0 ⇈
j123123 # 0 ⇈
Да. Если ты в макросне напишешь if (x) {y;} else {z;} то у тебя это условие в то место впихнется как код. Для тебя это новость?
vistefan # 0 ⇈
bormand # 0 ⇈
Макросня работает на уровне токенов. Можешь считать её скриптом на PHP, который просто что-то там в тексте правит и копипастит. А в языке она ничерта не смыслит, ни в сишке ни в крестах.
vistefan # 0 ⇈
vistefan # 0 ⇈
bormand # 0 ⇈
Т.е. про == и if шаблонизатор ничего не знает, как PHP ничего не знает про <div>. Поэтому он их дословно копирует на выход.
vistefan # 0 ⇈
guest # 0 ⇈
vistefan # 0 ⇈
bormand # 0 ⇈
vistefan # 0 ⇈
gologub # 0 ⇈
MAKAKA # 0 ⇈
a + b
то у a вызыавался бы append (Ну тоесть делался бы тот самый реаллок)?
Flexible_array_member кстати не очень нужен, когда есть шаблоны: туда же можно реальный размер передать, И потечь
MAKAKA # 0 ⇈
PolinaAksenova # 0 ⇈
> explicit MyVector
explicit нужен только для конструкторов, принимающих только один аргумент. Для других он ня имеет особого смысла.
bormand # 0 ⇈
PolinaAksenova # 0 ⇈
MAKAKA # 0 ⇈
MAKAKA # 0 ⇈
guest # 0 ⇈
У нас нет кодстайла для крестов, потому что на крестах в моем отделе три тупых утилиты написано
Я использую тот кодстайл, который форсит мне по умолчанию студия и R#, он более-ли-менее коньсистентен
guest # 0 ⇈
bormand # 0 ⇈
Т.е. он эту хуйню всё-таки не смог пропихнуть в кодстайл? 😉
guest # 0 ⇈
MAKAKA # 0 ⇈
Я был за то, чтобы писать его во всех переменных. А другие были против.
Я добавлял, другие удаляли
Потом ввели общепродуктовый стиль, и разумеется ненужный final запретили
Речь только о локальных (автоматических) переменных конечно
А в котлине и TS "val" и "const" уже признаны хорошим тоном.
А вы помечаете переменные const при любой возможности?
bormand # 0 ⇈
Ну да. Читать легче.
Хотя по-хорошему const на переменных должен быть по-умолчанию чтобы не замусоривать код. В ocaml'е вроде так и сделали.
MAKAKA # 0 ⇈
Слава богу, я уже давно почти всё JVMговно пишут на котлине, а там всё неизменяемое по умолчанию, само собой
vistefan # 0 ⇈
guest # 0 ⇈
До этого тоже доебывается, кстати
bormand # 0 ⇈
Ну про конст, имхо, есть смысл доебаться в джвух случаях где он пиздец как важен:
- const справа от функции
- const у данных, на которые указывают указатели и ссылки
Остальное -- это просто вкусовщина и подстраховка от ошибок. Никто не умрёт, если его не напишешь. Но ревьювить будет сложнее если функция большая (надо в уме доказывать, что в переменную не срут).
MAKAKA # 0 ⇈
Это же мой любимый пример отсоса всех джав и сишарпов у крестов: const семантика:)
По сути это другой тип (с точки зрения джависта так точно).
А внутри метода иметь немутабельные переменные просто хорошо (например tslint ругается, если ты пометишь let то, что может быть const)*.
Забавно, что в котлине аргументы функции иммутабельны всегда: ты не можешь изменить то, что то тебе передали (только скопировать)
* https://palantir.github.io/tslint/rules/prefer-const/
MAKAKA # 0 ⇈
guest # 0 ⇈
bormand # 0
- 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
bootcamp_dropout # 0 ⇈
Desktop # 0 ⇈
MAKAKA # 0 ⇈
Desktop # 0 ⇈
MAKAKA # 0
Типа
или лучше всё таки лямбду юзать и не выёбываться?
bormand # 0 ⇈
Можешь ещё с бустом повыёбываться: std::find_if(i, last, _1 > 2).
guest # 0 ⇈
guest # 0 ⇈
guest # 0 ⇈
bormand # 0 ⇈
Потому что ты не умеешь его читать. Я думаю с опытом он нормально воспринимается.
А вот все эти bind2nd -- устаревшее говно, конечно. Для тривиальных случаев есть универсальный bind, в котором сразу понятно что куда попадёт. А для более сложных можно лямбду или функцию написать.
guest # 0 ⇈
Как и большинство коллег. Именно это я и хотел сказать.
bormand # 0 ⇈
А теперь представь, что вокруг тебя математики, которым эти векторные операции и функции высшего порядка гораздо ближе, чем циклы. Для них J будет читаться не хуже обычных формул.
MAKAKA # 0 ⇈
Для старой юниксбляди перл вполне читаем, питух с delphi бекграундом просто волосы на жопе рвет, и орет 'как вы на этом говне пишете вообще?'
MAKAKA # 0 ⇈
>std::bind2nd(std::greater<int>(), 2)
?
bormand # 0 ⇈
З.Ы. Именно за это я не люблю STL. Он пытается косплеить функциональщину, но получается как у тех папуасов с карго-культом.
MAKAKA # 0 ⇈
Ну всёж таки в STL была хоть какая-то ванаби-функциональщина еще в 2003-м. А например в жабе всё руками делали
vistefan # 0 ⇈
MAKAKA # 0 ⇈
лист компрехеншены правда тоже лямбды в каком-то смысле (но тоже малоудобные, лол)
Питон такой антируби
vistefan # 0 ⇈
bormand # 0 ⇈
CkpunmoBbIu_nemyx # 0 ⇈
MAKAKA # 0 ⇈
то есть круглые скобочки, а не кводратные
bormand # 0 ⇈
MAKAKA # 0 ⇈
>Ну нету здесь никакой функциональщины
а в map и filter есть?
bormand # 0 ⇈
Ну тут не поспоришь.
MAKAKA # 0 ⇈
Мне нравятся цепочки, которые есть в руби и в груви и частично в JS и в котлине и даже можно изъбнуться в перле.
А только в питоне принято всё расписывать вручную, потому что цепочек нет
bormand # 0 ⇈
Да. У тебя есть функция для одного элемента и она лифтится в функцию, которая обрабатывает много.
В совсем труъ функциональщине было бы так: (map f) list, но и map(f, list) тоже неплохо её косплеит.
MAKAKA # 0 ⇈
а чем вот это не это?
bormand # 0 ⇈
Ну вот смотри, в map(do_all, list) ты описал ЧТО нужно сделать, не вдаваясь в детали реализации.
А в (do_all(x) for x in list) ты пишешь КАК это нужно делать, явно выписывая императивный цикл.
MAKAKA # 0 ⇈
(do_all(x) for x in list)
можно было написать
(do_all in list)
то было бы оно?
bormand # 0 ⇈
Ну это тоже не функциональщина... Где здесь превращение do_all, который обрабатывает один элемент во что-то большее, что умеет обрабатывать много? А это важно для композиции, к примеру. Чтобы я мог связать несколько таких функций в один конвейер.
Как ты в твоём синтаксисе запишешь (map do_all) . (filter (> 42)) . (map preprocess)?
MAKAKA # 0 ⇈
(do_all in list)
отличается от
(do_all, list) ?
>конвеер
Ну как-то так, наверное
(fuck_em_all in (do_all in list))
Но вообще это в питоне некрасиво сделано всё таки, что с itertools что без них.
Толь дело руби
bormand # 0 ⇈
Да, вот тут прям красиво закосплеили.
Но всё равно немного не то, конечно... Нету композябельности, нельзя заюзать эти операции как лего, собирая из мелких кубиков что-то интересное.
Т.е. в примере из хаскеля я могу добавить ещё какие-то фильтры и преобразования. Или даже сделать функцию, которая эти фильтры навешивает по параметрам. А потом запустить список на обработку получившейся функцией. Вот в чём суть труъ функциональщины.
А в примере из руби я просто выполняю одну операцию над списком. А потом выполняю вторую. Скукотища.
vistefan # 0 ⇈
MAKAKA # 0 ⇈
bormand # 0 ⇈
Но уже очень близко...
MAKAKA # 0 ⇈
А строку туда просто пихнули, а рядом вон енумератор от 0 до 1000
Но я понимаю, что собрать конвреер, а потом его запустить было бы круче
bormand # 0 ⇈
Ну как это, цепочка начинается с en 😉
В принципе, можно сделать def compose(f, g) def res(x) f(g(x)) end res end.
И им уже соединять кусочки: chain = compose(cap, first_two). А потом запускать: chain foo.
JloJle4Ka # 0 ⇈
bormand # 0 ⇈
Да, а map -- это фабричная функция. Так и живём.
MAKAKA # 0 ⇈
Билдер это когда ты напихиваешь говна в коробочку, а потом просишь по нему что-то построить
вот std::stringstream или StringBuilder это строители
MAKAKA # 0 ⇈
Это оно?
bormand # 0 ⇈
Х.з., а пайпы можно закомпозить друг с другом? Или только с нуля конструктором строятся?
MAKAKA # 0 ⇈
bormand # 0 ⇈
Хотя... всё норм. pipe() это не новая сущность, просто функция для композиции функций. Ну тогда труъ.
MAKAKA # 0 ⇈
Таких функций офердохуя, кстати: есть tap для сайдэффектов, например)
Я попытался принести RxJava к нам в проект (полагаю, там тоже самое), но мне сказали юзать котлиновские корутины и ченнелы.
А там всё таки императивщина: если ты хочешь из одного ченела в другой переложить, то ты должен писать цикл (хотя он и будет конечно ленивый, ибо suspendable функция)
bormand # 0 ⇈
Эм, а как они на JVM это сделали? Генерят класс со стейтмашинкой вместо функции? Или что-то хитрее?
MAKAKA # 0 ⇈
Функция это класс, хранящий в себе свое состояние и свой "стек".
Его метод вызывает диспетчер. Метод завершается, когда встречает суспендбл вызов (разумеется, блокирующие вызовы типа read и sleep запрещены!)
Всё это обмазано сахаром, потому выглядит как будто ты отдельный процесс запустил
bormand # 0 ⇈
Или попробуй написать функцию, которая настраивает фильтры, а потом отдаёт эти фильтры в другую функцию, которая уже будет обрабатывать список. Не получается, выглядит как говно? А ведь это вполне практическая задачка, на которой императивные языки просто сосут.
Ты не можешь клеить куски этой цепочки во что-то более интересное, ты можешь только применять их к списку по одному за раз.
MAKAKA # 0 ⇈
Вспоминается реактивное RxJS и иже с ними. Там ты можешь создавать папйпы, как угодно их соединять, и потом куда угодно подключать.
Причем это всё может быть ленивое
bormand # 0 ⇈
Ебучие гармошки вместо кода... Или разрабы просто не умеют его готовить?
MAKAKA # 0 ⇈
ну вот я там привел пример
bormand # 0 ⇈
Не, гармошка -- это те 3 экрана кода, которые до )))))))))
CkpunmoBbIu_nemyx # 0 ⇈
MAKAKA # 0 ⇈
ну может быть
Я обычно стараюсь генераторы, потому что они ленивы, и не создают в памяти лишний лист
Главное потом не пройтись по нему два раза случайно
CkpunmoBbIu_nemyx # 0 ⇈
vistefan # 0 ⇈
MAKAKA # 0 ⇈
но читать его не очень кмк
vistefan # 0 ⇈
PolinaAksenova # 0 ⇈
https://abseil.io/tips/108
MAKAKA # 0 ⇈
Но почему не
?
PolinaAksenova # 0 ⇈
MAKAKA # 0 ⇈
DoStuffAsync же не имеет this
Но я всё равно не понимаю, на что расчитывали seasoned C++ engineers пися
> std::bind(&MyClass::OnDone, this)
что this как-то волшебным образом прибайндтися к OnDone?
PolinaAksenova # 0 ⇈
MAKAKA # 0
https://i.redd.it/mleiaj2hucg31.png
guest # 0 ⇈
bormand # 0 ⇈
MAKAKA # 0 ⇈
bormand # 0 ⇈
MAKAKA # 0 ⇈
Уильям Шекспир
MAKAKA # 0 ⇈
Точно помню, что в одном приложении никакой пуш эппловский не использовался (он имеет смысл когад у тебя 100000 клиентов, когда он один, то можно пулить прямо с сервера)
Там ios нас будило, и мы рисовали нотификацию.
Но как именно работало уже не помню, давно очень было(
bormand # 0 ⇈
> можно пулить прямо с сервера
Ну и зря. Там же не в сервере проблема, а в батарейке клиента. Пуши экономят батарейку, оставляя только один полл, который и так уже есть в системе.
MAKAKA # 0 ⇈
Лол, я нашел репу с тем говном)
Там было так:
UIBackgroundModes -> fetch стояло в Info.plist, и потом ios переодически нас будила, и дергала performFetchWithCompletionHandler
ну мы фетчили по http и создавали UILocalNotification
bormand # 0 ⇈
Пуши сейчас даже в браузерах есть. И юзать их вообще тривиально.
MAKAKA # 0 ⇈
А вот подпись для него нужно было получать официально. Платили бабла эпплу, и их эппла звонил питух, и подтверждал!
Пишут, что можно зайти в свой девелопре аккаунт на эппле и зарегить там пуш
Пуши в браузерах ты сам делаешь со своего сервера же, нет "централизованного сервера пушей"
Или есть?
bormand # 0 ⇈
Вроде есть. Иначе у тебя браузер заебётся поллить десяток сайтов.
MAKAKA # 0 ⇈
vistefan # 0 ⇈
bormand # 0 ⇈
vistefan # 0 ⇈
vistefan # 0 ⇈
bormand # 0 ⇈
А разрабам похуй, конечно. Отправляют плейнтекстом.
vistefan # 0 ⇈
MAKAKA # 0 ⇈
Ты хочешь локально нотификацию показать? Типа висишь сервисом и показываешь Toast?
vistefan # 0 ⇈
MAKAKA # 0 ⇈
bormand # 0 ⇈
Кстати, фетч про который ты выше пишешь, это же тоже походу оптимизация батарейки? Чтобы твой сервис ходил в инет только в положенный таймслот вместе со всеми остальными, а потом девайс нормально спал с отключенной сетью.
MAKAKA # 0 ⇈
Я прошу ios иногда меня разбудить, чтобы я мог что-то пофетчить.
Иос имеет право не будить меня когда нет батарейки, или когда там дорогой Интернет в роуминге
Но возможно этот API уже устарел.
А в андроиде есть WorkManager , который ты тоже можешь попросить чтобы тебя запускали только когда телефон заряжен или есть wifi итд
bormand # 0 ⇈
Ну это для каких-то больших загрузок, наверное. Когда какая-нибудь игрушка или навигатор хочет скачать гигабайт. Ради сообщений в мессенджере было бы глупо ждать вайфая.
MAKAKA # 0 ⇈
bormand # 0 ⇈
Steve_Brown # 0 ⇈
(тру стори)
((там, правда, не роуминг был, а местная симка, но все равно бабки сожрало, с запасом же было положено. И еще не сразу понял, что баланс 0, испугался, что мобильная связь не работает, может, уже все рухнуло и мне возвращаться некуда))
bormand # 0 ⇈
bormand # 0 ⇈
Эм, да может конечно. У меня даже говнотифи так делало... Борьба с этим очень простая: тычешь в уведомление и говоришь "больше не показывать". И приложение с этим запретом ничего сделать не сможет.
А пуш -- это именно про оптимизацию доставки небольших пакетов от сервера. Ну и если тебе совсем влом пилить сервис -- можешь попросить, чтобы ось сама его показала когда получит. Тут, конечно, шифровать ты его не можешь иначе как ось без твоей помощи покажет.
vistefan # 0 ⇈
bormand # 0 ⇈
MAKAKA # 0
И я отвечу: обсырают С++.
Прежде, чем обсирать его, переведите на няшную такую вот ненужную программу, написанную в терминах C++03 (а то и 98)
Не то чтобы подобные задачи я решал на работе, но это показывает, как много всего можно было делать из коробки еще 20 лет назад.
PS:
Текст взят отсюда:
https://www.youtube.com/watch?v=cBdIsUp6k7o
j123123 # 0 ⇈
JloJle4Ka # 0 ⇈
j123123 # 0 ⇈
Когда Ричи хотел внести в C очередную фичу, Керниган говорил: "Если тебе нужен PL/1, ты знаешь, где его взять". Видимо, Страуструп не знал, где взять PL/1.
bormand # 0 ⇈
Какая ортогональность ))
MAKAKA # 0 ⇈
А потом в каждом серьезном проекте ..
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".
Кажется, все три варианта самые плохые
PolinaAksenova # 0 ⇈
JloJle4Ka # 0 ⇈
PolinaAksenova # 0 ⇈
А это зависит. Для высокоуровневых скриптовых языков такой аргумент вполня себе валиден, потому что чем больше говна в стдлибе — тем проще и быстрее няписать говноскриптик, а скорость и простота няписания говноскриптиков — один из важных параметров скриптоязыка.
Вот у ме-ня возникла нядавня задача вытащить инфу из виндовых инсталляторов (которые msi). Я взяла Python, импортировала msilib и решила свою задачу за десять минут: максимальня быстро и безо всяких поисков нужных либ. Это хорошо и удобня.
MAKAKA # 0 ⇈
Зачем? Зачем писать на крестах без стдлибы?
bormand # 0 ⇈
Не всегда есть выбор ;(
Она, к сожалению, неудачно спроектирована и слишком сильно завязана на сервисы ОС.
MAKAKA # 0 ⇈
bormand # 0 ⇈
MAKAKA # 0 ⇈
Вот lua везде работает, на любом C89 компиляторе.
3oJIoTou_xyu # 0 ⇈
bormand # 0 ⇈
Удачи с более сложными языками. Один из самых наивных факапов в дизайне крестострок.
MAKAKA # 0 ⇈
Причем оно же, суко, может и скомпилироваться.
bormand # 0 ⇈
[email protected] # 0 ⇈
bormand # 0 ⇈
JloJle4Ka # 0 ⇈
bormand # 0 ⇈
MAKAKA # 0 ⇈
С русским не соснул же, чем немецкий хуже?
bormand # 0 ⇈
MAKAKA # 0 ⇈
а ща проверю
inkanusinho # 0 ⇈
MAKAKA # 0 ⇈
Вообще настоящие строки должны содержать кодпоинты наверное, а не байтики
bormand # 0 ⇈
Просто не надо напяливать transform на строки, вот и всё. Им нужны свои алгоритмы и итераторы, как в том же icu.
А utf-8, utf-16, utf-32, какая-то другая кодировка -- это вообще непринципиально.
MAKAKA # 0 ⇈
https://codepoints.net/U+00B4
То есть ситуация, когда при добавлении символа не изменяется их число, а просто меняетя предыдущий, там в порядке вещей.
Твой эсцет из той же области
Вот что я имел ввиду)
Но ты прав: работать с такими строками как векторами каких-то сущностей уже не получится
зы: всем хватит cp866 или koi8-r. Понапридумывали хуйни ненужной, блядь
bormand # 0 ⇈
Получится, но надо stateful алгоритмы. А transform он без состояния.
MAKAKA # 0 ⇈
Всё таки крестостроки это такие обёртки вокруг массива чаров (точнее того, что там в traits), вообще почему они не спецификация вектора?:)
"настоящие" строки это совсем другое, ну вот icu наверное для того
bormand # 0 ⇈
Так вышло. Они же в крестах были изначально, задолго до STL. Ну и нолик там в конце, как в соседнем треде обсуждали.
> icu наверное для того
Угу. Оно и весит десятки мегабайт...
JloJle4Ka # 0 ⇈
MAKAKA # 0 ⇈
PE4HOu_nemyx # 0 ⇈
Ещё радует, что в турецком «i» переводится в «İ» вместо «I», а в «I» переводится «ı». То есть даже апкейс/лоукейс от «I» и «i» зависит от локали.
В греческом заглавная «сигма» одна (Σ), а строчных две (σ и ς). Вторая используется на конце слов. Т. е. для правильного лоукейса ещё нужно найти границы слов.
PE4HOu_nemyx # 0 ⇈
Однако, используют ли эту букву реально, я не в курсе.
А в совсем старых книгах в качестве заглавного «эсцета» использовали не «SS», а «SZ». Как эта питушня поддерживается софтом, я не знаю.
PE4HOu_nemyx # 0 ⇈
Река в единственном числе — Fluß, а во множественном — Flüsse. А ещё «ss» может случайно оказаться на стыке основ (первая заканчивается на «s», а вторая на «s» начинается), когда менять «SS» на «ß» ни в коем случае нельзя.
А ещё бывает мозговзрывающее слово «масштаб» (Maßstab).
ru66oH4uk # 0 ⇈
PE4HOu_nemyx # 0 ⇈
https://ru.wikipedia.org/wiki/Реформа_немецкого_правописания_(1996)
Я никак не могу запомнить, в каких словах они поменяли «ß» на «ss», а в каких оставили.
Кстати, посмотри картинки в статье. Там и «ttt» есть.
Desktop # 0 ⇈
– но очень хочется?
PE4HOu_nemyx # 0 ⇈
На самом деле мне пофигу, потому что чаще приходится переводить на русский. А немцы как-нибудь обойдутся без моего перевода, пусть языки учат.
Desktop # 0 ⇈
ru66oH4uk # 0 ⇈
Desktop # 0 ⇈
мы практически точно знаем, что икарус работал в издательском деле в 90-x
у него работа связана с текстом и возможно переводами
интересно, что это за работа
а ты мне что?
PE4HOu_nemyx # 0 ⇈
Desktop # 0 ⇈
ru66oH4uk # 0 ⇈
Desktop # 0 ⇈
ru66oH4uk # 0 ⇈
Одно время их выходило по пять штук в год
Desktop # 0 ⇈
знаю onenote, evernote
bootcamp_dropout # 0 ⇈
PE4HOu_nemyx # 0 ⇈
Desktop # 0 ⇈
PE4HOu_nemyx # 0 ⇈
https://en.wikipedia.org/wiki/Comparison_of_note-taking_software
ru66oH4uk # 0 ⇈
Desktop # 0 ⇈
хотя забавно, что, когда я искал todoist и notion, мне показывало рекламу трелло с какого-то хуя
ru66oH4uk # 0 ⇈
есть еще google tasks
Desktop # 0 ⇈
Desktop # 0 ⇈
– тогда джира это тоже заметки
ru66oH4uk # 0 ⇈
Desktop # 0 ⇈
ru66oH4uk # 0 ⇈
https://d2k1ftgv7pobq7.cloudfront.net/meta/p/res/images/spirit/product/89d378b845766a8f0c48e955336266f8/board.png
Desktop # 0 ⇈
в джире можно сделать такие же тудушки
в чём удобство трелло и неудобство джиры, особенно в контексте софта для заметок?
ru66oH4uk # 0 ⇈
Desktop # 0 ⇈
а остальное можно конечно
только я бы даже для туду, не говоря уже о других категориях, не стал бы пользоваться ни жирой, не треллой
совершенно из другой оперы софт
тут туду это тикет
Desktop # 0 ⇈
ru66oH4uk # 0 ⇈
Desktop # 0 ⇈
какие-то мимолётные идеи, примитивная домашняя бухгалтерия, списки ссылок на пх, план поездок
туду это частный случай, не более
PE4HOu_nemyx # 0 ⇈
grep -P "^[uvwxyz]+$" usernames.txt
ru66oH4uk # 0 ⇈
https://www.gnu.org/software/grep/manual/html_node/Matching-Control.html
PE4HOu_nemyx # 0 ⇈
А вот «*BSD» и «Solaris», возможно, в пролёте:
И «Занятая коробка» в пролёте:
https://www.busybox.net/downloads/BusyBox.html
ru66oH4uk # 0 ⇈
В такую жопу её запихали
https://www.gnu.org/software/grep/manual/html_node/grep-Programs.html
PE4HOu_nemyx # 0 ⇈
3.14159265 # 0 ⇈
> В такую жопу её запихали
Зачем? Зачем?
Если нет «man» у большинства комманд всегда есть свитч --help
ru66oH4uk # 0 ⇈
ajtkulov # 0 ⇈
PE4HOu_nemyx # 0 ⇈
https://www.gnu.org/software/grep/manual/html_node/grep-Programs.html#index-_002dP
PE4HOu_nemyx # 0 ⇈
К слову, можно вообще обойтись без знания иностранных языков. Некоторые программисты английского не знают, для них «if» и «for» — это иероглифы.
Desktop # 0 ⇈
bormand # 0 ⇈
Удачи там с японским. В icu походу мегабайтный словарь японских слов для этого есть.
JloJle4Ka # 0 ⇈
MAKAKA # 0 ⇈
bormand # 0 ⇈
MAKAKA # 0 ⇈
RabbitMQ
MSMQ
bormand # 0 ⇈
MAKAKA # 0 ⇈
А еще бывает табличка в шареной базе данных)))
bormand # 0 ⇈
В NGK очередь на сканирование тредов так и работала.