- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
void printParser(const wchar_t *fileName, const wchar_t *str, boolean showLineCharPos)
{
ts::Parser parser;
auto sourceFile = parser.parseSourceFile(fileName, str, ScriptTarget::Latest);
ts::FuncT<> visitNode;
ts::ArrayFuncT<> visitArray;
auto intent = 0;
visitNode = [&](ts::Node child) -> ts::Node {
for (auto i = 0; i < intent; i++)
{
std::cout << "\t";
}
std::cout << "Node: " << wtoc(parser.syntaxKindString(child).c_str()) << " @ [ " << child->pos << " - " << child->_end << " ]" << std::endl;
intent++;
ts::forEachChild(child, visitNode, visitArray);
intent--;
return undefined;
};
visitArray = [&](ts::NodeArray<ts::Node> array) -> ts::Node {
for (auto node : array)
{
visitNode(node);
}
return undefined;
};
auto result = ts::forEachChild(sourceFile.as<ts::Node>(), visitNode, visitArray);
}
спортировал TypeScript парсер в C++ и ахренел от обьема работы :)
Не все смотрят в сток
https://img.gazeta.ru/files3/32/13548032/gayduck-pic905-895x505-71993.jpg
Мой любимый поисковик :-)
♫Утка-гей, утка-гей.♫
То есть меняет их? А правильно было бы ничего не менять никогда, потому что в функциональщине ценят иммутабельность?
Если foo(x) = 4, то желательно, чтобы оно всегда было 4, и не зависело бы от того, сколько раз ты это посчитал
Приведи реальный пример такой функции
Функция имеет доступ только к своим параметрам.
Нестабильная сортировка может поменять местами два одинаковых объекта, но это не значит, что если ты ее несколько раз запустишь с одними и теми же аргументами, то получишь разный результат
Но я же явно туда ничего не передаю...
> это не значит, что если ты ее несколько раз запустишь с одними и теми же аргументами, то получишь разный результат
Да, это так. Вообще, т.к. в любом случае создастся новый массив, никакие сортировки уже не стабильные.
А про ранд я сам понял, там ничего рандомного-то и нет особо.
Ладно, а как в картину ФП будет вписываться функция генерации случайных чисел, основанная на вот таком:
https://www.random.org/audio-noise/
?
не понял тебя.
sort(а,я,б) = [а,б,я]
sort(а,я,б) = [а,б,я]
sort(а,я,б) = [а,б,я]
[а,б,я] == [а,б,я]
стабильность это про то, можно ли поменять местами буквы "а" в массиве [а,а,я]
>Но я же явно туда ничего не передаю...
а это и не функция с точки зрения ма-те-ма-тика же
просто программеры ее так называют
Про audio-noise и вообще IO: https://www.haskell.org/tutorial/io.html.
Вкратце: все принципиально "ня-математические" действия (запросы к аппаратным ГСЧ, чтение файлов, печать символов, общение по сети, ...), которые по своей сути ня могут быть чистыми, выделяются в отдельный огороженный загончик и стыдливо прикрываются тряпочкой IO. Из этого загончика можно вызывать чистые функции, а вот няоборот — из чистых функций IO-действия — нельзя. Таким образом наш уютный чистый мир математических функций не шкварится.
Вовсе нят. IO — это изумительно красивый хак, на самом деле, поскольку теоретически ничего нового в семантику чистого функционального языка он не вносит. Т.е. функции, работающие с IO, с точки зрения системы типов, пользователя и компинятора выглядят как приличные чистые функции, и они ведут себя так же (вернее, им не дают вести себя по-другому, см. ниже).
Формально, каждая функция, работающая с IO принимает на вход переменную типа RealWorld, и возвращает значение того же типа. Если убрать обёртку из монадок, получится что-то вроде:
В примере выше, readFile с параметром "my_file.txt" может возвращать разные результаты, что вроде как чистым функциям нельзя. Но мы в неё передаём дополнительный аргумент realWorld, который каждый раз имеет разное значение. Значит всё в порядке.
Монада IO выполняет две функции: во-первых, она позволяет ня таскать этот параметр rw руками, а автоматизирует процесс. А во-вторых, что самое главное, она в принципе прячет от пользователя этот параметр внутрь модуля. Таким образом, она не позволяет юзеру взять, и переиспользовать одно и то же значение rw. Ибо если бы юзер мог это сделать, обман бы раскрылся. Но поскольку доступ к этому значению имеют только доверенные функции из стандартной библиотеки, которые используют его "правильно", иллюзия сохраняется. На самом деле тип RealWorld — пустышка, и, увы, состояние мира на 2011 год там не хранится, а жаль.
По ссылке истинно случайные числа, и для их создания требуется аналоговый источник шума. Машина Тьюринга сама по себе их создавать не умеет, программируй её хоть на ФП, хоть на императивщине.
На а псевдослучайные числа в FP делаются точно так же, как и в императивщине:
https://hackage.haskell.org/package/random-1.2.0/docs/System-Random.html#v:random
(Обрати внимание на тип функции. g — это состояние генератора, a — полученное значение).
Только состояние PRNG (g) прячут не в статическую переменную, а в монаду.
Ну и для юнит-тестов даже в крестах часто юзается явное состояние ГПСЧ. Иначе потом фиг воспроизведёшь почему упало.
(Как же бесят люди, считающие медиану времени для бенчмарков с детерминированными знячениями ヽ(‵﹏´)ノ!)
Ня дружат они в том смысле, что их ня получится сделать "чисто", без дополнительных явных параметров/хаков с IO/спросите бородатых девочек-функциональщиц.
Лямбда крестоговна это такая же функциональщина, как и обычная сишкофункция, ничего такого ФП-шного оно не добавляет, просто позволяет определять функцию по месту и сразу ее вызывать. Оно и захватывать хуйню может внешнюю и менять ее, т.е. нихуя такого там нет, любое использование лямбд можно переписать на банальные функции.
Зачем мне создавать функцию в функции, если я могу просто написать код в том месте? Или функция должна быть рекурсивной т.е. уметь сама себя вызывать? Не, ну можно в принципе переделать вот ту хуйню https://www.govnokod.ru/19299 чтоб там гнутые расширения не использовались, и свой стек хуйнуть там для адресов возврата.
https://ideone.com/yqAHZq - можешь в вижуалстудии проверять
Чтобы передать её куда-то?
Кстати что с захватом скоупа у йажа колабл?
Как функции, которые где-то там генерируются.
>А захват скопа как будет устроен?
Указателями на переменные скоупа.
Я описал лямбду, которая захватила нужные мне переменные (она же кложа) причем ровно так, как я попросил (по референсу или копироваием) и я передал ее в функцию, которая ее как-то использовала
Если я верну указатель на что-то, что есть у меня на стеке, и потом выйду, то указатель укажет в жопу.
Это же не жабки с шарпами, где захваченные переменные живут, пока живет лямбда (отличный способ запутаться, и потечь памятью)
Во всех языках с GC можно кложей захватить пол стекфрейма, положить кложу в кучу, выйти из функции, и вызвать кложу.
Все твое говно сохранится
Вовсе ня обязательно.
https://wandbox.org/permlink/lCNDWAAjUflyrsUq
И кстати, где будет адрес переменной msg после этого std::move в лямбде? В стекфрейме main? В хипе?
Функция с ней ничего сделать ня сможет даже в теории, потому что по условиям задачи лямбда возвращается через return (ノ´ヮ`)ノ*: ・゚.
> или какая-то другая лямбда в той же функции
А для такого достаточно завернуть msg в shared_ptr и убрать std::move(msg). Сможешь ходить десять лямбд возвратить вектором.
> И кстати, где будет адрес переменной msg после этого std::move в лямбде? В стекфрейме main? В хипе?
Адрес — нигде. Сама строка msg будет лежать в объекте lambda — в стекфрейме main, в данном случае. Ну, если быть совсем точной — в этом примере компилятор эту лямбду заинлайнит, и никакого объекта lambda в асме ня будет.
Она-то может и возвращаться через return, но не сразу. Сначала она может куда-то передаваться, кто-то там эту лямбду повызывает, а потом уже та функция может что-то опять поделать с локальными переменными, и уже потом возвращать через return эту лямбду. Так что надо эти мувы делать именно при возврате, а не вот просто сразу.
> А для такого достаточно завернуть msg в shared_ptr и убрать std::move(msg). Сможешь ходить десять лямбд возвратить вектором.
Референс каунтер, коим этот shared_ptr является - уже анскильно и попахивает GC. Так-то можно все локальные переменные ф-ции через большой malloc выделять, завести счетчик на тот malloc-нутый адрес который декрементится когда лямбда юзающая маллокнутые хрени уничтожается, ну и надо регистрировать ситуации, когда на лямбды нет нигде указателей (счетчик для локальных переменных выделенных в хипе равен 0 - никакие лямбды уже его не юзают - можно освободить память). Эта питушня мне напоминает концепцию ownership из Rust https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
> Адрес — нигде. Сама строка msg будет лежать в объекте lambda — в стекфрейме main, в данном случае.
А если лямбда будет не из main а из какой-то другой функции доставаться, и та другая функция будет ту лямбду возвращать еще через return и так далее, то это всё будет через стек копироваться, да? Это анскильно.
А если ту лямбду в глобальную std::function присвоить, где будет храниться ее msg?
Т.е. нужно две почти одинаковые лямбды, одну мы передаем в функции как аргумент (притом ту лямбду лучше никуда в глобальные или статические переменные не присваивать, потому что она будет уже невалидной при выходе из скоупа той ф-ции в которой ее создали), другую в самом конце перед ретурном с std::move объявляем и возвращаем. Какой багор )))
разумеется "данные" не могут являть собой указатель на переменные внутри почившего в бозе стек фрейма
вроде как сишники и крестовики это должны учитывать, чай не джаваскриптеры
Страння, конечно: тебе показывают удобный, production-ready, инструмент, позволяющий сократить количество кода и ошибок, а ты в ответ нячинаешь яростно выдумывать миллиарды корнер-кейсов, когда этот инструмент работает не идеально. При этом в качестве няпобедимого образца ты демонстрируешь https://ideone.com/yqAHZq, в котором гордо городишь свой собственный стек. Это, няверное, должно быть образцом краткости, читаемости, удобства и производительности?
Вот именно, в крестах это всё неидеально. Если начать внимательно докапываться, всплывает куча всякой низкоуровневой хрени и подводных камней, типа что вот если мы передаем лямбду-захватывающую-локалки в другие функции, то вот те другие функции ни в коем случае не должны ту лямбду присваивать в некую глобальную переменную, которую потом можно вызвать по выходу из стека функции-с-той-лямбдой. Чтоб корнер-кейсов не было, достаточно просто взять язык с GC и не сношать себе мозг всем этим безобразием.
> При этом в качестве няпобедимого образца ты демонстрируешь https://ideone.com/yqAHZq, в котором гордо городишь свой собственный стек. Это, няверное, должно быть образцом краткости, читаемости, удобства и производительности?
О нет, я это естественно не приводил как образец читаемости, удобства и производительности. Это не более чем пример того, как можно сделать.
А ты хочешь одну кнопочку "сделать хорошо"? Ну извини, такого ня придумали ещё. Лямбды — это очень удобный и эффективный инструмент, позволяющий существенно снизить количество бройлер-плейта. То, что они ня работают как лямбды в языке с ГЦ — так извините, у нас не язык с ГЦ.
> типа что вот если мы передаем лямбду-захватывающую-локалки в другие функции, то вот те другие функции ни в коем случае не должны
Сделай [=] и спокойно присваивай что угодно чему угодно ценой лишних копирований. Чем эффективнее должен быть твой код — тем больше нядо писать, это в любом языке так. Если тебе важен каждый передвинутый байтик, то очевидно, что тебе придётся подробно объяснять компилятору, какие байтики двигать нядо, а какие ня надо (тут вызываю штатных девочек-волшебниц для демонстрации мощи Хаскелля и ко).
> Чтоб корнер-кейсов не было, достаточно просто взять язык с GC и не сношать себе мозг всем этим безобразием.
Будто бы в языках с GC корнер-кейсов и мозговыносящего няочевидного поведения меньше.
> Это не более чем пример того, как можно сделать.
А зачем он? Кажется, то, что C — тьюринг-полный ЯП, никто ня оспаривает. Через setjmp()/longjmp() и портянки макросов к сишке хоть полноценный гц можно прикрутить.
А еще можно все локальные переменные в функции с лямбдой выделять не на стеке, а на хипе одним большим куском, и в лямбде таскать указатель на область памяти с локалками. Много чего придумать можно.
> А зачем он? Кажется, то, что C — тьюринг-полный ЯП, никто ня оспаривает. Через setjmp()/longjmp() и портянки макросов к сишке хоть полноценный гц можно прикрутить.
Ну так я его не с нуля писал сейчас. История того говнокода восходит к https://www.govnokod.ru/19299 - я его просто слегка переделал, избавив от гцц-измов. В подписи к тому говнокоду написано, зачем это: "Этим кодом я доказывал одному типу какой-то бред, связанный с рекурсией. Типа он считал что ее нельзя реализовать через сраные циклы со стеком(или может просто хотел посмотреть на такую реализацию)."
> Типа он считал что ее нельзя реализовать через сраные циклы со стеком
Ну это он глупость сказал, конячно. А код, безусловно, изобретательный.
Лямбды крестов ничего принципиально не меняют, это такой какбы сахарок над объявлением статической функции, только такая функция не имеет никакого имени в рамках единицы трансляции, и указатель такой ф-ции присваивается в какую-то переменную, или же мы сразу вызываем эту лямбду, и тогда даже указателей никаких нет (но и с функцией такое тоже будет, если она заинлайнится). Захват переменных из скоупа это неявная передача указателей на эти переменные в лямбду.
Вот если б завезли лямбды как в языках-с-GC, когда можно что-то позахватывать лямбдой и не думать над тем, вышли мы из стекфрейма или не вышли из стекфрейма... но тут без какого-то GC или рефкаунтера мало что сделать можно. Рефкаунтер-то по сути огрызок GC, только циклические ссылки он чистить не сможет никак
> Вот если б завезли лямбды как в языках-с-GC
Я уже говорила выше: хочешь GC — сделай себе GC на shared_ptr, а лямбды в этом помогут.
— всё, ни о чём больше думать ня надо, код максимально короткий и выразительный. За простоту платим, во-первых, няобходимостью аллокаций (ня обязательно в куче, правда: можня сделать свой собственный аллокатор, который будет выделять память в глобальном массива байтиков, няпример), во-вторых — подсчётом ссылок при создании/уничтожении local.
Reference cycles RC решать не умеет (у ябла для этого были "слабые" ссылки, g: "strong weak dance").
GC называет такие штуки "isle of isolation", и выпиливает их.
Для разрешения циклических зависимостей существует std::weak_ptr. Но всем будет гораздо проще, если этих зависимостей ня будет вообще, как в приведённом мною примере.
А они вполне могут быть. Для std::weak_ptr то мы еще должны заранее знать, что вот эта лямбда1 владеет лямбда2 (на нее std::shared_ptr), а вот лямбда2 уже не владеет лямбда1 (на нее std::weak_ptr), а мы это можем не знать на этапе компиляции, связи между лямбдами могут формироваться динамически в процессе исполнения. Могут быть какие-то длинные кольца с этих лямбд, которые друг на друга ссылаются. Вот допустим образовался кольцевой связный список из этих лямбд, и на какую-то из лямбд указывает что-то, и допустим оно перестало указывать.
Какая из связей должна быть weak_ptr? Очевидно, чтобы этот цикл разорвался при убирани связи something-> , weak_ptr должен быть между lambda4 и lambda1
Но что если этот поинтер из something будет перставляться с лямбды на лямбду? Хо-хо-хо, тогда и weak_ptr должен мигрировать, т.е. нужно пробежать весь кольцевой список и переставить этот weak_ptr
Разве не охуенно? А если у нас не кольцевой связный список из лямбд, а вообще произвольная поебень может из этих ссылок сконструироваться? И GC бы эту проблему просто брал бы и решал, а в крестах тут всплывает какая-то непонятная херота, хоть GC пиши.
Там нет лямбд, нет динамической памяти, даже рекурсии нет. Можно вообще ни о чем не задумываться.
В "GC" ты можешь случайно зацепить лямбду оставив ее в какой-нить коллекиции, и она утащит за собой 300 мегабайт.
В крупном проекте по любасу нужно понимать что и где лежит и какие есть ссылки.
В том же ябле, например, были когда-то четкие правила на что нужно иметь weak ref, а на что нет.
> MIPS unlike other archs doesn't have a push or pop register/immediate instruction. So you rely on managing the stack yourself. This is actually noted in most of the arch outside of mul/div where your registers don't have a specific use, just a suggested way to use it. Now if you used it however you wanted, you would break something if you tried to integrate with C for example.
В x86-процессорах есть особый механизм кеширования, который завязан на call/ret
https://www.agner.org/optimize/microarchitecture.pdf - см. 3.16 Returns (all processors except P1)
"Страння, конечно: тебе показывают удобный, production-ready, инструмент, позволяющий сократить количество кода и ошибок, а ты в ответ нячинаешь яростно выдумывать миллиарды корнер-кейсов, когда этот инструмент работает не идеально."
На лицо неприятие всего нового, даже когда оно нужно и полезно.
А обмен корнер-кейсами можно проводить хоть до бесконечности: сделаешь substr(0, 10) от гигабайтной строки в языке-с-GC-ня-надо-думать — получишь утечку гигабайта.
Это не инструмент, это банальный сахарок над созданием функции где-то в текущей единице трансляции, ничего концептуально нового в язык не добавляющий. Любой код с лямбдой можно известно как переписать на код с вызовом функции, объявленной где-то в этом же файле.
Инструментом можно было б считать те же метаклассы, они вот реально много чего в языковых возможностях меняют
> Любой код с лямбдой можно известно как переписать на код с вызовом функции, объявленной где-то в этом же файле.
Любой код с сишки можня переписать на JavaScript. Означает ли это, что сишка не нужна?
> Инструментом можно было б считать те же метаклассы, они вот реально много чего в языковых возможностях меняют
Это не инструмент, это банальный сахарок над созданием классов где-то в текущей единице трансляции, ничего концептуально нового в язык не добавляющий. Любой код с метаклассом можно известно как переписать на код с явным class, объявленным где-то в этом же файле.
Нет. Сигфолт сишки от вылезания за пределы массива на JavaScript не перепишешь. И вообще, в JS указателей нифига нет.
любой код на тюринг полном языке можно переписать на другой тюринг полный язык, и наверняка ты это и без меня знаешь
А указатели вообще ня нужны: от них одни только сегфолты. Здоровым, адекватным джаваскриптерам вполне хватает ссылок.
Ха. Руками писать вместо метаклассов некую фигню-которая-синтезируется-метаклассами будет существенно сложнее, чем написать функцию, которая чего-то принимает как аргументы и что-то возвращает, и пользоваться ей вместо лямбды.
Вообще, все языки это сахарок над машинным кодом, кроме верилога какого-нибудь, который уже сахарок над топологией соединения и конфигурацией ячеек.
Пусть сложнее, а что концептуального нового-то? Вот я ня так давно писала генерацию методов у классов:
— как видишь, все эти ваши хвалёные метаклассы прекрасня эмулируются старым добрым препроцессором, а, следовательня, не нужны.
Между функцией в Си и лямбдой в каком-нибудь JS есть очень существенная разница, а между функцией в Си и лямбдой крестов разницы по-сути никакой нет, только небольшой плюс к удобству. Не, можно конечно и на Си и на крестах какими-то кривыми костылями с препроцессингом и кодогенерацией реализовать лямбду с рефкаунтингом и GC, только это уже будет совсем другая сущность, имеющая мало общего с той лямбдой, которая есть в крестах.
И метаклассы тоже можно к имеющимся крестам прикостылить, сделав транспайлер из одного стандарта крестов в другой
Да. Из этого можно сделать вывод, что ни сишка, ни ассемблер ня нужны: всем нужно срочно писать программы в машинных котах. Рекомендую WCT.
> Между функцией в Си и лямбдой в каком-нибудь JS есть очень существенная разница
Концептуально — нет никакой разницы. Джаваскриптовские замыкания (это ня то же самое, что и лямбды) можно, вооружившись препроцессором и такой-то ока-сан, сэмулировать и на C++, и на C.
Большой плюс к удобству, отсутствие длинного бройлер-плейта, статические гарантии (няпример, что ты ня забудешь прокинуть локальную переменную в инициализатор структурки-контекста), простой и удобный синтаксис определения списка захвата. Ну и давай посмотрим на реальный, однозначный пример:
В ручном подходе имеем целый ворох способов выстрелить себе в ногу (помимо тех, о которых ты тут целый день распиняешься), нявскидку:
1. Можно забыть иняциализировать "c": получишь nullptr внутри функции.
2. Каждую переменную из списка захвата упоминяешь два раза: в определении структуры и инициализации.
3. Меняешь тип локальной переменной — ня забудь пройтись по всем таким "лямбдам" и ручками меняй его.
4. Хочешь получать c по ссылке, а не мувать? Ня забудь убрать std::move() и изменить определение. Аналогичня — для всех остальных переменных.
Все эти проблемы крестовая лямбда эффективно решает: забыть инициализировать ничего нельзя, список захвата пишешь ровно один раз, все типы выводятся автоматически, способ захват чётко и ясно виден ровно в одном месте, и, что важно, прямо перед определением тела функции.
~ \{=^~^=}/ ~
Еще можно кое-какой хренью делать так, чтобы:
Я даже знаю, через какой препроцессорный костыль это можно было б сделать. Можно попробовать запилить такого макроговна, но как-то лень
А оно уже появилось.
https://archive.jlongster.com/Lisp--It-s-Not-About-Macros,-It-s-About-Read
> That should impress you. How would you do that in Python? Or Javascript? You need access to the AST and need to learn all the internal methods for parsing it. Lisp code is an AST.
homoiconicity!
Представляешь, как круто: вместо того, чтобы зубрить один C++, придётся в каждом проекте зубрить свой собственный C++! Зубрилки визжат от радости.
В абсолютном большинстве случаев стандартное лучше нястандартного. Лучше выучить один стандартный сахарок и везде использовать его, чем зубрить двадцать самописных сахарков, решающих одно и то же, но по-разному и с кучей неочевидных нюансов каждый. В реальном мире гомоиконность и прямая модификация AST — удел либо развлекательного программирования, либо фанатиков, не видящих дальше своего крошечного мирка.
О чём тут говорить, если даже при наличии хорошо сделанной банальной лямбды в нашем сообществе из 3,5 человек уже нашёлся желающий её переписать ня макроговно — исключительно потому, что NIH?
Исключительно чтоб показать, что даже кривым сишным препроцессором можно что-то похожее родить.
Это все прекрасно но дело в том что с++ не развивается в сторону мощного метапрограммирования не потому что benevolent dictator решил что обезьянкам оно не нужно а потому что как я понял из ваших разговоров децентрализованый комитет не умеет в последовательный дизайн. По-моему лучше бы уже децентрализовались до конца и сообщество каталось на велосипедах и в ходе рыночных процесов рождались хуевые или не очень решения, если комитет делает то же самое только долго и с претензией на правильность
Комитет как раз централизован, просто он адски нуден и няповоротлив — не в последнюю очередь из-за того, что в нём сидит приличное количество контрибьюторов в компиляторы, которые ня каждый пропозал с забористой метушнёй первым делом хватаются за волосы и орут о том, как же они это говно будут реализовывать. Многие же пропозалы просто забывают, впрочем.
И да, 10000 обезьян за клавиатурами обязательня няпечатают Идеальный Стандарт, но это будет не при няшей жизни.
для меня это выглядит как "медленное и долгое развитие"(велосипеды) и "очень медленное и бюрократизованное развитие"(комитет)
>И да, 10000 обезьян за клавиатурами
Это разговор в плоскости политики: как именно мы хотим управлять языком и если хотим демократично, то насколько прямой должна быть демократия.
Я хочу сказать что то что предлагает j123123 не является чем-то однозначно худшим чем то что есть сейчас и разговоры про NIH выглядят как рационализация твоей нелюбви к велосипедам
Ключевая разница в несовместимости. Единая и централизованная толпа макак — Комитет — делает хоть и условно, но совместимый и более-менее консистентный стандарт. А вот кто будет собирать по углам Гитхаба миллионы принципиально нясовместимых между собой поделий, полировать их и объединять во что-то более-менее прилично выглядящее — большой вопрос.
> и разговоры про NIH выглядят как рационализация твоей нелюбви к велосипедам
А что, есть люди, которые реально любят использовать велосипеды? Ну в смысле не писать их для развлечения или из большой нужды (когда ни stdlib, ни сторонние либы объективно ня подходят), а просто брать и совать в прод переизобретённые копии существующих и хорошо работающих вещей?
Ну буст же собрали и он как-то стал стандартом де-факто...
>миллионы принципиально нясовместимых между собой поделий
Это неправильная дихотомия и может быть множество вариантов "между", наиболее реалистичным будет несколько больших и известных экосистем и множество пакетиков для эзотерической хуйни которую уж найдет тот кому она нужна
>А что, есть люди, которые реально любят использовать велосипеды?
я не знаю грани после которой велосипед становится существующей и хорошо работающей вещью поэтому на вопрос ответить не могу
любопытно, как будет организована стондартизация крестговна в следующем цикле
Можно запилить стандартные лямбды, метаклассы и наследования в стандартной библиотеке на этой гомоиконности с модификацией AST.
А если кто-то решит свои альтернативные лямбды делать, то это уже его личное дело. Никто ж не запрещает свои говностроки изобретать под каждый проект
Именно. Только если с говностроками всё более-менее по-ня-тно (есть говнокласс, у говнокласса есть конструкторы/методы/деструкторы, открыла объявление и читай), то гомоиконность — это прямой путь к изобретению собственного говноязыка говнопрограммирования, который надо учить заново. И так ня каждом говнопроекте.
В реальном мире гомоиконность и прямая модификация AST — удел либо развлекательного программирования, либо фанатиков, не видящих дальше своего крошечного мирка.
Проблемы негров шерифа не волнуют. Ежели кто будет по мини-говноязыку изобретать на каждом говнопроекте, а потом искать зубрилок, которые эти говноязыки будут готовы расширять и писать на них, это уже его проблемы.
Как я уже сказал, проблемы негров шерифа не волнуют. Если программисты такие ебланы, что понаделают какого-то нечитаемого мета-говна на гомоиконах, то это ИХ ПРОБЛЕМЫ. Значит пусть делают из этого какие-то оргвыводы и договариваются о том, что надо б вот эту готовую мета-либу использовать, а не свои велосипеды через модификацию AST городить. Или можно вообще отключить эту фичу с модификацией AST флагом компилятора (или забыть о ее существовании), и писать без нее.
> C++ — довольно таки примитивное, но монстровое поделие, полное исторически сложившихся нелепых нагромождений. Человек, который хорошо в нем ориентируется — это хорошее зубрилко, а не хороший программист.
Итого, ты против C++, потому что в нём слишком много нагромождений, которые нядо зубрить. В качестве решения ты предлагаешь прямое управление AST, чтобы любая закорючка могла означать что угодно, правильня?
Не совсем так. Там не просто слишком много нагромождений, оно еще и хуево спроектировано. Мне например не нравится механизм обработки исключений. Мне не нравится что std::string не умеет CoW. Мне не нравятся тупые и долбанутые правила наследований, не нравится ООП в реализации C++ и вообще в целом ООП мне не нравится, это какой-то сраный мусор, который надо облить бензином, поджечь, обоссать, залить бетоном и скинуть на дно Марианской впадины.
> В качестве решения ты предлагаешь прямое управление AST, чтобы любая закорючка могла означать что угодно, правильня?
Когда мне это реально надо, тогда да. В целом кресты - хуево спроектированный язык, где надо в уме держать кучу говноньюансов всякого говна, и лучше сделать другой язык.
Да. Только немного ня ясно, почему тебя особення обозлил один из нямногих действительно грамотно и удобно спроектированных сахарков в виде лямбды.
> Когда мне это реально надо, тогда да.
А неограниченное управление AST реально нужно примерно в 0% случаях, потому что изобретение DSL на пустом месте для решения частной задачи — это прямой путь к няподдерживаемому говну, которое читать сможет примерно 1 человек в мире и то только один месяц после няписания.
Да я и не обозлился.
>А неограниченное управление AST реально нужно примерно в 0% случаях, потому что изобретение DSL на пустом месте для решения частной задачи — это прямой путь к няподдерживаемому говну, которое читать сможет примерно 1 человек в мире и то только один месяц после няписания.
Так я и не призывал каждый раз свой велосипед изобратать. Когда мне нужно было на контроллере сделать быстрое преобразование Фурье, я почему-то не начал писать свою реализацию с нуля, я поискал по гитхабу, нашел некоторое количество либ, решающих мою задачу, выбрал одну из них и всё. Если б в условном языке X изначально не было фичи Y но она была б реализуемой через механизм управления AST, и мне такая фича была б сильно нужна, я б тоже первым делом пошел искать мета-либу, которая б эту возможность добавляла. Не вижу между этими двумя кейсами никакой существенной разницы
Ну ладня.
> Не вижу между этими двумя кейсами никакой существенной разницы
Разница в том, что "обычная" либа не изме-ня-ет сам язык. Какую бы ты крестолибу ня взял — const у тебя останется модификатором константности, шаблоны будут объявляться через template<...>, а в квадратных скобочках будут либо объявления массивов, либо индексация, либо лямбда (ой, ня очень хороший пример (ノ*°▽°*)).
А вот с металибами всё будет по-другому: они по определению будут добавлять в твой проект новые закорючки, новые скобки, новые модификаторы и так далее. По отдельности это ещё можно терпеть, но вот когда ты подключишь пяток таких стильных модных лисподобных либ — ты внязапно обнаружишь, что вместо любимой сишечки ты пишешь ня какой-то дикой солянке из нясочетающихся языковых элементов, придуманных вообще никак не общающимися друг с другом людьми. И если уж даже вроде как совещающийся Комитет сделал говно, то толпа несвязанных макак сделает твою жизнь нявыносимой.
Мета-либы в гомоиконном языке через S-expr делать, и тогда новые закорючки появляться не будут. Какая-нибудь лямбда может записываться как-нибудь так например:
> По отдельности это ещё можно терпеть, но вот когда ты подключишь пяток таких стильных модных лисподобных либ — ты внязапно обнаружишь, что вместо любимой сишечки ты пишешь ня какой-то дикой солянке из нясочетающихся языковых элементов, придуманных вообще никак не общающимися друг с другом людьми.
Слишком категоричные и общие утверждения. Тут всё завист от конкретики, как эта работа с AST реализована, каков изначальный синтаксис и система типов в конкретном ЯП, насколько интуитивно синтаксис отображаем в непосредственно AST
И даже так семантику происходящего ты никак ня узнаешь. Что эта лямбда делает с переменными, что можно с ней делать, какие някладные расходы у её создания, какие побочные эффекты — совершенно ня ясно. Она тебе может скобочки перегрузить, а ты и ня узнаешь.
> Тут всё завист от конкретики, как эта работа с AST реализована, каков изначальный синтаксис и система типов в конкретном ЯП, насколько интуитивно синтаксис отображаем в непосредственно AST
Дело не в интуитивности, дело в семантике. Прямое управление AST нужно только для одного: для горожения собственных DSLей, для изменения семантики языка.
Для этого есть документация или сам код металибы на худой конец.
> Дело не в интуитивности, дело в семантике.
Ну так если у меня AST близок к синтаксису (s-expr как в лиспах), и у меня есть металиба, которая имеет права на чтения всей единицы трансляции, а конструировать AST фигню она допустим может только лишь в особо огороженных предварительно прописанных областях, то можно просто посмотреть, во что конкретно такая-то лямбда развернется вот там-то и там-то. А если язык с синтаксисом как в крестах с какими-то [](){}<blabla<kokok{}<kukarek> > то хрен там плавал
Ну да, и так мы получаем ограниченное управление AST, о чём я и говорила изнячально. Опять же, что-то похожее, но ещё чуть-чуть более ограниченное, предлагает Саттер в своих метаклассах.
Что значит "изменения семантики?" Вот, к примеру, мой самый метушистый проект с прямым управлением AST: https://github.com/k32/typerefl
Он никакие семантики не меняет, а добавляет некоторые фичи языку, которые иначе делались бы бойлерплейтом.
Другой мой DSL (не опенсорсный) был более близок к изменению семантики, но в нём магия кастовалась через синтаксическую конструкцию, заведомо не имеющую смысла в базовом языке.
Манипуляция AST даёт совсем другие возможности, нежели & в крестах перегружать. Вот пилить DSL на крестах с помощью перегрузок — это априори говно, тут соглашусь.
И ты получаешь новый язык-нядмножество исходного, пони-мать который становится капельку сложнее. И чем больше таких фич добавляется — тем меньше готовый продукт становится похож на оригиняльный, что в пределе выливается в отдельный диалект (привет, Lisp!). А уж если AST можня крутить как угодня безо всяких ограничений, то дробление языка ня кусочки просто няизбежно.
Не понимаю наезда. Даже тупенькие джависты, которые боятся перегрузок, ибо сложна, ничего не понятно, используют аннотации. Тут тоже самое: видишь аннотацию, понимаешь, что она превращается в такую-то фигню.
> А уж если AST можня крутить как угодня безо всяких ограничений, то дробление языка ня кусочки просто няизбежно.
Дробление языка на кусочки прекрасно делается и без помощи трансформации AST. Достаточно заиметь две либы, использующие разные имплементации строк. (Привет, haskell, с пятью типами строк)
Кстати, хорошая идея, надо запилить.
Проблема в том, что все либы пишут дураки разной степени дурашливости — причём как субъективно, так и объективня. Поэтому ЯП общего нязначения (в отличие от нямеренно элитарных, вроде того же Хаскелля) обязаны соблюдать баланс: они должны, с одной стороны, достаточно ограничивать дураков, чтобы они ня начли творить беспредел, а с другой — давать достаточня возможностей творить беспредел тогда, когда он будет уместен.
> В теории, конечно, можно запилить parse_transform, который все строковые литералы заменяет на цитаты из зелёного слоника
На няфицированные цитаты из Зелёняго Слоняка!
Применяем к коду:
Выводит
Ну да, я об этом и пишу: чем сильнее метушня ограничена — тем меньше от неё вреда.
Возможность управления AST можно сравнить с няявными преобразованиями типов: когда их слишком мало — получается унылый бойлерплейт "foo(intVar.toLong())", когда их слишком много — получается 16 + "JavaScript".
Хорошо, когда AST можно дёргать чуть-чуть: это избавляет от бойлерплейта. Плохо, когда AST можно дёргать как угодно, и подключённая металиба перегружает тебе пробелы.
> Достаточно заиметь две либы, использующие разные имплементации строк.
Да, строки лучше иметь в стандартной библиотеке. Вот бы они в C++ были...
Так-то можно сделать ограниченную метушню из неограниченной, и пользоваться этой ограниченной метушней. К неограниченной метушне прибегать только в случае крайней на то необходимости, соблюдая все меры предосторожности. Если какие-то дураки будут неограниченную метушню использовать по поводу и без, это уже их личные проблемы, в условиях свободной конкуренции их кривыми говнометалибами пользоваться не будут и их говнометушня канет в лету.
В условиях свободной конкуренции PHP стабильня входит в топ-10 самых популярных языков программирования. C++, кстати, тоже.
А личные проблемы дураков в один прекрасный момент внязапно станут твоими проблемами, когда тебе вдруг понядобится специфическая либа или поддержать чужой проект.
Нят, в принципе, если все свои проекты ты пишешь в одиночку и никогда чужой код ня читаешь — то такой образ мышления вполне себе работает.
Потому что есть много написанного на PHP и C++ кода. А если какой-то Васян напишет какую-то говнолибу, то надо еще чтобы она стала популярней других либ, решающих ту же задачу. И если либа Васяна - говно на фоне других либ, вряд ли она станет популярной. Популярной она может стать лишь в отсутствии конкурентов, и потом заменить такую либу будет проблематично, если много что на ней завязано.
Если б C++ появился одновременно с появлением Rust, и при этом не было б никакого языка Си, который достаточно с крестами совместим (т.е. если б C++ был вообще с нуля придуман, и нельзя было сишкокод переиспользовать) то что-то я сомневаюсь, что кресты б выиграли в этой конкуренции.
Можно сделать некие правила, ограничивающие область работы металибы вот таким-то участком кода (скоупом функции, или вообще условием внутри некоего цикла, если удобно), ну типа
Ну да, а потом придёт k234234 и начнёт утверждать, что это анскильно, дайте мне возможность перегрузить пробел во всём TU.
В пропозале с метаклассами, кстати, специально выделено (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0707r4.pdf):
Саттер всё предусмотрел.
Ну так всю TU завернуть в %%USE_METALIB1%% можно, но если чего-то не так будет, это уже твои проблемы. И да, если к некоторому куску кода применять более одной металибы, то порядок может иметь значение. Например если одна либа заменяет пробелы на запятые, а другая заменяет запятые на пробелы, а в коде есть и пробелы, и запятые.
— имення потому, что слишком упоротое метапрограммирование приносит крайне мало пользы, зато количество способов выстрелов в ногу увеличивается в геометрической прогрессии.
И да, те же концепты, няпример, нямеренно упрощают шаблонное метапрограммирование, делая ручное сфинячество нянужным. И это хорошо.
* Правда, понять, как пофиксить эту дыру, они пока что ня смогли.
Стандартного сахарка может быть мало, а когда (если) комитет разродится стандартом, где появится нужный тебе здесь и сейчас сахарок, ты уже можешь сменить работу и даже уйти на пенсию.
Захвачены будут только те переменные, которые упомянуты в теле. Ручной же эмуляции всё равно придётся прописывать весь бойлерплейт и своевременно обнявлять его.
Коротко, красиво, ясно, УДОБНО.
> Вообще, все языки это сахарок над машинным кодом, кроме верилога какого-нибудь, который уже сахарок над топологией соединения и конфигурацией ячеек.
Всё так.
так что неудобства минимальны, а реверсить в разы, если не на порядок сложнее
Это классический баг программиста, я вижу его постоянно, он называется "не решает всех проблем".
Некто пользуется инструментом $FOO.
Ему говорят: инструмент $BAR позволяет делать тоже самое, но писать при этом меньше кода
Некто отвечает: но $BAR ведь тоже не решает всех проблем, так что $BAR не нужен.
Примеры:
"Статическая типизация не решает всех проблем, можно написать код с ошибками, который скомпилируется. Следовательно, она не нужна" (с) питонист
"ORM не решает всех проблем, иногда нужно писать SQL вручную, следовательно ORM не нужен"
итд
*Это, конечно, ня так.
Изучение Крестостандарта — главная ценность в мире крестоблядей. Твой вес в этом обществе определяется не размером счета в банке, а тем, насколько ты продвинут в знании Крестоговна.
Человек, который хорошо в нем ориентируется — это хорошее зубрилко, а не хороший программист.
Умение героически преодолевать трудности, которые создает твой собственный инструмент, вместо того, чтобы решать непосредственно прикладную задачу, в современном мире ценится разве что только среди прыщавых сосок.
Работодатель же это сомнительное умение не ценит, и совершенно справедливо.
высказываний vsl про modern c++ к сожалению не сохранилось
Пожалуйста:
https://wandbox.org/permlink/qXV0Y5ryFQIO1WAx
> Референс каунтер, коим этот shared_ptr является - уже анскильно и попахивает GC.
Вам шашечки или ехать?
> то это всё будет через стек копироваться, да?
Что "всё"? msg — это, грубо говоря, size_t и указатель. Да, size_t и указатель будут копироваться через стек.
> А если ту лямбду в глобальную std::function присвоить, где будет храниться ее msg?
Детали реализации, нясколько я знаю. Но std::function — сама по себе крайне тяжёлая, в контексте подсчёта байтиков её использовать страння.
Переменных может быть и побольше. Но так-то да, все переменные можно выделить в одном аллоцированном куске памяти в хипе и просто таскать указатель на этот хип, и при возврате лямбды через return просто пробрасывать этот указатель.
Можно соснуть в openbsd с w^x, там вроде нельзя писать в страницу, а потом поменять ее на execute, если ты не слинковался со спец ключом, который тебе в заголовки ELF добавил запись типа "снять защиту"
Да, примерно так. Для ARM-ов надо еще какие-то кеши сбрасывать, а то можно огрести
Просто это корявенько.
Причем в сишке это можно делать 50 лет как, а в котором мейнстим говне (не будет показывать на джаву пальцем) это добавили совсем недавно (до этого эмулировалось через классы)
А в фортране ASSIGNED GO TO есть. Вместо указателя на функцию можно номер строчки передавать ^___~
> (до этого эмулировалось через классы)
Там и сейчас, вроде, нормального стрелочного типа нет, вместо него инстансы Function генерятся.
В GNU C есть такое расширение, и у меня про него говнокод был примерно 5 лет назад https://govnokod.ru/19105