Как стать автором
Обновить

Комментарии 361

Как все знакомо... С - первая любовь (начинал еще когда плюсов не было). С++ - первые реализации ("С с классми") - зашли, а вот все что началось дальше - уже нет. Ну то есть умею в некоторой степени, но не более того. И не претендую на глубокие знания в этой области.

Но вот 6 лет назад (скоро уже 7 лет) занесло на узконишевую платформу IBM i и специфические задачи - работа с БД и коммерческие расчеты. И обнаружил что если есть язык, специально предназначенный для решения какого-то класса задач, то решать эти задачи на нем и проще и быстрее и эффективнее чем на любом языке "для всего". Потому что он специально под эти задачи сделан. И код на нем получается простоя и понятный. И работает он быстро и эффективно. И вот прям зашло... Хотя если что-то низкоуровневое-системное, то тут, конечно, С удобнее...

Numba

что если есть язык, специально предназначенный для решения какого-то класса задач, то решать эти задачи на нем и проще

Поздравляю парни, да вы открыли понятие DSL!

А любой DSL можно на любом другом языке реализовать. Хоть на Python, хоть на C++, да хоть на JSON.

И это не проблема "базового" языка, это проблема продуманности (или, что чаще встречается - непродуманности и/или излишней абстрактности-заумности) предлагаемых API и прочих специфичных задаче сниппетов и структур.

Применительно к С++ это и вовсе означает очевидное - пора выбросить многовековое нагромождение шаблонных несуразиц по имени STL как "стандарт", которое задает тон всем остальным библиотекам, и заменить чем-то более простым, понятным, адекватным и современным.
Взяв лучшее от "C++ вытеснителей".

И дело пойдет. Но никто пока не решается.

Применительно к С++ это и вовсе означает очевидное - пора выбросить многовековое нагромождение шаблонных несуразиц по имени STL как "стандарт", которое задает тон всем остальным библиотекам, и заменить чем-то более простым, понятным, адекватным и современным.Взяв лучшее от "C++ вытеснителей".

Ок. Выкинули все из С++. Теперь вопрос - вы работаете с БД. В больших объемах - лопатите десятки и сотни миллионов записей по многим таблицам.

И вот простенькая задачка - прочитать запись из одной таблицы по ключу, как-то поработать с ее полями (а там могут быть date, time, decimal, numeric) и положить запись в другую таблицу. Сколько зависимостей вам придется подтянуть в С++ и сколько кода написать. А на советующем DSL это выглядит так:

dcl-ds dsMyFileRec likerec(MyFile.MyFileRecF: *all);

chain (KeyValue) MyFile.MyFileRecF dsMyFileRec;

dsMyFileRec.numericFeild += 1;
dsMyFileRec.dateField += %days(3);

update MyFile.MyFileRecF dsMyFileRec;

5 (пять) строк кода.

1 - объявили структуру "такую же как формат записи MyFileRecF в таблице MyFile

3 - прочитали запись для значения ключа KeyValue в эту структуру

5 - увеличили в записи поле numericFeild (допустим, оно имеет тип NUMERIC - это тип данных с фиксированной точкой) на 1

6 - увеличили дату в поле dateField на три дня

8 - сохранили запись обратно в таблицу

Заметьте - все это на 100% средствами языка и в рантайме не создано ни одного дополнительного объекта (чтобы работать с типами numeric и date) - все типы данных, что есть в БД, нативно поддерживаются языком.

Это можно написать на С++. Но так написать не получится. Будет длиннее и много лишних телодвижений.

Хитрые сипипишники скажут - просто надо воспользоваться каким-нибудь фреймворком или библиотекой на С++ для БД!

Хитрые сипипишники скажут -  просто надо воспользоваться каким-нибудь фреймворком

Как хитрый C++ ник я могу сказать - ничего лучше INSERT INTO table2(...) SELECT ... FROM table1 до сих пор не придумано.

Если не хватает базового SQL (и каких cross-database links), то есть понятие EXTERNAL TABLES, когда вывод некого скрипта можно представить для сервера баз данных как виртуальную таблицу (к примеру в .CSV формате) и далее опять куда там нужно тебе INSERT INTO SELECT FROM

И то - это если у тебя какого PL/SQL нет под рукой (который вполне покрывает 99% задач по трансформации данных).

Это если говорить о реалиях реальной жизни.

А если говорить о "взагали по взагалях" и как оно неплохо было бы - то возможности C/C++ тебя не ограничивают, упарываться в DSL можно как угодно - к примеру из таблиц/вьюшек нагенерировать классов в стиле OORM. И взять любой из десятка доступных API - от преснокислого ODBC до прям специализированных, OCILIB какой к примеру очень и очень неплох.

Вопрос то в чем собственно? Если не удалось найти достаточно выразительный и удобный DSL (а SQL и PL/SQL это как раз примеры очень удачных DSL), то напиши свой. И документацию к нему не забудь. Для себя-же, который будет это все потом через пару лет читать и материться, в духе "какой же баран это все так криво понаписал".

Если не хватает базового SQL (и каких cross-database links), то есть понятие EXTERNAL TABLES, когда вывод некого скрипта можно представить для сервера баз данных как виртуальную таблицу (к примеру в .CSV формате) и далее опять куда там нужно тебе INSERT INTO SELECT FROM

А теперь представьте, что только один ваш процесс молотит сотни миллионов записей в сутки. А разных процессов на сервере тысячи крутятся. Вот прилетает вам структура. В качестве параметра. Из нескольких десятков полей. И вам нужно прогнать ее через десяток разных проверок ("проверка" - это некий набор условий для параметров из этой структуры) и выдать результат - прошло/не прошло, если не прошло то где и почему. И таких вызовов реально может быть миллионов сто и более. Все эти "виртуальные таблицы в CSV" на таких объемах просто встанут колом.

Ну или вот задачка. Есть клиенты. Их 50млн. У каждого 5 типов адресов. Это с одной стороны. С другой стороны есть "субъекты списков росфина" (террористы/экстремисты всякие). Их... ну тысяч 300, положим. И у каждого по 2-3 адреса.

Ваша задача найти совпадения адресов клиентов с адресами субъектов. Совпадением считается когда все уникальные элементы (слова) адреса субъекта входят в адрес клиента (порядок следования не важен, дубли не важны).

И как решать будете? Прикиньте количество комбинаций (пар для сравнения).

С учетов способа хранения всего этого в БД (в виде витрин, где все адреса уже разложены по элементам) можно сделать все это скулем. Запрос получается на три страницы. И работает очень долго (на тестовом юните, где данных кот наплакал - субъектов там реальные объемы, но клиентов всего-то тысяч 20) оно работает где-то 60-70сек. На бою это растянется на несколько дней, что неприемлемо.

А на DSL, без скуля вообще все это работает в разы быстрее (на тех же данных на тесте 4.5сек). Хотя бы за счет того, что там большая часть поверок идет без чтения записи в БД. Просто по наличию соотв. ключа в индексе (да, DSL такое позволяет - просто посмотреть есть оно в индексе или нет, не лазя в саму таблицу за записью).

Ну а если нужен скуль -

       dcl-proc GetCustInf;
         dcl-pi *n extpgm('CUS001');
           inCusNo like(arCNum) const;
           outName like(arName);
           outAddr1 like(arAdd1);
           outAddr2 like(arAdd2);
           outCity like(arCity);
           outState like(arStte);
           outZip like(arZip);
         end-pi;
         exec sql select arName, arAdd1, arAdd2, arCity, arStte, arZip
                  into  :outName, :outAddr1, :outAddr2, :outCity, :outState,
                        :outZip
                  from   ARMSTF1
                  where  arCNum = :inCusNo
                  fetch first 1 row only
                  with CS
                  use currently committed;
         return;

Просто вставляем SQL запрос в код на DSL. А всю сложную логику пишем на DSL. Никто не запрещает. Embedded SQL называется. Запросы любой сложности. С подзапросами и прочим. Можем из программы на DSL вернуть SQL ResultSet если надо. Можем принять ResultSet из другой программы.

У нас каждая поставка проходит обязательное нагрузочное тестирование на копии промсреды. Да и на тестовых юнитах есть инструменты снятия статистик по производительности. Так что как сделать это максимально быстро - тут уже шишек понабито изрядно. В каком случае скулем лучше, в каком - прямым доступом.

Все эти "виртуальные таблицы в CSV" на таких объемах просто встанут колом.

Почему они встанут колом? Эти виртуальные таблицы (в формате CSV) можно чем угодно делать - от bash до С/С++, да хоть на ассемблере. В базу данных подается просто готовый результат уже, который нужно сохранить (если нужно). Возможно сейчас не совсем было понятно, что такое EXTERNAL TABLES и как они работают, но... можно погуглить наверное. В простейшем случае это SELECT FROM stdout - а кто в этот stdout пишет и что именно - это вопрос десятый.

А так - для современной базы данных сотни миллионов записей в день это не проблема. Там практический лимит был для типового не очень свежего 16 ядерного x64 сервера около 5 млрд. записей, по 100 байт каждая, в сутки. С парой индексов сверху. Без индексов сильно больше. И то оно все упиралось просто в хранилище. А если direct path insert какой взять INSERT /*+ APPEND */ в простонародье, и без логов - то там и сильно больше 5 млрд можно осилить. Не в один поток естественно это все.

Другой вопрос - где вы такие объемы берете-то.
Но С++ там точно не серебряная пуля, основные временные затраты идут вовсе не на клиентской стороне.

Просто вставляем SQL запрос в код на DSL. А всю сложную логику пишем на DSL. Никто не запрещает. Embedded SQL называется.

Честно говоря - писать свой DSL для подобного - не очень убедительно. Но хотите так (через самописный DSL, а не через EXTERNAL TABLES генераторы-врапперы) - никто не против, так тоже можно.

Другой вопрос - где вы такие объемы берете-то.

Да объемы не вопрос. Банк. 50млн клиентов. И у каждого куча данных. Счета (у крупного корпората их может быть сотня, у обычного физика и то десяток счетов, считая кредитные и депозитные, не редкость), карты (плюс держатели карт), доверенные лица всякие, клиентские данные - документы, адреса, доверенности, контакты... А еще всякие риски, платежные документы, проводки...

Сколько там всего этого трудно сказать. По самым грубым оценкам - несколько десятков тысяч объектов БД.

И при этом на сервере одновременно крутится десятки тысяч разных бизнес-процессов. С достаточно сложной логикой (там не просто из одной таблицы в другую перекладывать данные).

писать свой DSL для подобного

А кто говорил про самописный? Это не самописный язык. Речь про RPG. Он с 1959-го года существует. В целом, все, что можно написать на С, можно написать на RPG и наоборот. Но сравнивать их бессмысленно т.к. есть вещи, которые удобнее и быстрее писать на одном, а есть - на другом. Бизнес-приложения - это про интенсивную работу с БД и всякие расчеты, связанные с датами, временем и деньгами (а деньги считаются только в формате с фиксированной точкой). Поэтому вполне логично, что все это реализовано на уровне языка.

И да, вопрос производительности стоит крайне остро. Потому что в нормальных условиях нагрузка на сервер 50-60%, а в пиковых (например, предновогодний шоппинг) может резко подскочить до 90... Сервер - 120 8-поточных ядер Power9.

И на нагрузочном тестировании смотря на все - создаешь какие-то временные объекты - к тебе будут вопросы. Излишнее переоткрытие файлов - будут вопросы. Даже за слишком интенсивное использование динамической памяти спросить могут (предпочтительнее использовать статику - с памятью тут проблем нет, во-первых, тут одноуровневая память, во вторых на сервере 12Тб оперативки стоит).

Насчет DSL-подхода (и, что характерно, на примере все той же задачи взаимодействия с БД) весьма неплохо написано вот в этой статье: https://habr.com/ru/articles/422667/

И должен констатировать, что опыт вынуждает с ним согласиться.

Откуда уверенность, что DSL это обязательно какой-то самописный велосипед?

Вот есть у IBM платформа IBM i - middleware коммерческие серверы. Для бизнеса в первую очередь. История там длинная, если закапываться совсем вглубь, то можно дойти до System/3. "Новая история" - System/38 -> AS/400. Дальше уже больше ребрендинга. Сейчас оно называется IBM i (есть еще мейнфреймы IBM z, но они от System/390 идут, это другое).

И есть на этой платформе DSL - RPG Корнями уходит в 1959-й год (первая реализация эмулятора табуляторов для IBM 1401).

Так вот, на нем тут пишется более 80% кода. Де-факто на этой платформе это стандарт. Появился SQL - добавили в RPG возможность встраивать SQL в RPG код (exec sql ...).

И да, для решения задач в тех областях, где эта платформа используется, это самый эффективный путь. Можно пробовать (и пробовали) делать все то же на С. Или на С++. Но ни по скорости разработки, ни по качеству результата никакого выигрыша нет. Скорее даже наоборот. Будет прикручивать к тому же С++ кучу зависимостей, чтобы получить то, что в RPG уже есть на уровне языка. То, что в RPG реализуется compile time типами, в C++ будет реализовано создаваемыми в runtime объектами (а это лишнее время и лишние ресурсы).

Но если мне, например, нужно удобное API для работы с какой-нибудь User Queue (есть такой тип системного объекта), я сделаю это на С. А потом буду использовать из RPG приложений уже под бизнес-задачи. Ну и до кучи напишу на RPG UDF/UDTF чтобы можно было со всем этим из SQL работать.

Синтаксис выглядит забавно. Мы в oracle apex подсмотрели такой подход, чтобы не объявлять десятки переменных l_out_name ARMSTF1.arName%type;:

procedure get_custInf(
    p_arcnum in ARMSTF1.arcnum%type
) as
    cursor l_c is
    select
        arName,
        arAdd1,
        arAdd2,
        arCity,
        arStte,
        arZip
    from
        ARMSTF1
    where
        arCNum = p_arcnum
    fetch first 1 row only;
begin
    for i in l_c loop
        -- i.arName etc
        exit;
    end loop;
end get_custInf;

Минус фреймворка в том, что там слишком много чего делается в рантайме. В приведенном выше пример структура - статическая. Она "раскручивается" на этапе компиляции. Ровно так, как если ее просто руками наколотить в структуре записи в БД. И никаких маппингов, никаких дополнительных объектов в рантами не создается. И типами с фиксированной точкой, датами, временем работает точно также как в С работаем с int или double... Ну есть специфические операции типа операций с округлением - просто нужно специальный модификатор поставить который указывает что делать при уменьшении количества знаков после запятой - откидывать или округлять. Но это уже тонкие тонкости всякие. А если пишем a = b + c, то все три переменных могут быть любого числового типа - int, float, decimal, numeric...

>Минус фреймворка в том, что там слишком много чего делается в рантайме

Сделайте фреймворк, который будет делать "слишком много" не в рантайме, в чём проблема?

Дело в том, что у меня нет нужды делать какие-то фреймворки.

>обнаружил что если есть язык, специально предназначенный для решения какого-то класса задач, то решать эти задачи на нем и проще и быстрее и эффективнее чем на любом языке "для всего"

Так речь не о вас, а о вашем ошибочном суждении. Конечно ошибочно оно не только у вас, если посмотреть на весь зоопарк DSL.

>И никаких маппингов, никаких дополнительных объектов в рантами не создается. 

Сделайте ещё специализированную БД и прикрутите к ней этот фреймворк и там тоже не потребуется создавать маппингов и прочих рантаймов. А потом посмотрим, что будет эффективнее - ваш DSL или специализированная система.

dcl-ds dsMyFileRec likerec(MyFile.MyFileRecF: *all);

chain (KeyValue) MyFile.MyFileRecF dsMyFileRec;

dsMyFileRec.numericFeild += 1;
dsMyFileRec.dateField += %days(3);

update MyFile.MyFileRecF dsMyFileRec;

5 (пять) строк кода.

Простите конечно, но чем псевдокод лучше вот такого? Строчек ровно в два раза меньше.

UPDATE myFile rec
   SET rec.numericField = rec.numericField + 1,
       rec.dateField = rec.dateField + 3 -- ook, Oracle specific
WHERE  1 = 1; --  likerec(MyFile.MyFileRecF: *all)

Ну да, += в SQL так и не завезли, печаль печаль огорчение :) Но по сути, чем вот то что выше лучше? Возможности вставить произвольное процедурное в процессе - это тоже есть, можно на каждое UPDATE хоть JSON запросы на внешние вебсервисы дергать, и даже результаты в другие вебсервисы засылать, есть и такие средства.

Ну я привел пример из серии Hello Word. И это не псевдокод. Это реально скомпилируется и реально сработает. Оно действительно вот так просто все.

Но в реалии все намного сложнее в плане логики. Плюс очень жесткие требования по производительности, которые скуль в большинстве случаев просто не вывозит - для нас работа с объемами в десятки и сотни миллионов записей не редкость.

Начать с того, что эта структура может вам не из БД прийти, а как параметр вашей процедуры (допустим, это некий актор). И вам нужно будет произвести несколько десятков манипуляций с разными ее полями, подтягивая дополнительные данные откуда-то. А потом отдать ее обратно уже в модифицированном виде. И так 100млн раз в день (примерно с такими объемами работает комплекс комплаенс-проверок в системе контроля платежей).

Про возможность вставлять SQL запросы непосредственно в код написал выше. Иногда быстрее и эффективнее действительно тянуть данные из БД SQL запросом. А иногда наоборот - прямой доступ и по времени и по ресурсам будет выгоднее. Это уже на основе накопленного опыта понимаешь где что лучше.

До того, что иногда быстрее сделать избыточный запрос без группировки, а всю агрегацию выполнить средствами языка.

В общем и целом - чем больше разных вариантов и доступных средств, тем больше возможностей выбрать наиболее оптимальный под конкретную задачу.

В общем и целом - чем больше разных вариантов и доступных средств, тем больше возможностей выбрать наиболее оптимальный под конкретную задачу.

В современном мире использовать SQL для highload runtime, да еще и с гарантией по времени отклика - да, это так себе идея. Тем не менее, о чем вообще спор был изначально?

С++ вполне может быть адекватен даже для бизнес задач. Для тех самых типовых задачек вида "конвертируем что-то из одного условно-табличного вида в другой" (к которым сводится 99.9% всех айтишных задач).

Все упирается лишь в написание нормальных API, чтоб были максимально приближены к DSL/решаемой задаче. А вот с этим проблемы, просто потому что удачных примеров очень мало.

В современной разработке что C++, что Java подходы из коробок/книжек - они, изначально, мягко говоря, не про бизнес задачи. Сильно много слов заставляют писать не по "теме".

LINQ вот еще подавал надежды, но тоже сдулся. lsFusion еще тут мелькал, как альтернатива 1С, но... не будем больше о грустном.

По хорошему нужно что-то, что может в одном адресном пространстве (без всяких IPC/TCP/etc) иметь сразу и ORM, и SQL, и сразу HTTP(s)/JSON, и чтоб быстро и чтоб надежно, и еще column-storage. И без лишних конвертаций туда-сюда. И чтоб язык был хороший для "скриптов".

Tarantool еще, ах да. Интересно, так и пытаются LUA продавать?

LINQ вот еще подавал надежды, но тоже сдулся

нельзя ли поподробней? пропустил похороны поциента.

Тем не менее, о чем вообще спор был изначально?

В целом - про то, что бессмысленно притягивать за уши С/С++ "до уровня DSL" чтобы получить то, что уже есть в DSL, но с потерей времени. Т.е. оно ни работать быстрее не будет и писать быстрее не получится.

Одно дело, когда у вас нет под рукой подходящего инструмента - да, приходится приспосабливать то, что есть. Но если вам предлагается готовый и эффективный инструмент, то проще один раз его освоить и пользоваться. Если у вас есть циркулярка, не стоит пытаться электролобзиком получить длинный ровный рез просто потому что циркуляркой вы не пользовались, в лобзик для вас привычен. Если видите что вам предстоит ровно нарезать 100500 листов фанеры на прямоугольники - освойте циркулярку а привычный лобзик отложите для более подходящих для него задач.

Вот вам еще про скуль.

Есть таблица "дата актуализации клиента". Таблица "историческая" - когда у клиента меняется дата актуализации, туда просто добавляется запись с новой датой (бизнесу зачем-то это нужно).

По этой таблице есть индекс по ID клиента и DT - дате его актуализации.

Очень много ситуаций когда в задаче требуется получить текущую (последнюю) ДА по клиенту. Так вот, "скулевое" решение

select ID, max(DT)
  into :id, :dt
  from DATbl
 where ID = :id
 group by ID;

работает ощутимо медленнее, чем решение с прямым доступом

dcl-ds dsDATblRec likerec(DAIdx.DATblRecF: *all);

setgt (id) DAIdx;
readp DAIdx.DATblRecF dsDATblRec;

Это подтверждается PEX (Performance EXplorer) статистиками. Скуль пытается что-то там агрегировать в группе, в прямом доступе SetGT тупо по индексу ставит указатель после последней записи с заданным значением ключа, а потом ReadP читает предыдущую запись. Которая и есть в данном индексе запись с максимальным DT для заданного ID.

в прямом доступе SetGT тупо по индексу ставит указатель после последней записи с заданным значением ключа

Это вам повезло, что ставит указатель именно после последней записи. А если бы ставил перед первой? А если бы после последней, но задача была бы `select id, min(dt)` ?

Конечно, легко найти один частный случай...

А если в SQL варианте для max() что-то "агрегируется" с заметными тормозами, это просто недоработка оптимизатора конкретного движка. Вы будете давать зуб, что все движки тут недорабатывают, или кроме DB2 ничего не проверяли?

Это вам повезло, что ставит указатель именно после последней записи. А если бы ставил перед первой?

Если я правильно понимаю, что означает "SetGT", то "поставить перед первой" было бы "SetLT".

то "поставить перед первой" было бы "SetLT".

Может, да, может, нет... надо смотреть в детали. Тем более что там есть ещё над чем подумать:

  • Откуда взялась именно такая сортировка, кто-то создал курсор по составному индексу? Это не сказано.

  • Если этот id последний, SetGT станет на последнюю позицию или пустую за последней?

  • А для SetLT, если это первая, станет на первую или перед первой? Нужен readn (по аналогии с readp) или нет? Эти случаи кто-то отработал?

  • Зачем сначала становиться за последней позицией, а потом возвращаться назад?

Я писал когда-то под Clipper и FoxPro и помню эту беготню курсорами... да, оно просто на совсем простом. Но затем рост сложности, в отличие от SQL, практически экспоненциальный...

Это вам повезло, что ставит указатель именно после последней записи. А если бы ставил перед первой? А если бы после последней, но задача была бы `select id, min(dt)` ?

dcl-ds dsDATblRec likerec(DAIdx.DATblRecF: *all);

setll (id) DAIdx;
read DAIdx.DATblRecF dsDATblRec;

Вместо SetGT используем SetLL - он ставит указатель перед первой записью с указанным значением ключа.

Вместо ReadP (чтение предыдущей записи) используем Read - чтение следующей записи.

Если нужно проверить, есть ли в таблице запись с нужным значением ключа (но сама запись не интересует), пишем так

SetLL (KeyValue) MyIdx;
if %equal(MyIdx);
  // запись существет
else;
  // Такой записи нет
endif;

При этом не тратим время на чтение записи из таблицы, проверяем только наличие ее в индексе.

И там таких моментов очень много. Мелочь, но на скорость на больших объемах влияет ощутимо.

Я уже упоминал задачу про поиск соответствия в больших объемах строк.

Есть две таблицы - "витрина элементов адресов субъектов" - таблица где содержится Id адреса, Id элемента и его порядковый номер в строке. И таблица где содержатся сами элементы - Id элемента и сам элемент (слово).

Аналогичная витрина есть для адресов клиентов.

Нужно найти соответствия - когда все уникальные элементы адреса субъекта входят в адрес клиента.

Можно решить скулем. Один запрос, находящий пересечения в группах по витринам адресов субъектов и клиентов и отбирающий те, где количество пересечений в группе равно количеству уникальных элементов в адресе субъекта. Но работает достаточно долго (на промсреде это может занимать 7-10 часов для всех клиентов-субъектов).

Длиннее по коду, но эффективнее:

  • Составляем список уникальных элементов адреса субъекта

  • Берем первый элемент списка, находим его Id в таблице элементов адресов клиентов

  • По этому Id находим Id всех адресов клиентов, содержащих этот элемент и заносим их в массив

  • Дальше цикл - берем очередной элемент адреса субъекта, находим его Id в элементах адресов клиентов и потом проходим по нашему массиву, проверяя наличие связки Id адреса (из массива) и Id элемента в индексе (без чтения самой записи, нам важно только есть оно или нет). Если есть - адрес "проходит в следующий тур", если нет - удаляется из массива (отсеивается).

  • С каждым элементом длина массива сокращается и после последнего там остаются только те Id, которые соответствуют адресам клиентов куда вошли все элементы проверяемого адреса субъекта.

Это работает в несколько раз быстрее, чем скулевый запрос "в лоб".

Итого

  • Чтение элементов адреса субъекта (3-5-7 записей)

  • На первом "обороте" цикла заполнение массива - чтение всех записей, содержащих первый элемент (там много - может быть несколько сотен тысяч)

  • На всех оборотах цикла чтение одной записи по уникальному ключу - получение Id очередного элемента адреса субъекта в таблице элементов адресов клиентов.

  • Все остальное - без чтения записей, только проверка наличия значений в индексе.

Никаких группировок и агрегирования скулем (это достаточно "дорогие" операции). Однократное заполнение массива с последующим его просеиванием.

Если еще чуть оптимизировать и добавить "ключевое слово" - элемент адреса субъекта, имеющий минимальное количество вхождений в таблицу элементов адресов клиентов, и использовать его на первом обороте цикла (при заполнении начального массива), то сразу получаем массив минимальной длины и ускорение еще примерно в два раза.

Итого - на промсреде уже не 7-10, а 1-2 часа работает.

Вместо SetGT используем SetLL - он ставит указатель перед первой записью с указанным значением ключа.

Перед записью или на записи?

SetLL (KeyValue) MyIdx; if %equal(MyIdx);

И вылетаем на пустом ответе?

При этом недумаю тратим время на чтение записи из таблицы, проверяем только наличие ее в индексе.

Если select только полей из индекса в SQL, можно тоже не тратить время на чтение записи. Есть такая оптимизация. DB2 её не умеет?

Длиннее по коду, но эффективнее:

Реализуемо в большинстве "взрослых" движков SQL как хранимая процедура. И с перебором курсора, и с промежуточными представлениями результатов выборки.

Пока что весь этот рассказ выглядит как пример типа "DB2 туповата, обходим вручную"...

а если на С++ написать функцию которая это делает, то окажется можно сделать за одну строку:

make_what_we_need();

люди как будто не понимают, что этот дсл надо ещё реализовать

А если он уже реализован? И развивается постоянно?

А зачем пытаться забить шурупы молотком? Есть более подходящий инструмент - отвёртка.

Если работаете с базой - есть более эффективные и удобные инструменты.

А если например пишите свою базу - есть С++.

Для каждой части проекта - свой язык подходящий под задачу. Нет ни одной причины писать все на одном языке. Кроме пишу на чем знаю. Все равно, раз зашёл разговор про базу - уже 2 языка. Сделайте следующий логический шаг и пишите разные части проекта на подходящих языках. К тому же большинство языков схожи. Переход/изучение нового много времени не занимает. Кроме всякой экзотики (одна из весомых причин почему и экзотика кстати).

Язык я-ля DSL это хорошо, но с ним есть проблема. Кто на нем будет писать. Если он нишевый, но более-менее распространенный, типа того же RPG или ABAP/4, то в целом людей можно найти. Если же это совсем узкая штука конкретной конторы, то писать на нем прикладуху мало кому интересно, просто в силу того, что за пределами конторы это никому не нужно. То есть свой DSL лучше делать, чтобы могли на нем писать кто-то вроде аналитиков.

То есть свой DSL лучше делать, чтобы могли на нем писать кто-то вроде аналитиков.

Совсем не обязательно писать свой именно отдельный язык. Есть же пример Lisp/Scheme, где и языка как такового нет и ты сразу пишешь просто в AST.
Ну так AST можно описать чем угодно - хоть в YAML, JSON или и вовсе на С/C++ макросах, которые будут убирать лишнее под капот.

К примеру вот пример C/C++ кода. Ниже FOR(), SELECT(), FROM(), WHERE(), IS_NOT_LIKE() - это макросы.

int main() {
  FOR(record, 
    SELECT(INDEX_DESC(persons_name)) 
    FROM(persons)
    WHERE(IS_NOT_LIKE(persons.name, "Сидоров%") && (persons.age > 40))
  ) {
    printf("%s %d\n", record.name, record.age);
  }  
  return 0;
}

И подобный подход (макросами) можно расширить на что угодно.

Только не надо говорить что макросы это зло - вы просто не умеете их готовить (с)

P.S. А еще M4 существует :)

К примеру вот пример C/C++ кода. Ниже FOR(), SELECT(), FROM(), WHERE(), IS_NOT_LIKE() - это макросы.

Это eDSL. ;-)

НЛО прилетело и опубликовало эту надпись здесь

Не-не, любой язык общего назначения с макросами, это не для аналитиков. Для аналитиков должен быть довольно специфический язык. Я такой делал, для ERP, прикладуху на нем писали девушки-аналитики, быстро и успешно. Но это не для всех подойдет.

Ну наконец-то :-)

Да, речь именно об RPG. У нас в стране как минимум три банка (Альфа, Райф и Росбанк) его используют. Плюс как минимум три (которых я знаю) компании - BTC, Cinimex и РМС-Лаб предлагают услуги по разработке на нем. На SO есть теги #rpg (старые диалекты) и #rpgle (современный диалект). В LinkedIn есть группы. Есть форум на Code400, есть блоги - Nick Litten, Scott Klement, Simon Hutchinson (RPGPGM). Есть IT Jungle, MySampleCode, WisdomJobs... Т.е. вполне устойчивое сообщество где можно и поделиться чем-то и спросить.

Так а чем вас так STL не устраивает? Да и "стандарт"?

Вот было круто то, когда был borland C++, embarcadero C++, и очередной закрытый компилятор от странной конторы которая не понятно вообще будет ли жива через 2 года.

Ну и на самом деле никто не мешает вам не линковаться с -lstdc++ и жить себе прекрасно на рукописных примитивах с -fno-exceptions в счастливом мире си с классами.

Ну и гугл уже делал свой карбон, только что там с ним и как не слышал давно. Была какая-то куллстори, что для новых проектов советуют раст

да хоть на JSON

Это как?

Ну например вот функция сложения двух чисел

{"type": "function", "name": "adder", "args": [["x", "int"], ["y", "int]], "result_type": "int",
 "body": [
   {"st": "return", "expr": ["+", "x", "y"]
   }
]}

Такой себе AST в виде списков и деревьев, только на JSON.

В реальном, конечно, будет много отличий (например вместо "x" в выражении, скорее всего, будет что-то вроде {"local":"x"}), но внешне будет достаточно похоже.

Языки, заточенные под определенные задачи, это DSL. И да, соглашусь, что так и надо делать если, конечно нет каких-то уж очень специфических требований

Если вы про RPG, то это не язык, заточенный под задачи "работы с БД и коммерческие расчеты", а платформа мейнфреймов ΙΒΜ заточенна под глубокую интеграцию с этим прориетарным языком(вроде возможности прямого чтения данных из бд). Шаг в сторону от ΙΒΜ мейнфреймов и этот язык теряет всякий смысл в отличии языков общего назначения типа С/С++/Java и т.д.

И да и нет.

IBM i - это не мейнфреймы. Мейнфреймы - IBM z. i - это middleware. Изначально позиционировались как сервера для малого и среднего бизнеса. Но получилось настолько мощно и масштабируемо, что успешно используется и в крупном

Да, RPG интегрирован в систему. Но тут все интегрировано. БД (DB2) тоже часть системы. Компиляторы (CL, COBOL, C, C++, RPG) - часть системы. Все это получаешь сразу из коробки как единое целое.

При этом есть реализации и для других платформ. Тот же ASNA VisualRPG (в т.ч. и для .NET)

В С/С++ тоже есть поддержка decimal (правда, только ее, нет ни varchar, ни numeric, ни date, ни time, ни timestamp). И есть библиотека для прямой работы с БД - RECIO. Правда, в чисто "Сишном" стиле - куча опций, параметров, 90% которых в обычной работе нафиг не нужны.

Так что в принципе, тут тоже можно все на привычном С++ писать (и я даже знаю таких людей, правда, лучшей производительности кода при всех оптимизациях у них достичь не выходит, а времени на разработку уходит больше).

Речь исключительно о том, что если вам надо раскроить большие листы фанеры на ровные прямоугольники и если у вас есть под рукой циркулярка - воспользуйтесь ей. Не надо делать это лобзиком только потому что "лобзик универсален и им можно сделать все и вы умеете им пользоваться". Циркуляркой получится ровнее при меньших затратах времени и усилий. Первые пару резов непривычно, зато потом все пойдет быстро и ровно.

Лично я до банка совсем другими задачами занимался. И 25+ лет писал на С/С++. И сейчас иногда пишу когда это оправданно задачей. Но вот столкнувши с RPG быстро понял что раз он тут есть, то использовать его для решения банковских задач эффективнее как с точки зрения разработки, так и с точки зрения конечного результата.

Иными словами, основной посыл тут - использовать для решения конкретной задачи, здесь и сейчас, наиболее подходящий из доступных инструментов.

Но вот столкнувши с RPG быстро понял что раз он тут есть, то использовать его для решения банковских задач эффективнее как с точки зрения разработки, так и с точки зрения конечного результата.

Замечательно. Осталось понять при чем здесь C++.

Ведь из ваших слов логичным образом вытекает, что в ваших условиях и на ваших задачах RPG будут сливать и Java (со Scala-ми и Kotlin-ами), и C# с F# впридачу, и другие высокоуровневые универсальные языки (ну, может быть, за исключением COBOL-а).

Но "на помоечку" (с) отправить нужно именно C++.

Я изначально так и ставил вопрос. О том, что любой универсальный язык тут будет проигрывать.

С/С++ тут только при том, что здесь он тоже есть и есть возможность сравнить решение одной и той же задачи на них или на RPG. По затратам времени на разработку и по эффективности полученного результата (объективно, через снятие PEX статистик на одних и тех же данных).

С COBOL вопрос открытый. С одной стороны, он также специализирован для этого же класса задач, с другой - он не развивается давно (а IBM его никогда и не развивала, им MicroFocus занимался). И в нет много того, что сейчас появилось и появляется в RPG. Чисто на уровне "синтаксического сахара".

Хотя, если стоит задача портирования, то COBOL будет лучшим решением т.к. его можно перенести на другие платформы (тот же GNU COBOL).

О том, что любой универсальный язык тут будет проигрывать.

Тогда зачем продолжать полоскать C++?

Ну хорошо, не будем, раз это так оскорбляет чьи-то чувства.

Речь не о чувствах, а о том, чтобы картина была объективна.

Ваше восхваление RPG можно было бы понять, если бы вы пришли на платформу IBM i и начали решать свои специфические задачи на C++, долго от этого страдали, пока кто-то не раскрыл вам глаза на существование RPG. После чего мир заиграл новыми красками, а жизнь вновь стала прекрасна и удивительна.

Но, как я понимаю, было не совсем так. На этой платформе уже был инструмент, который заруливал и C++, и Java, и C#. Было бы странно отказываться от него. Но раз инструмент заточен и под платформу, и под задачу, то какой смысл все время противопоставлять его C++?

Вот кто-то бы начал сравнивать C++ с регулярными выражениями, уместно бы было такое сравнение?

Да, на C++ вы могли бы закатывать Солнце вручную выписывая что-то вроде:

auto exp = capture(repetition(2, 8, range('0', '9')));

вместо ([0-9]{2,8})

Но если бы кто-то начал бы снова и снова приводить примеры того, как лаконично и просто выглядит регулярка, и как все сложно с ее повторением в C++, то нормальным бы это вряд ли выглядело.

Ваше восхваление RPG можно было бы понять, если бы вы пришли на платформу IBM i и начали решать свои специфические задачи на C++, долго от этого страдали, пока кто-то не раскрыл вам глаза на существование RPG. После чего мир заиграл новыми красками, а жизнь вновь стала прекрасна и удивительна.

Так скажем, никто не запрещает тут решать задачи на С++. Главное условие - задача должна выполнять поставленную бизнес-функцию и должна получить согласование на внедрение на нагрузочном тестировании.

И да. Когда я пришел сюда 6+ лет назад, я имел неплохой опыт в С/С++ (25+ лет, значительная часть которых была связана с промавтоматизацией и той или иной степенью реалтайма - т.е. писать быстрый и эффективный код я умел и шишек на том понабил изрядно).

И да. Мне привычнее было бы делать все на С/С++. И я пробовал это делать на С/С++. Но быстро пришел к тому, что это не самый эффективный путь в данных конкретных условиях. И тут даже ООП не очень хорошо ложится т.к. работа всегда крутится не вокруг взаимодействия объектов, но вокруг потока данных, который в каждой задаче кардинально разный. Составить иерархию абстракций конечного размера не представляется возможным (хотя попытки были).

В результате пришел к неизбежному - вся бизнес-логика на RPG, С/С++ - для низкоуровневых вещей.

И да, я знаю людей, которые по прежнему пишут на С++ то, что мы делаем на RPG. И Честно скажу - результат не впечатляет. Ни по затраченным усилиям, ни по производительности конечного продукта.

Если успокоит - могу сказать, что окажись в другом месте, где эффективно использование других языков (Golang, Rust. Haskel...) я бы делал точно такой же выбор по тем же критериям - сочетание трудозатрат на разработку с эффективностью и производительностью конечного результата. И если С/С++ даст лучшее сочетание - выбрал бы их. У меня нет предубеждений по поводу конкретного инструмента. В принципе нет.

На заре деятельности я точно также выбирал между Паскалем и С. Потом был момент выбора между Clipper и Clarion. В какой-то момент даже использовал dbVista (ныне RDM - Raima Data Manager) т.к. ее сетевая модель БД более подходила под конкретную задачу, нежели реляционная.

И да. Мне привычнее было бы делать все на С/С++. И я пробовал это делать на С/С++.

Ну понятно. Именно C++ плох потому, что вы пришли из C++. Пришли бы из Java, то плохой по сравнению с RPG была бы Java. Но т.к. в вашем багаже Java (или C#) не было, то плох именно C++.

Где я говорил что С++ плох? Вот прям чтобы вот так вот. Я говорил только то, что для задач, связанных с реализацией бизнес-логики на этой платформе есть более удобные инструменты.

Везде писал что RPG позволяет данные конкретные задачи решать проще и эффективнее. При этом, на нем можно сделать все, что можно сделать на С, но если нужно что-то системное, то это будет достаточно неудобно. Можно, но на С или С++ это будет проще и изящнее.

Скажем, я могу на RPG написать движок для распараллеливания обработки больших объемов данных или тот же USRQ API, но это займет больше времени и будет "неуклюже" по сравнению с С/С++.

С C# сравнивать не могу т.к. не сталкивался с ним во-первых, на этой платформе его нет (и нет возможности одну и ту же задачу решить разными инструментами и сравнить результат) во-вторых.

Я говорил только то, что для задач, связанных с реализацией бизнес-логики на этой платформе есть более удобные инструменты.

Да я вам уже устал повторять: на вашей платформе RPG для ваших задач рвет чуть ли не всех. Но вы упорно говорите про то, что именно C++ не лучший выбор. Хотя вместо C++ можно подставить любой современный мейнстримный язык.

Не подставляете же вы именно потому, что в бэкграунде у вас C++. Была бы Java, вы бы точно так же говорили про Java.

Если и сейчас до вас не дойдет...

RPG "рвет всех" только в конкретном классе задач. Это узкозаточенный инструмент.

С++ - более универсальный инструмент широкого профиля. И в тех задачах, которые не связаны с бизнес-логикой на этой же платформе (а такие тут тоже есть) он кратно лучше RPG.

Я не против какого-либо инструмента. Я против зацикливания на чем-то одном. И за выбор наиболее удобного под конкретную задачу.

И, честно говоря, не совсем понимаю вашу позицию - вы что пытаетесь доказать? И кому?

И, честно говоря, не совсем понимаю вашу позицию - вы что пытаетесь доказать?

Я пытаюсь доказать, что когда вы сравниваете RPG с C++ в своих задачах, то вы напрасно акцентируетесь на C++. Т.к. на место C++ в этом сравнении можно подставить хоть Java, хоть C#, хоть Kotlin, хоть Scala. Ничего не поменяется.

И кому?

Вам.

Я сравниваю сравнимое. То, что можно взять и запустить параллельно в двух терминальных сессиях и посмотреть разницу (по времени выполнения, PEX статистикам). Сравнить время на реализацию одной и той же задачи.

И неоднократно говорил, что ряд задач я делаю на С/С++ потому что это быстрее и удобнее. Но это системные задачи. Обычно требующие плотной работы с системными объектами (системные указатели, MI), работы в TERASPACE модели памяти с 64бит указателями и т.п. Для всего этого на этой платформе нет альтернативы С/С++.

Я сравниваю сравнимое.

Да я тоже могу на C++ сделать DSL для описания регулярного выражения, а потом сравнить его результат с выхлопом, скажем, re2c. Или сделать на C++ вручную bottom up LR(1) парсер и сравню его с bison-ом.

Не, ну а чё? Сравнимое же.

А потом еще и буду говорить, но вот когда нужно делать обработку 2D изображений, тогда, конечно же, С++ круче, чем re2c и bison вместе взятых.

Получится как у вас с вашим любимым IBM i.

Я могу понять, когда люди сравнивают C++ и, скажем, Java для реализации проектов типа NetBeans или Eclipse. Когда компонентная архитектура, плагины от разных разработчиков. И хочется, чтобы все это работало и быстро, и надежно.

Ну так о чем и речь. Выбор наиболее эффективного инструмента под задачу.

Просто сейчас, так сложилось, у меня 80% задач требуют вполне определенного инструмента. Но это не значит что я буду натягивать сову на глобус и использовать тот же инструмент под оставшиеся 20%.

Ну так о чем и речь.

Тогда повторю свой вопрос: а при чем здесь C++?

Зачем вы именно C++ противопоставляете "наиболее эффективному инструменту под задачу"?

В переводе на русский, я так понимаю, "зачем именно под статьёй про C++, где обсуждается только C++ и всё, что с ним связано, влезать со своим инструментом", верно? Просто, ну, это можно было бы и прямо сказать, со стороны совсем не очевидно, что эта статья только про C++.

Как бы да, и я стараюсь об этом прямо сказать.

Но, позволю себе немного растечься мыслею. Сама статья весьма специфична и в ней речь идет о (кмк) сравнительно узкой сфере задач, решаемых на C++. Тем не менее, она актуальна в том плане, что автор статьи рассказывает о вещах, которые появились a) недавно (так мне показалось) и b) как способ преодолеть ограничения, достигнутые при применении универсальных языков (C++ в частности). Т.е. сперва задачи из предметной области автора статьи решались на C++ (и конкурентов практически не было), но времена меняются и сейчас вне C++ можно достичь результатов лучше, чем на C++.

Здесь все OK. С поправкой на то, что не нужно специфику узкой области автора статьи экстраполировать на вообще весь C++ и сферы его применения (что, кмк, происходит в комментариях, автор статьи такой попытки и не делал).

Но вот появляется персонаж, который в очередной раз (ну вот реально он не впервые прибегает с RPG в комментарии к статьям про C++) говорит: "А вот RPG в моих задачах рвет C++ как тузик грелку". И это не имеет отношения к поднятой в статье теме просто потому, что RPG специально затачивался под такие задачи, и рвет он не только C++, но и вообще все за исключением COBOL-а (с той же самой платформы).

Мало того, что данный персонаж со своим RPG уже поднадоел, так еще и непонятно какие выводы из его историй стоит сделать (и это принципиально отличает обсуждаемую статью). Ближайшая аналогия: если вам нужны регулярки, то используйте готовые regex-а, а не костыльте их самостоятельно. Ну как бы да, спасибо, Кэп.

Если внимательно почитать статью, то

 Я по-прежнему писал в основном на C++, но то и дело ко мне обращались с вопросом: «А хочешь вот эту задачу, она не на C++?» И я отвечал: «Давай!» А затем брался за задачу, какова бы она ни была.

Теперь ситуация изменилась, и требуется меньше фич, а в то же время – более высокая производительность при работе с теми фичами, которые у вас уже есть.

Дальше идет перечисление инструментов, которые к каких-то узких областях лучше С++

И вывод:

Если мне придётся променять  C++ на «не C++», то 80% моей работы никак не изменится. Язык C++ уже просто нерелевантен для большинства моих задач. Могу ли я в таком случае утверждать, что для меня C++ уже на 80% мёртв?

Вот об этом мои комментарии. И самый первый вроде как особых возражений не вызвал. Потому что на 100% соответствует последнему абзацу статьи.

Да, но речь в посте же идет про задачи общего назначения, не привязанные к вендору и экосистеме(как RPG и IBM). К примеру, амазон может сделать специальную интеграцию Visual Basic для своего api, что позволит писать на нем под AWS быстрее и проще чем на любом другом языке, но это не сделает Visual Basic в общем случае удобнее и производительней чем С++

С - первая любовь (начинал еще когда плюсов не было). С++ - первые реализации ("С с классми") - зашли, а вот все что началось дальше - уже нет.

Вы читаете мои мысли!)

C++ умирает именно потому, что современное программирование - оно вообще не про написание кода, а про его чтение и компоновку из готовых кусков.

Самый лучший язык XXI века - тот, который позволит вам сделать git clone, тут же собрать склонированное и наскоро адаптировать к своей задаче парочкой воткнутых костылей.

Соответственно, рулит не синтаксический сахар, синтаксис сейчас не значит вообще ничего.

Непременные признаки хорошего современного языка общего назначения:

  • Удобный тулчейн, чтобы сборка проекта, стянутого по git clone, осуществлялась одной командой и не падала хотя бы в 95% случаев, а при падении выдавала внятное сообщение об ошибке.

  • Хорошая работа с зависимостями, чтобы все нужные версии всех нужных библиотек и инструментов подтягивались автоматически и это просто работало.

  • Богатая стандартная библиотека.

У C++ нет ни первого, ни второго, ни третьего. Какое будущее может быть у языка, в котором написать программу заново может быть проще, чем заставить скачанное с github'а просто собраться на вашей машине? Современный программист не будет читать пять страниц инструкции по сборке, которая подразумевает ручную установку зависимостей и ручную же синхронизацию пачки скриптов, использующих make, bash, perl, python и node.js одновременно.

Что за язык, у которого в стандартной библиотеке до сих пор нет нормальных средств работы с сетью? И это когда WiFi уже даже в микроконтроллеры встроен, а весь софт давно ушёл в облака.

C++ умирает именно потому, что современное программирование - оно вообще не про написание кода, а про его чтение и компоновку из готовых кусков.

Да С++ уже 30+ лет как умирает и умереть не может. В сферах где нужен перформанс (и часто компоновка из кусков не работает, потому что кусков то и нет, так как проприетарное железо/операционки), а С слишком голый, альтернатив по прежнему не особо.

На плюсах писал лет 8. Пришёл к ощущению, что что-то совсем низкоуровневое лучше на "голых" сях слабать, а если что посложнее, особенно с зависимостями - тулинг незаменим, так что какой-нибудь Rust или Python, да хоть Ruby.

Кажется, что на C++ пишут приложения, которые с одной стороны будут живы и через 15-20-30 лет, с другой - поддерживать их будут плюс-минус те же команды. В современном климате таких не настолько много: или делаем на века и для всех (как ядро Linux), или цикл разработки занимает несколько лет: зашли на рынок, привлекли денег, выросли, выкинули старый код и переписали заново.

Кажется, что на C++ пишут приложения, которые с одной стороны будут живы и через 15-20-30 лет, с другой - поддерживать их будут плюс-минус те же команды.

Весь серьезный геймдев, всякие про приложения типа фотошопа, 3д макса и т.д.

что-то совсем низкоуровневое лучше на "голых" сях слабать

Я вроде и согласен, но бывает что людям хочется чтобы С, но были классы, или темплейты, или что еще. Проще в таком случае взять С++ и кастрировать (а давайте напишем на плюсах, но без RTTI/исключений/смартпоинтеров/у_кого_на_что_фантазии_хватит), что собственно часто и происходит.

Весь серьезный геймдев

Геймдев пишет на том, начем написан лучший движок по сочетаюнию цена/качество. Когда был бум мобильных игр, геймдев писал на Unity/C#.

 всякие про приложения типа фотошопа, 3д макса и т.д.

Blender на чем написан?

Blender на чем написан?

80% на C++. Тулзы и аддоны на Python. Его рендер (cycles) на C и С++.

Если я ничего не путаю, в Maya расширения тоже пишутся на Python, когда она сама написана C++.

И Godot на C++ со своей скрипт машиной. Теперь все будут писать на gdscript, спускаясь в плюсы по желанию

Геймдев пишет на том, начем написан лучший движок по сочетаюнию цена/качество.

По этому и написан серьезный (хотя наверное стоило написать ААА). Куча студий пишут кастомные движки либо используют анриал и очень сильно его кастомайзят, что опять таки С++. Сам юнити так же написан на С++.

Сам юнити так же написан на С++.

Нет, Unity написана C#, в отличии от 99% движков, которые, да, написаны на C++.

Нет, "Unity itself is written in C++".

Там же: "The code that has to run super-fast like the physics and animation, all that  is C++" (David Helgason, the CEO and co-founder of Unity Technologies).

C# это скриптовый язык юнити и, если правильно помню, редактор написан на шарпе, сам кор движка/рендер написан на плюсах

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

Проще в таком случае взять С++ и кастрировать

То так, мне кажется, что многие конторы так и работают с C++. Но управлять процессом сложно; в плюсах за годы появилось много всего хорошего, конечно, но нет какого-то... Ясного видения, что ли. Стандарты выглядят как свалка. "Фичи? Их есть у нас!". То же самое начинает проникать и в код - или у тимлида светлая голова и готовность следить за внутренними стандартами, или "мы пишем без темплейтов кроме вон тех трёх мест, где лучше не придумали". Иногда лучше меньше, да лучше.

Мой аргумент, пожалуй, в том, что "пишем на кастрированном C++" - в некой мере следствие занятой плюсами доли рынка. То бишь уже есть люди, умеющие писать на C++, и дешевле занять их, чем переучивать или находить кого-то, умеющего в идеально подходящий с точки зрения технологии стек. От такого язык не умрёт быстро, но на спад, пожалуй, идёт. Так-то и фортран с коболом "живы".

НЛО прилетело и опубликовало эту надпись здесь

это какой то уже бред в активной стадии, под перфоманс написать свой язык и компилятор

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Ну и да, отдельно напишу, что там, где перформанс на самом деле нужен и является конкурентным преимуществом, так и делают.

Да, вы абсолютно правы. Но согласитесь, очень уж печальные у вас примеры: по-сути это просто высокообразованные высокотехнологичные спекулянты, живущие в городах-помойках.

НЛО прилетело и опубликовало эту надпись здесь

Ну это вопрос философский, особенно считать ли спекулянтов чем-то плохим.

Всё упирается в философский вопрос - "нужны ли мы нам?" :-) Если вас интересует существование человечества, развитие индустриальной цивилизации, то спекулянты безусловно плохи.

Это особенно печально, но удалёнка нас спасёт.

Очень приятно осознавать, но удалёнки у спекулянтов нет. :-) Так что если хочется на них работать, придётся жить в помойке. Карма.

Да и можно заработать спекуляциями многоденег, переехать в город подешевле и поприятнее

Для этого надо быть спекулянтом, а не работать на них.

НЛО прилетело и опубликовало эту надпись здесь

Чувак, пишущий инфру для трейдеров (или те вот всякие DSL) — он уже спекулянт или ещё нет?

Главное, что он бессмысленно прожигает свою жизнь. Но нет, разумеется, он является обслугой спекулянтов.

и там в офисе надо быть что-то вроде около одного дня в неделю

Это и есть нет удалёнки.

Главное, что он бессмысленно прожигает свою жизнь.

Ну может быть исключение - если он разработает, например, новый lock-free wait-free gluten-free алгоритм или структуру данных :) чтобы сэкономить 5нс заказчику, и опубликует это. А иначе прогресс в таких областях не очень-то и движется.

На ICFP последней реально было крайне печально смотреть на применения «высокого программирования»: либо пузырь AI, либо спекуляции, либо геймдев (кмк, мэтры очень стеснялись участия в этом геймдеве, но может быть и зря — затея хотя бы отчасти благородная: дать передний край детям). Одна радость — у Tarides был стенд про космос (они запустили Mirage на одном из индийских спутников в качестве нагрузки).

НЛО прилетело и опубликовало эту надпись здесь

Я в январе беседовал с чуваками, запилившими свой компилятор с какого-то расширения Питона. Именно для обслуживания квантов-трейдеров. Это не так сложно, как вам кажется, там же миллиарды разворовывают.

Бред, но ещё это может быть HFT.

Как это согласуется с

В мире настолько много опытных программистов, как никогда ранее в истории.

Не особо-то они, значит, и опытные, а так, натасканные на несколько шаблонов.

Я правильно понял что языком общего назначения вы назвали Golang? :)

Не смотря на то, что эта критика абсолютно валидна - мы это решили при помощи vcpkg, где Cmake сначала скачивает все зависимости (залоченные), а потом собирает.

Это работает лучше, чем стандартный питончик, где при обновлении версии надо обновлять половину либ.

" У C++ нет ни первого, ни второго, ни третьего " - ололо. поколение nuevo гордится тем что не слышало про make ?

Make это отрыжка из 70ых.

Как мне собрать это под вин, без выслушивания нытья, что вин недоось и мне на самом деле не надо это собирать ?

я бы воспользовался кросс компилированием)

Горжусь тем, что не знаю make, не называю переменные транслитом и не закидываюсь хмурым.

до сих пор нет нормальных средств работы с сетью

Работу с файлами дождались - и сети дождёмся. И зачем-то 2D графику...

" рулит не синтаксический сахар, синтаксис сейчас не значит вообще ничего " тот в C# каждый год новый сахар завозят - от ненужности )) там есть сомнительные вещи, но они больше для "когда очень нужно"

думаю у c++ сообщество все это есть.

Вопрос только в том, почему люди этим не пользуются?

  1. Есть тот же conan, vcpkg. Но хорошие либы и без них собираются одной командой - make или cmake.

  2. conan, vcpkg

  3. boost

Вообщем-то

если бы эти 3 ключевых фактора правда были бы основополагающими, то все бы уже писали на новых языках. Но плюсы дают ещё что-то, чем не могут похвастаться новые языки. И я не думаю что это всего лишь страх переписывания миллионов строк кода)

хотелось бы согласиться с вашим первым утверждением, потому что так и должно быть. Но обилие велосипедов перед глазами не позволяет мне это сделать)

выжимать мощность арендованного вами оборудования вплоть до последнего флопса.

Очень и очень редко нужно. Выжать 95% возможностей, потратив на разработку в 4 раза меньше усилий - это почти всегда более интересное для бизнеса предложение.

Фишка большинства этих языков — просто в стреноживании программиста, якобы, для его же блага.

В авиации бы так думали. Зачем нужна система предупреждения о столкновении с землёй? Хороший пилот и так всегда смотрит, куда летит. Только мешает время экономить.

В авиации бы так думали. Зачем нужна система предупреждения о столкновении с землёй? Хороший пилот и так всегда смотрит, куда летит. Только мешает время экономить.

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

Ну, тут, конечно не вопрос жизни и смерти, но если в результате падения вашей программы (или просто она начала дико лагать) в "горячий" предновогодний период миллионы клиентов по всей стране не могут расплатиться картой вашего банка в течении нескольких часов ("нет ответа от банка") - к вам точно будут вопросы... Причем, вопросы будут сначала у регулятора к банку, а потом уже начнутся внутренние разборки - комиссия по инцидентам и все такое.

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

В этом принципиальна разница.

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

Как же "быть не может", если новые модели самолётов выпускают в эксплуатацию только после экспериментальных полётов с лётчиками-испытателями и последующим анализом всей телеметрии.

я к тому что падение на землю самолета там вроде как не допустимый результат проверки, хотя... машинам то вот точно устраивают краш-тесты.

Давайте остановимся на общем выводе что краш-тесты тоже имеют право на жизнь :) .

Крэш-тесты устраивают и самолётам. Разумеется, какому-нибудь 737MAX - вряд ли, хотя, при минимуме набивки только на голой обшивке - возможно, и делали (ну, с макетами набивки). А средствам подешевле и помассовее - тем более.

Отработка сценариев отказа на макете тоже регулярно производится - типа "что скажет центральный процессор на сигнал отрыва двери".

Давайте остановимся на общем выводе что краш-тесты тоже имеют право на жизнь :)

Безусловно :)

падение на землю самолета там вроде как не допустимый результат проверки

От отсутствия системы предупреждения самолёт сам по себе не упадёт. Это именно предупреждение для уставшего/отвлёкшегося пилота, что "кажется что-то пошло не так", и надо срочно что-то делать.

Ну и да, что-то типа крэштестов в авиации делают. Это, правда, не весёлый "бдыщ", а скучные и долгие статические испытания, чтобы проверить, что при всех допустимых нагрузках у самолёта крылья не отвалится.

Очень и очень редко нужно. Выжать 95% возможностей, потратив на разработку в 4 раза меньше усилий - это почти всегда более интересное для бизнеса предложение.

Бизнес часто попадает в ловушку, когда первые 10% решения действительно пишутся в 4 раза быстрее, а вот последние 10% из-за динамического типизирования встают в такую копеечку! См. тесты, объём которых больше программы. :-)

Так что "я сын С++ника, тут не всё так однозначно". :-)

" См. тесты, объём которых больше программы " а как размер тестов зависит от типизации?

Например, можно выразить часть гарантий в типах

Антипропорционально зависит.

И то, и другое — это средство проверки гарантий, если брать аналогии с интегрированием, то тесты — это Монте-Карло, а статическая типизация — автоматизированные аналитические вычисления (Mathcad/Mapple/Mathematica/Maxima).

Выбор того, чем описывать гарантии — инженерная задача, как правило, компромисс. Соответственно, оптимум обычно лежит посередине, а Питон находится у края.

Бизнес про это в курсе, поэтому действительно популярных языков с ДП сейчас осталось примерно три, причём во все типизацию тем или иным способом завезли.

причём во все типизацию тем или иным способом завезли.

«Органично совмещая недостатки обоих подходов» ;-)

Зачем вообще программировать на C++, если достаточно дать высокоуровневое описание алгоритма — и инструмент сделает вам код, в два раза обгоняющий код на C++?

тут есть один простой вопрос: на чем написан инструмент, который сделает вам код, в два раза обгоняющий код на C++, хотя бы частично?

Я боюсь что тут вариантов никогда не будет: С++, С, Ассемблер.

Они бессмертны, пока есть процессоры система команд которых это и есть ассемблер.

C++ и C - не совершенство и просто позволяют описать логику, которую потом переведут в машинный код. Таких языков много.

Язык это не только логика, но и возможности среды исполнения.

Если говорить про возможности чистого C:

Чистый C позволяет писать программы без динамической памяти. И в ряде случаев это хорошо. Однако чистому C требуемся стэк (и, возможно, немного локальной памяти). Без стэка C не может. С другой стороны: много ли языков могут работать в таких условиях?

И если пойти чуть дальше:

Ассемблер (который про процессоры, не про браузеры) позволяет писать программы без стэка (правда, иногда подставляя кэш процессора как квази-память для создания ощущения стэка). И в ряде случаев это тоже нужно. А вот тут совсем мало подобных языков.

К чему это? А, да: сомнительно, что таких подобных языков (заменителей C, Asm) много. Вот честно: очень сомнительно. Приведёте парочку примеров?

FPC, например

Ну так Turbo Pascal, на систаксисе которого обосновался Free Pascal он весьма древний, как-бы не древнее ANSI C++....

С другой стороны: много ли языков могут работать в таких условиях?

Про Паскаль уже сказали. Естественно, его продолжения в виде Modula и Ada. Fortran.

Всем названным нужно отрубить стандартную библиотеку, ну так и для C это тоже надо (freestanding сборка с нужными свойствами).

Среди этого комплекта мы в основном помним C только потому, что в нём соответствующие действия выражаются максимально прямо.

правда, иногда подставляя кэш процессора как квази-память для создания ощущения стэка

Это ортогонально использованию стека. Если говорить про старт x86 в до-ME реализациях, то там псевдо-RAM на стеке использовалась и для данных (типа результатов итерирования устройств на шинах), а до получения такой псевдопамяти стек эмулировался адресами возврата прямо в коде.

А, да: сомнительно, что таких подобных языков (заменителей C, Asm) много.

Заменителем ассемблера может быть только другой ассемблер для той же ISA, потому что что бы ни делали, всё равно требуется указывать конкретные машинные команды. Поэтому постановка вопроса о замене ассемблера в целом бессмысленна. Хотя, если признать прямую запись в числах и "автокод" чем-то иным, чем ассемблер, то их вполне можно назвать.

Вакансии на Ассемблер никогда не исчезнут, все пять.

Это вы рассматриваете только легальные (белые) вакансии. Тогда как для ассемблерщиков самые доходные вакансии связаны не с написанием кода, а с реверсинженирингом всего подряд - от потрошения прошивок микроконтроллеров до слома коммерческого софта.

Да, эта деятельность в значительной мере нелегальная, но пока существует компьютерное пиратство, ассемблерщиков всегда будет нехватка, и зарабатывать они могут вполне прилично.

Сколько ни видел вакансий на реверс-инженера, в них ещё требуется уметь "писать понятную реализацию изученного на высокоуровневом языке".

Или вы про читоделов?

Читал, что не хватает с обратной стороны - античитеров в команде разработчиков онлайновых игр, которые реверсили бы читы.

Я не совсем из этой песочницы, но что бы что-то разреверсить, надо иметь представление, как оно было написано. Т.е. наличие в голове типичных паттернов компилятора (и, желательно, автора) исходной софтины очень помогает.

Похоже, вы не хотите особо распространяться на эту тему, хотя и вбросили. А было бы интересно узнать как зарабатывают крякеры программ и игр. Думал, они это делают только по приколу, соревнуясь друг с другом. Разве что EMPRESS собирал(а) донаты, пока за жопу не взяли.

А потрошение микроконтроллеров для чего? Чтобы подправить, залить на свои устройства и продавать?

за 25 лет я что-то не видел ни одной вакансии на Ассемблер. Хотя как раз 25 лет назад меня взяли на работу в очень известную фирму именно потому что я был единственный кто знал Ассемблер, как потом выяснилось, но даже в описании той вакансии Ассемблер не упоминался.

А как же программирование микроконтроллеров?

esp8266 гоняет с 80кб общей оперативки и 4мя мегабайтами места под программу (она вообще flash, можно барахло свое хранить). Ассемблер там не то чтобы нужен.

В целом за пределами понимать и периодически читать ненужон. Ну кроме кейсов экстремальной экономии где тянут пик16 и пытаются в него запихать всякого и прочих особо извращенных кейсов. А за пределами этих кейсов, в консумер электронике уже целый линукс с нод-жс на нем встречается.

Компиляторы теперь частенько состоят из двух частей. Первая переводит из языка в универсальный код, а вторая компилирует универсальный код под конкретную архитектуру. Это позволяет отделить оптимизацию под архитектуру от языка в разные проекты. Первая часть у любого приличного языка написана на нём самом. Даже у Python есть такой вариант. Вторая часть - это обычно LLVM, написанный на С. Но есть и Cranelift написанный на Rust.

Так что как минимум Rust можно целиком компилировать на нём самом. Другое дело, что так никто не делает, потому что никто кроме вас и ещё пары человек, не видит в этом ценности. Когда Rust начнёт вытеснять C, просто LLVM перепишут на Rust и дальше двинутся. Да уверен, кто-нибудь уже начал.

никто кроме вас и ещё пары человек, не видит в этом ценности

Ну вообще конкретно в этом случае ценность есть. Cranelift оптимизируется под скорость компиляции, и позволит делать debug-сборки быстрее, и быстрее получать обратную связь

</зануда>

Не, вы не въехали :) Речь о том, чтобы компилятор/среда языка был целиком написан на нём самом, без вставок на С. Я не думаю, что отсутствие такого софта говорит, что язык плох, или жить не может без С. Припрёт - перепишут, а сейчас зачем, если есть и С и кодыри на нём?

Про это как раз в статье написано:

Большинство из них, взять, к примеру, Rust, Julia и Clang, даже работают с одним и тем же бекэндом. Невозможно определить победителя в автогонке, если все претенденты сидят в одной машине.

Появляются новые оптимизации в LLVM - и сразу появляются во всех языках, которые используют его.

Не согласен. Оптимизации и решения до уровня LLVM гораздо более важны для производительности. Из банального: один язык при любом обращении к массиву проводит проверку выхода за пределы n < arr.length, второй тупо берёт *arr[0] + n*sizeof(arr[0]), а Rust вообще имеет интеллектуальную выбиралку, проверять или нет. LLVM такие штуки не решает, столь сложные вещи ему даны в ощущениях.

Проведите эксперимент - возьмите C++ код, скомпилируйте в LLVM IR опциями типа `-S -emit-llvm`, напустите ll-opt на результат и затем в бинарь. С разными уровнями оптимизации у clang и у ll-opt. Увидите, что если clang получил -O0, то результат исправить потом практически нереально, будет куча лишних операций.

НЛО прилетело и опубликовало эту надпись здесь

Тоже используем Haskell для этого, только генерим С99 =)

тут вариантов никогда не будет: С++, С, Ассемблер.

А как же Forth?

А как же Forth?

Среда Forth со старта уже требует RAM и двух стеков в нём (данных и возвратов) и стандартной библиотеки.

А как же Forth?

не знаю такого, забыл наверно. У него есть бесплатная среда разработки, компилятор?

Начните с GNU Forth. Да, есть. (Но условиям он не соответствует)

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

Компиляторы большинства компилируемых языков написаны на них самих.

Да инструмент можно сделать на любом языке, собственно. На той же Java или на Python — на чём-то кроссплатформенном. А потом можно написать инструмент-компилятор на новом языке, который будет компилироваться инструментом-компилятором предыдущей версии.

Мы же теперь живём в XXI веке. В мире настолько много опытных программистов, как никогда ранее в истории. И ещё нам сейчас более чем когда-либо ранее необходим эффективный софт.

В XX веке всё было проще. У вас есть идея, вы обёртываете её в некий пользовательский интерфейс и продаёте как продукт для ПК. Программа тормозит? Какие проблемы? Всего через полтора года компьютеры станут вдвое быстрее. Главное войти на рынок, начать продажу фич, предпочтительно — чтобы они работали без багов.

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

Но вот почитать про языки, предназначеные для повышения эффективности выполнения - это таки да, интересно. Так что если рассматривать статью исключительно с этой стороны, то она IMHO таки достойна перевода.

Тем не менее, считаю, что писать на C++ — плохая привычка. Этот язык небезопасен, не так эффективен, как считается, при работе с ним программисту приходится жутко ломать голову над вещами, которые никак не связаны с созданием ПО. А вы знаете, что в MSVC uint16_t(50000) * uin16_t(50000) == -1794967296? А знаете, почему? Да, вот такие мысли меня занимали.

Доктор, когда я так делаю. Мне больно.

Так не делайте так.

Используте новые стандарты и хорошие практики и будет вам счастье.

uint16_t(50000) * uin16_t(50000)

А вот тут все зависит от того, что компилятор использует для "промежуточного результата вычислений" и куда потом заносится результат.

В иных системах вы получите корректный результат если все это заносите в uint64_t или системное исключение что результирующей переменной недостаточно для сохранения результата, если попробуете все это занести в uit16_t. Но результат будет или "все хорошо, работаем дальше" или "тут какая-то дичь и дальше будет еще хуже, поэтому стоп."

если ваш конпилятор Сам Без Спросу преобразует Unsigned в Signed то это уже диагноз к выбиральщику конпилятора.

Даже если делать так?

uint64_t a = uint16_t(50000) * uin16_t(50000);

Да.

Речь не о том кто что куда преобразует. А о том, что будет в случае переполнения.

Справедливости ради, в новых стандартах integer promotion никуда не девается. Когда с вычислениями на C или C++ имеешь дело регулярно, это все учитываешь автоматически, "жутко ломать голову" отнюдь не требуется. Впрочем, тут выше пишут, что "современный погромист", дескать, читать мануалы не привык, а привык собирать все из готовых кусочков (и то с переменным успехом, как в известной сцене из фильма "Идиократия", где главный герой наблюдает за поведением соседей по тесту на уровень интеллекта), зато вот получать хочет все больше. Верной дорогой, как говорится.

НЛО прилетело и опубликовало эту надпись здесь

Это разумно требовать от С++ сеньора. И нагружать его соответствующими задачами. Пусть запилит супер оптимизированные штуки для вашей предметной области на которых другие люди уже построят нужную бизнес логику.

Насколько я знаю геймдев именно так устроен. С++ разрабы пилят супер оптимизированный код. Дизайнеры уже на нем рисуют максимально красивые модельки, а геймдизайнеры делают интересные сражения.

НЛО прилетело и опубликовало эту надпись здесь

Игра 2024 года на Unreal выглядит лучше Crysis 2013 года. А ещё лучше посмотреть на то что последние версии Unreal могут не в играх, там явно видно производительность.

А многопоточку везде сложно писать. А там где "просто" можно уткнуться в невозможность нормального описания разделенных мутабельных данных или производительность мьютексов. И даже если эти проблемы можно обойти, нужно тщательно продумывать как это сделать не создав бутылочное горлышко.

привык собирать все из готовых кусочков

Одним словом, современный программист работает с гораздо большим количеством инструментов, каждый из которых имеет свои нюансы. Мануалов, соответственно, тоже стало больше. :)

НЛО прилетело и опубликовало эту надпись здесь

Если "новые стандарты" и "хорошие практики" это ckd_mul() из C23 и аналогичные интринсики GCC+Clang, то я согласен. Но для их прихода ко всем ещё несколько лет. Кстати, куда пропала ckd_shl?

Похоже, вы единственный, кто сможет ответить на ваш же вопрос. ☺

Описанное весьма похоже на ситуацию, когда в очередном проекте с классической классической клиент-серверной архитектурой я решил выбрать одну из ORM: не нужно строить многоэтажные SQL запросы, система всё разрулит сама, в крайнем случае железа помощнее добавим и т.д. Ну, всё хорошо, пока не появятся узкие места: большие объемы, необходимость явного управления транзакциями, оптимизация, миграция между версиями структр... Ага, я справился, так как раньше делал "руками" и понимал, что должно происходить на нижнем уровне.

Имхо, здесь описанными преимуществами сможет воспользоваться лишь тот, кто понимает, во что и почему транслируется Python - код, т.е., специалист, имеющий опыт работы с С/С++...

1. Многочленная модель в 3 раза быстрее стандартной синусной функции, если собрать её при помощи clang 11 и опциями -O2 -march=native, а затем выполнить на Intel Core i7-9700F. Но, если собрать её при помощи NVCC с опциями --use-fast-math и выполнить на GPU, а именно на GeForce GTX 1050 Ti Mobile, то стандартная синусная функция окажется в 10 раз быстрее многочленной модели.

Это мне напомнило детские приколы. Кто быстрее: черепаха или Усэйн Болт?
А если Усейну ноги в бетон залить?

при "use fast math" - у вас будут не синусы, а функции, отдалённо их напоминающие (там ошибка уж очень большая). Что по-хорошему должно отдельно указываться в ТЗ (для нейросеток с пониженной точностью пойдут, только если learning и inference - использовать на одинаковых устройствах).

Киллер C++ № 1. SPIRAL

Использует:

Shell 60.7% (написана на С)

GAP 21.0% (написана на C)

C 16.6%

Киллер C++ №2. Numba

Библиотека Python, который вроде как на C реализован.

Киллер C++ №3. ForwardCom

Итак, ForwardCom — это ассемблер .... С любой практической точки зрения, это C будущего.

Инструментарий написан на C и С++.

Как я понял, у всех этих киллеров под капотом C и C++. Это уже самоубийство какое-то :)

Ну, если так рассуждать, то развитие именно так и происходит:

  1. Убийца машинного кода был написан на машинном коде.

  2. Убийца ассемблера был написан на ассемблере.

Допустим, компилятор убийц ассемблера может быть написан без использования ассемблера и переводить программу сразу в машинный код (объектный код опустим), минуя тот же ассемблер.

Тогда вопрос, а вот с этими убийцами убийц ассемблера такой фокус получится? Или для их существования/поддержки всё же требуется C/C++/третий язык?

Как заметил автор статьи, сейчас ничего полностью не умирает, тот же ассемблер, например. Он просто перестал быть мейнстримом. И если говорить о мейнстриме, то ИМХО Python или JS несколько лет уже вроде как "убили" сами знаете кого. Только вот ОС, драйвера и прочее, где нужна перфа, на этих "убийцах" не пишется.

Наблюдая за тем как всё больше "десткопных" приложений не могут запуститься без гигабайта памяти для текстового чата, я очень сильно надеюсь, что не будут писаться и дальше. Иначе linux.js, куда нужно установить gcc.js и просто подождать ещё 43 часа пока скачивается весь npm

этих убийц плюсов уже столько, что никто не помнит как их всех зовут.

вот еще три новых имени появилось.

Если говорить серьёзно по теме статьи, то три киллера С++ (в порядке увеличения их значимости):
1. С++
2. Go
3. Rust.

Го подпирает С++ "сверху", как язык более высокоуровневый, Rust снизу, как более низкоуровневый, а сам С++ - стимулирует программистов переходить на другие, более удобные \ безопасные whatsoever языки.

Это смешно, потому что правда.

если можно писать на Python и иметь производительность как на C++, то зачем вообще писать на C++?

Из-за преимуществ Обязательной Статической Типизации.

Узнать, что ваша программа не будет работать не в середине недельного цикла выполнения а сразу при компиляции - дорогого стоит!

Динамическая типизация питона с ней никогда не сравнится потому что она опциональна, а программисты ленивы и поэтому нельзя гарантировать что в стороннем коде кто-нибудь не нарушит ваш API.

То, что статическая типизация повышает безопасность это, извините, миф. Конечно, если:

  1. Использовать ЯП/среду со строгой типизацией, которая кидает исключения при малейшем несовпадении, а не JS.

  2. Использовать эксплиситные конвертеры. (Грубо говоря, var a = 5.0; var s = String.print("%f", a);, для переменной a тип не выводится, типов нет, но если подсунуть %i, вылетит птичка).

  3. Покрывать код тестами и прогонять их перед тем, как пускать недельные циклы.

Собственно, компиляция (как проверка, а не как способ получить бинарник) — это относительно дешёвая и относительно слабая замена полноценных тестов, которая основывается на предположении, что если типы нигде не перепутаны, то всё как-нибудь выполнится.

И я бы сказал, вообще так ставить вопрос нельзя — про преимущества статической типизации. Есть сценарии, где без неё просто нельзя обойтись. Например, задачи, для которых надо явно задать i4 или i8. Да хотя бы вот, если надо написать динамическую типизацию (для юзеров), нужна статическая типизация для себя (или CaaS). А есть сценарии, когда обойтись можно и нужно.

НЛО прилетело и опубликовало эту надпись здесь

Контекст был именно плюсы )

дедфуд ты что ли? а с тем акком что случилось?

НЛО прилетело и опубликовало эту надпись здесь

тестировать остаётся ваши предположения о том, как работает условная ФС/БД/тому подобное

Тот неловкий момент, когда прочитал "как работает условная ФСБ"...

НЛО прилетело и опубликовало эту надпись здесь

Вопрос не в безопасности, вопрос в возможности гарантировать работоспособность кода.

Проблема питона в том, что когда в новой версии чужого кода кто-нибудь добавит или уберёт пару параметров у функции (да или банально ты сам забудешь что-нибудь указать) то это будет проглочено без малейших сигналов до тех пор, пока не дойдёт очередь до исполнения.

Если в C++ есть два модуля, каждый из которых работает правильно и при их взаимодействии нет никаких ошибок то они будут работать правильно и вместе в >90% случаев.

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

Самое грустное, что на Python уже некоторое время можно накидывать типы, но в доке чёрным по серому написано

Note: The Python runtime does not enforce function and variable type annotations. They can be used by third party tools such as type checkers, IDEs, linters, etc.

Я не найду с ходу ссылки, но делались расширения рантайма, который это проверял именно на основании описанных типов (вставлял assertʼы в рекомендованных местах). Встроиться в систему импорта в Python достаточно легко.

Но и описание для чекеров это уже неплохо, чтобы вылавливать самые грубые ошибки.

Руки бы поотрывать тому, кто меняет сигнатуру публичной функции без сохранения обратной совместимости. И это безотносительно ЯП.

Собственно, компиляция (как проверка, а не как способ получить
бинарник) — это относительно дешёвая и относительно слабая замена
полноценных тестов, которая основывается на предположении, что если типы
нигде не перепутаны, то всё как-нибудь выполнится.

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

Сильная и статическая типизации - лучше обе, но и по отдельности тоже улучшение - позволяют сократить тестирование до характерных тестов - прямых и маргинальных.

В языках типа C/C++ к этому надо добавить максимальный обход undefined behavior, работы в этом направлении ведутся, хоть и слишком медленно. В более новых эта проблема чаще всего решена кардинально, даже если не слишком эффективно для работы кода.

  1. Покрывать код тестами и прогонять их перед тем, как пускать недельные циклы.

Конкретный workflow вашего проекта имеет мало отношения к общей работе отрасли.

И я бы сказал, вообще так ставить вопрос нельзя — про преимущества
статической типизации. Есть сценарии, где без неё просто нельзя
обойтись. Например, задачи, для которых надо явно задать i4 или i8.

Или задачи, в которых должно быть именно целое число. Или задачи, в которых должно быть целое число от -90 до +90. Или ещё стопиццот вариантов, когда i4 или i8 это просто контейнер, слишком широкий для представимых значений, просто ближайший адекватный.

Ага, конечно. Если взять компиляцию, так от неё никто не ждёт чудес проверки безошибочности, как-то понимают люди, что достаточно проверки узких мест, типа наличия поля с заданным именем (при компиляции даже характер данных не проверяется!). А как в том же самом контексте речь зашла про тесты, так вынь да положь проверку всех сочетаний, чтобы они считались полноценными.

Если вы не в курсе, ваши «"полноценные тесты"» невозможны не за миллионы лет, они просто невозможны. Я когда-то специально интересовался, как обходят проблему остановки в системах, которые что-то гарантируют. И мне было отвечено, что введением фундаментальных ограничений, которыми в ЯП общего назначения и не пахнет.

А мои «полноценные тесты» это результат творческого процесса, потому что узкие места определяет программист, а не тупой автомат (компилятор). Именно поэтому они и лучше.

Не надо передёргивать. Предъявляйте к компилятору те же самые требования по отлову ошибок, которые предъявляете к тестам, и посмотрим, за сколько миллионов лет его напишут.

Предъявляйте к компиляции те же самые требования по отлову ошибок, которые предъявляете к тестам, и посмотрим, за сколько миллионов лет его напишут.

Э...

В статически-типизированном языке C++ можно определить шаблон класса bounded_value, что-то типа:

template<typename T, T Lower_Bound, T Upper_Bound>
class bounded_value {...};

конструктор которого будет проверять, что переданное ему значение попадает в [Lower_Bound, Upper_Bound]. Что легко протестировать один раз.

После чего при тестировании функций вида

void do_something(bounded_value<char, -90, 90> a, bounded_value<char, 0, 90> b) {...}

нам уже не нужно писать тесты для ситуаций, когда аргументы a и b не попадают в разрешенный диапазон.

В отличии от языков с динамической типизацией.

Это называется: «Дай сиплюсплюснику гвоздь и микроскоп, и он оба эти предмета будет забивать шаблоном» ))))

То же самое можно переписать безо всяких шаблонов, и код станет только выразительнее. Даже в языках с динамической типизацией.

То же самое можно переписать безо всяких шаблонов, и код станет только выразительнее. Даже в языках с динамической типизацией.

Можно примеры?

А чем руками плохо?

from typing import NewType
LimitedInt = NewType('LimitedInt', int)

def check_limit(a: int, min_a: int, max_a: int) -> LimitedInt:
  if a < min_a or a > max_a:
    raise ValueError
  return LimitedInt(a)

def do_something( a: LimitedInt, b: LimitedInt ):
  pass

def main():
  do_something(check_limit(argv[1], 0, 10), check_limit(argv[2], 100, 500))

Если забудешь проверить лимит, тайпчекер напомнит. Если очень хочется, можно лимиты к типу пришить.

Если забудешь проверить лимит, тайпчекер напомнит.

Вот только динамическая типизация, о которой речь шла выше, где-то по дороге закончилась.

Почему же? В check_limit можно пихать всё, что умеет приводиться к int, и претензий не будет. А больше в таком огрызке динамической типизации проявиться негде. LimitedInt тоже можно положить в переменную и трактовать её как int. Нет только автоматического приведения int в LimitedInt, в этом вся соль.

Почему же?

По факту.

Без декларации типов не заработает.

Может, это и хорошо, что закончилась. Потому что её ж тут намеренно ограничивают.

(Конечно, лучше было бы наоборот - динамическая только там, где явно разрешено.)

По-моему упущен важный момент, что ограничения выражены в типе. У вас LimitedInt просто чем-то ограничен, у комментатора выше он ограничен конкретными значениями

А, так это же легко сделать, просто в check_limit не передавать пределы, а жёстко вкодить. Он выступает, по сути, конструктором для LimitedInt. Я просто показал пример семантического использования типов.

from typing import NewType
Hours = NewType('Hours', int)
Minutes = NewType('Minutes', int)

def make_hours(a: int) -> Hours:
  if a > 24:
    raise ValueError
  return Hours(a)

def make_minutes(a: int) -> Minutes:
  if a > 60:
    raise ValueError
  return Minutes(a)

def timeout(hours: Hours, minutes: Minutes):
  seconds: int = hours * 60 *24 + minutes * 60

Ну в вашем примере вы упомянули конструктор. Значит проверки будут происходить в рантайме. А значить даже в каком-нибудь пайтоне можно описать класс BoundedNumber который точно так же будет проверять в конструкторе что там ему пришло на вход.

А хотелось бы перенести проверки на этап компиляции. Правда, это возможно только на всяких экзотических языках типа Coq, где компиляция программы будет эквивалентна доказательству теоремы "Значения типов bounded_value никогда ни при каких обстоятельствах не выйдут за указанные пределы"

Сложно что-то вынести на этап компиляции на языке, где нет компиляции. А самое главное, что эта проверка всё равно где-то будет в рантайме, если вы значение получаете из внешней среды или вычисления. Нужно лишь добиться, чтобы проверка была один раз, не больше, не меньше.

Можно вынести на этап прогона юнит-тестов, который во многом заменяет для Питона проверки при компиляции. Через assert-ы которые убираются в релизном запуске.

А значить даже в каком-нибудь пайтоне можно описать класс BoundedNumber который точно так же будет проверять в конструкторе что там ему пришло на вход.

Посмотрите эту ветку обсуждения: https://habr.com/ru/articles/811151/comments/#comment_26776101
Я там основную претензию высказал -- когда начинается декларация типов в Python, исходная динамическая типизация прощается с нами.

А хотелось бы перенести проверки на этап компиляции.

Да. Но в статике хотя бы часть проблем с типизацией выявляется во время компиляции, а не в рантайме.

при компиляции даже характер данных не проверяется!

Ну пока вы будете думать только про типы i4 и тому подобные - да. Но если вы ни разу не видели enumʼы, ranged типы с проверкой при присвоении, и т.п. - это говорит только о вашем кругозоре. Даже в стандартном C++ тривиально сделать диапазонный тип (или взять готовый из boost). А с помощью __builtin_assume при чтении значения такого типа можно ещё и указать компилятору, какой диапазон значений, чтобы он использовал это в своих оптимизациях.

А как в том же самом контексте речь зашла про тесты, так вынь да положь проверку всех сочетаний, чтобы они считались полноценными.

Это у вас какое-то "вынь да положь". Я никогда такого не заявлял. Тесты это средство написания кода, верифицируемого в контролируемых условиях, и рассчитываются в первую очередь на обеспечение этой верификации (даже если она просто визуальная, то есть вычитка кода). Без верификации тестируется что угодно, но без тестирования нет гарантии условий для верификации. (И вот тут как раз крайне желательно, чтобы компиляция не ломала эти гарантии.)

А динамическая типизация в первую очередь даёт потерю этих самых гарантий контроля, ещё более "эффективно", чем undefined behavior и прочие неприятные особенности.

Если вы не в курсе, ваши «"полноценные тесты"» невозможны не за миллионы лет, они просто невозможны. Я когда-то специально интересовался, как обходят проблему остановки в системах, которые что-то гарантируют.

Если вы не в курсе, то такой результат получается без ограничения размера и сложности систем. А если вы проверяете, например, функцию деления чисел в процессоре без команды деления (как Itanium) - то перебрать полное множество сочетаний делимого и делителя возможно, даже если это 2^128 вариантов (2^64 * 2^64). И искусство тестирования состоит в том, чтобы определить, какие тестовые входные значения нужны, а какие - излишни, зная алгоритм (или, наоборот, не зная).

Что-то с вашим забегом в теорию тут откровенно "не то".

А мои «полноценные тесты» это результат творческого процесса, потому что
узкие места определяет программист, а не тупой автомат (компилятор).
Именно поэтому они и лучше.

А с чего вы решили, что у кого-то узкие места определяет компилятор? Что вы вообще тут назвали "узкими местами"?

Не надо передёргивать. Предъявляйте к компилятору те же самые требования
по отлову ошибок, которые предъявляете к тестам, и посмотрим, за
сколько миллионов лет его напишут.

Передёргиваете именно вы, выставляя такие требования. Статическая и сильная типизации помогают отлавливать большое количество проблем, которые при динамической и при слабой типизациях можно было бы ловить только тестами. Я пишу на Python с 2004 года и постоянно имею дело с проблемами динамики - то None вместо строки, то строка вместо числа, то двумерный массив вместо объекта матрицы и наоборот (привет numpy)... и это ещё Python, где типизация в основном неплохо сильная. Раньше ещё был Perl, где простейший аналог d['x'] выдаёт undef, и такая ерунда плодится ещё сильнее. Простейшая разметка типов и напускание чекера на код сокращает время на тестирование раза в 2-3 при первом написании, и несчётно - при последующем возврате к коду.

НЛО прилетело и опубликовало эту надпись здесь

Я другими словами попробую сформулировать. И заодно попробую дать ответ на вопрос, который меня когда-то очень интересовал.

Есть люди, для которых философия, эпистемология и вообще фундаментальная наука — «факультет ненужных вещей». Когда такие люди включают айфон, они не видят связи между его работой и научными принципами, которые отвергают. А я, например, наоборот, знакомясь с каким-то фундаментальным принципом всегда ищу, как он проявляется в каждодневных вещах, и как на них влияет. Соответственно, узнав о проблеме остановки, я задался вопросом: какой может быть прок от тестирования, если законы природы налагают фундаментальный запрет на предоставление гарантий даже по простейшему вопросу: не зависнет ли программа?

Ведь эти заходы про миллионы лет, они же для лохов. При обсуждении вечных двигателей и тестирования они не уместны. Вечный двигатель или работает вечно, или нет. Тестирование либо даёт гарантии, либо нет (и нет, оно их не даёт).

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

Автор тестов делает то же самое. Он просто выискивает потенциально проблемные ситуации и добавляет проверки. Иногда он основывается на репортах о пропущенных багах, добавляя тест, чтобы искать подобную проблему в будущем. Тоже ничего сверхъестественного. Проблема тут в том, что кто-то слишком буквально трактует слова «100%-ное покрытие тестами». Надо понимать, что это не абсолютные проценты, а чья-то персональная метрика. К тому же, она эмерджентна (несводима к составным частям). Если кто-то разбил проект на 10 частей и проверил каждую, другой может разбить проект на 11 частей в соответствии со своим вИдением, и окажется, что тестов не хватает.

Теперь, главное: в чём польза. Когда компилятор делает свои наивные проверочки, ему доступна, ещё раз, только грамматика языка. Она, конечно, фильтрует много откровенного шлака, но очень примитивного. А когда проверки делает программист тестов, ему доступны помимо грамматики: 0) знания о типичных сценариях, 1) общие знания о предметной области, 2) характерные данные, 3) реальное поведение среды (со всеми багами и трактовкой ошибочно неоднозначных мест из документации). Естественно, проверки, написанные программистом, будут лучше и полнее, чем результат компиляции.

Поэтому я зверею, когда слышу от нубов, которые не знают ничего кроме JS и TS или JS и C++ (никого из присутствующих в виду не имею), что статическая типизация + компиляция что-то добавляет к безопасности. Я бы не летал самолётами, не плавал пароходами, и вообще не маршировал с такими мальчишами, которые полагаются на проверки компилятора, вместо того, чтобы все их закладывать в тесты (вместе с кучей других проверок). Которые, разумеется, не потребуют никаких миллионов лет.

При всём при том, я противник TDD, и как раз по той же самой причине: TDD слишком всерьёз принимает всякие «покрытия тестами», а это идёт вразрез с фундаментальными ограничениями природы.

Ведь эти заходы про миллионы лет, они же для лохов. При обсуждении вечных двигателей и тестирования они не уместны. Вечный двигатель или работает вечно, или нет. Тестирование либо даёт гарантии, либо нет (и нет, оно их не даёт).

Верно. Тестирование само по себе - не даёт. Тестирование вместе с другими средствами, с которыми оно входит в комплект проверки - вполне может и давать. Результат, конечно, зависит от массы факторов, и в реальных проектах мало где стараются достичь абсолюта, но как помощь проблемам чтения оно работает великолепно.

Автор тестов делает то же самое.

Нет. Потому что компилятор использует то, что реально применено в коде. А автор тестов - то, что он хочет проверить. Это может быть и больше, и меньше. Но, как правило, без тестов проверки оказываются недоработанными.

И динамическая типизация тут усложняет жизнь тем, что дорабатывать надо ещё и корректность попадания значения именно нужного типа - то, что компилятором выполняется автоматически.

Он просто выискивает потенциально проблемные ситуации и добавляет проверки.

И именно необходимость явно подумать и отработать каждую из проблемных ситуаций - то, что человеку трудно (не сложно, а именно трудно), а компилятору - уже давно сделано.

Когда компилятор делает свои наивные проверочки, ему доступна, ещё раз, только грамматика языка.

И я вынужден повториться, что вы крайне примитивно думаете про возможности компилятора, не говоря уже о том, что ошибаетесь в терминологии. Что выражает конкретный тип это уже не грамматика, это семантика, и эту семантику компилятор может проверить - и часто проверяет. Если у вас один тип имеет границы значений [0..100], а другой [200..300], то присвоение первого второму может вызвать ошибку компиляции. Если у вас должно быть число, а вы передали строку - типовая ошибка в JavaScript - лучше, если это будет отловлено на компиляции, а не в рантайме.

И вот это практика, а не все те философские конструкты, которые вы зачем-то тут навернули, уходя от реальности, и, похоже, просто забалтывая.

Поэтому я зверею, когда слышу от нубов, которые не знают ничего кроме JS
и TS или JS и C++ (никого из присутствующих в виду не имею), что
статическая типизация + компиляция что-то добавляет к безопасности.

Зверейте сколько угодно... пока ваше зверение не будет оказывать влияние на реальные проекты. Я не нуб, я знаю плотно десяток языков и несколько доменов, и я твёрдо заявляю: статическая и сильная типизации добавляют к безопасности. (Я не говорю "компиляция", потому что это уже тут вопрос скорости исполнения, а не типизации. Вы снова ушли в эмпиреи, лажая в основах. Я не стал менять упоминание "компилятора" выше везде по тексту, но подразумеваю, что речь идёт про любой тип транслятора.) А добавляют они именно потому, что контролем типов - и операций над ними - позволяют при написании, анализе, и верификации кода видеть по контексту, что должно быть и что выполняется.

Я поскипал неуместные выплески философии. Хотел бы сказать, что к сожалению, но будет неправда...

"Посмотрите, как при помощи усердия и прилежания в языке X можно сделать то же самое, что в Y реализуется при помощи тайпчекера."

И ведь у C++ система типов довольно слабая, но даже она лучше, чем ничего.

Узнать, что ваша программа не будет работать не в середине недельного цикла выполнения

...а в середине недельного цикла компиляции. :)

xkcd.com/303 — это именно про плюсы.
xkcd.com/303 — это именно про плюсы.

Это не про плюсы а про шаблонную магию в плюсах. Там помню даже придумали специальный шаблон, продляющий компиляцию на нужное время.

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

" В этом движке было буквально всё, чем язык C++ мог похвастаться в 2005 году. Трёхзвёздочные указатели, восьмиуровневые зависимости, C-подобные макросы повсюду. "

азязя. тебя с самого детсва подло обманывали. это Не С++.

Для 2005 года нормально. С++03 еще был свеж и не мог быть везде в кодовой базе. Значит С++98.

C++03 — это несколько заплаток на C++98, новых фич там нет.

понимаете, все эти люди, которые хвалят прости госпади "Пытхон", они Реально Верят что 10тыщ строчек это БигДата. и что "создать зарплатную ведомость" это "очень трудоемкий процесс".

Пытхон за счёт С библиотек часто быстрее С# работает, а иногда быстрее С++. тоже касается вычислений на видеокарте

Пытхон очень быстрый

C++ в первую очередь угрожает сам C++

Это был отличный язык для своего времени, но он не справился с вызовами этого самого времени, как не справились множество его предшественников. Так устроен мир — молодёжь теснит дедушек. Мы будем с теплотой вспоминать тебя, старый добрый друг

Не "сам C++", а комитет по его "развитию" и стандартизации.

С++ уникален тем, что до какого-то времени давал программисту возможность почти полностью (за исключением мелких нюансов) контролировать генерируемый код. В этом плане его можно было бы развивать еще долго и далеко, вводя обобщения и новые понятия так, чтобы не нарушать этого принципа. Но, по мере ухода тех, кто "просекал фишку", и набегания тех, кто видит смысл программирования в "записи алгоритма конструкциями языка", новые возможности все чаще добавляются без возможности их увязывания с базовыми принципами.

То есть, хочется использовать новые возможности - придется смириться с тем, что контроль за результатом практически утрачен. Да, программа читабельна, она компилируется и правильно работает, но на то, каким образом это достигается "под капотом", лучше не смотреть, чтобы не расстраиваться. Это ставит C++ в ряд остальных непрозрачных языков, напрочь лишая его уникальности.

Хочется контролировать результат - придется либо отказаться от многих новых возможностей, либо долго и утомительно выяснять особенности их реализации на конкретной платформе, конкретной версией компилятора, и постоянно держать это в голове, ибо шаг в сторону - и компактный эффективный код мгновенно распухает и начинает тормозить.

По мне так шаблоны в C++ выглядят странно, и я надеялся, что комитет их починит...

"Странно" - это крайне мягкая характеристика. :)

-- Сынок, что сказал папа, упав с лестницы?
-- Маты пересказывать можно?
-- Нет, конечно!
-- Тогда он промолчал...

И на "починит" тоже есть соответствующие ассоциации - ну там, с раком на горе, тепловой смертью Вселенной, и подобными событиями ближайшего будущего... :)

Но, по мере ухода тех, кто "просекал фишку", и набегания тех, кто видит смысл программирования в "записи алгоритма конструкциями языка", новые возможности все чаще добавляются без возможности их увязывания с базовыми принципами.

Такое впечатление, что уход тех, кто "просекал фишку" состоялся во времена добавления в C++ механизма исключений. А то и еще раньше, когда перегрузку операторов сделали.

Перегрузка операторов не создает накладных расходов в результирующем коде - только на уровне анализа исходного текста, что достаточно легко компенсируется в IDE с навигацией по тексту.

Когда вводились исключения, то сразу же было оговорено, что накладные расходы достаточно велики, есть неочевидные проблемы, и использовать нужно с умом, а не как попало. И даже после длительного периода оголтелого использования исключений, многие умные люди признали, что это было не самой хорошей идеей.

А вот когда ввели шаблоны, то понеслась массовая истерия в стиле "долой макросы, до здравствуют шаблоны!", "если ты до сих пор используешь макросы, то ты не понимаешь C++". И все бы ничего, если б хватило ума и настойчивости приделать к тем шаблонам вменяемые средства управления. Но из всего, что хоть как-то похоже на средства управления шаблонами, почти ничто не заслуживает эпитета "вменяемое". Сплошь кривые костыли, работающие только в рамках "официально одобренных" способов применения.

А уж когда обнаружилось, что шаблоны составляют пресловутую полноту, у народа вообще поехала крыша, и с тех пор всё, что технически возможно сделать на SFINAE, по определению считается кошерным и "в стиле C++". Типа, на хрена вводить в язык какие-то новые конструкции, если того же можно добиться с помощью трех, пяти или пятнадцати завязанных в уродливый клубок шаблонов, которые потом аккуратно замести под ковер вынести в заголовок?

Если б подобный подход исповедовали создатели ассемблеров и языков типа фортрана, то конструкции "если-то-иначе", "выполнить для всех элементов контейнера" и т.п. так и не появились бы.

А вот когда ввели шаблоны, то понеслась массовая истерия в стиле "долой
макросы, до здравствуют шаблоны!", "если ты до сих пор используешь
макросы, то ты не понимаешь C++". И все бы ничего, если б хватило ума и
настойчивости приделать к тем шаблонам вменяемые средства управления.

И всё равно в целом они вменяемее тех макросов, что были до того.

Если бы сделали макропроцессор уровня CLisp или Rust, конечно, можно было бы сравнивать. А сейчас сильно много проблем с макросами, больше, чем можно себе позволить с типовым уровнем разработчиков.

Они "вменяемее" лишь при предельно тупом использовании - то есть, для прямой замены макросов, определявших достаточно примитивные классы/функции. Стоит попытаться определить что-то за пределами банальной подстановки параметров, как оно становится похоже на решение несложной арифметической задачи методами какого-нибудь функционального анализа. Нужно особым образом настраивать мозг, чтобы видеть деревья за этим лесом, не у каждого получается.

И макропроцессор, и процессор шаблонов можно было реализовать во множестве вариантов, лишь бы более-менее адекватно. Сишный препроцессор, насколько я знаю, вообще самый убогий среди существующих языков. Возможно, это повлияло и на концепцию шаблонов - "не жили хорошо, и начинать не стоило". :)

А большинство проблем с макросами растет от того, что в C/C++ не макропроцессор, а препроцессор, противоестественно отделенный от компилятора. В начале 70-х это еще можно было объяснить экономией ресурсов, но в конце 80-х такое объяснение уже не годилось. Могли бы в C++ объединить его с компилятором, превратив в нормальный макропроцессор, сделать минимально приличное управление и диагностику - и изрядная часть проблем ушла бы сразу.

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

Это есть, безусловно. Но самые простые случаи составляют большинство использования - это раз. После того, как написано и проверено, побочные эффекты (кроме раздувания кода;)) все отловлены - это два. Этого хватает, чтобы от макров избавляться по максимуму. Ну а на остаточный набор случаев, уже говорил, хочется что-то поумнее #define с прямой подстановкой цепочки лексем.

А большинство проблем с макросами растет от того, что в C/C++ не макропроцессор, а препроцессор, противоестественно отделенный от компилятора.

Да.

А вот когда ввели шаблоны, то понеслась массовая истерия в стиле "долой макросы, до здравствуют шаблоны!", "если ты до сих пор используешь макросы, то ты не понимаешь C++". И все бы ничего, если б хватило ума и настойчивости приделать к тем шаблонам вменяемые средства управления.

Осталось определиться на что вы жалуетесь:

а) на накладные расходы, которые связанны с шаблонами (какие, кстати говоря?);
b) на отсутствие "средств управления" (какого, кстати говоря?)

А то начиналось все с контроля генерируемого кода (что уже в случае с перегрузкой операторов и исключений было не просто), а пришло к порицанию некой "массовой истерии".

Простые шаблоны, вроде параметризованных классов, действительно почти не порождают накладных расходов, но кто сейчас использует простые шаблоны, да и что на них можно сделать? :)

Использование же шаблонов в том виде, как оно принято в "современном C++" - многократно вложенных, со множеством рекурсий, неочевидных зависимостей и костылей из побочных эффектов - порождает чудовищные накладные расходы прежде всего на их сочинение, анализ, компиляцию и поиск ошибок. Мало кто толком понимает, как работает эта кухня, поэтому большинство лишь применяет то, что сделано "продвинутыми программистами". Эти "продвинутые", не имея адекватных языковых средств, реализуют нужную функциональность преимущественно на побочках, но таким образом трудно сделать оптимально, чаще будет "так уж получилось, но ведь работает".

Если там под капотом исключительно статика, оно имеет шанс схлопнуться в относительно вменяемый двоичный код. Но такого уже почти не бывает, поэтому применение таких "умных" шаблонов обычно порождает множество лишних обращений к существующим переменным, временных переменных, вызовов, и редкий оптимизатор способен догадаться, что из этого можно безболезненно исключить. Начиная с некоторого уровня сложности, оптимизация практически перестает работать.

Когда же у пользователей такого "умного шаблона" возникают не совсем очевидные ошибки, большинство чаще всего опять же не понимает их внутренней логики, поэтому тупо перебирает варианты, пока ошибка не исчезнет. Говорить об оптимальном использовании тут опять же неуместно.

Под средствами управления я имею в виду способы как анализа параметров шаблона (предоставляемые компилятором, а не реализуемые вручную на побочных эффектах), так и генерации кода в зависимости от результатов этого анализа. Чтобы более-менее прозрачные сущности и алгоритмы можно было записывать относительно понятными конструкциями. То, как это принято делать сейчас, требует разворачивания в уме ряда нижележащих служебных уровней (чаще всего извращенных, по причине того самого отсутствия средств), и не является естественным следствием процесса реализации алгоритма на ЯВУ.

НЛО прилетело и опубликовало эту надпись здесь

С ходу - не смогу. Сам я таких конструкций не создаю, а когда вдруг вижу где-то, вместе с результатами кодогенерации - стараюсь побыстрее развидеть, чтоб не расстраиваться. :)

Понятно, что начинается это далеко не сразу - сперва кто-то делает библиотеку на std и своих (обычно умеренно или изрядно кривых, ибо иначе трудно) шаблонах, потом на этой библиотеке и паре других подобных делают (такими же методами) что-то более сложное, а конечное приложение находится уже где-то на пятом-седьмом уровне вложенности. Оттуда уже почти никогда не пытаются разбираться, что происходит даже парой уровней ниже, ибо опыта и терпения это требует изрядных.

А можете привести пример адекватной реализации какого-то алгоритма на основе сложных шаблонов? Адекватного в том смысле что его нельзя проще и эффективнее с точки зрения производительности скомпилированного кода переписать без сложных шаблонов?

НЛО прилетело и опубликовало эту надпись здесь

Но сложные шаблоны в итоге всем надоели

вот примерно это я и имел ввиду, все кто сталкивался с реальной разработкой с использованием сложных шаблонов рано или поздно от этих шаблонов отказываются в пользу более традиционных (что ли) решений.

Я сам пытался найти смысл применения шаблонов, шаблонов со спецификациями еще в самом начале 2000-х и пришел к выводу что разные формы наследования и владения объектов работают гораздо эффективней шаблонов практически в любой задаче. Вы не найдете шаблонов в WPF например, в OpenGL, что еще привести для примера? Шаблоны хороши только для библиотек функций по коллекциям например.

НЛО прилетело и опубликовало эту надпись здесь

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

я вам с удовольствием поверю если вы продемонстрируете какой-то пример в котором это работает так как вы говорите.

Традиционность DSL можно посмотреть по оценке

под DSL вы имеете ввиду domain-specific language ?

Это вроде как язык который надо еще придумать. Я бы даже рассуждать не взялся на такую абстрактную тему.

НЛО прилетело и опубликовало эту надпись здесь

Что именно работает? Лишнее время на вызов виртуальной функции и последствия её неинлайнинга?

Лишнее время по сравнению с чем?

Если вы посмотрите в ассемблер то вы не обнаружите сколько нибудь заметной разницы между вызовом виртуальной функции и обычной статической функции. Или вы считаете что дополнительное копирование из памяти в регистр занимает много времени?

и последствия её неинлайнинга

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

НЛО прилетело и опубликовало эту надпись здесь

Серьёзно?

Если бы у этого кода был смысл вы бы смогли его изложить. Дело в том что на бессмысленном примере можно доказать что угодно об этом еще древние греки знали.

НЛО прилетело и опубликовало эту надпись здесь

Вы наверно не в курсе, был один древний грек, который доказал что Ахилес не сможет обогнать черепаху. Только на способности Ахилеса это доказательство никак не повлияло.

Тоже самое и с вашим примером если он что-то и доказывает то только потому что вы взяли за основу задачу, которая не имеет практического смысла, на приктике такие конструкции не то что никому не нужны , они будут мешать. Поэтому так писать никто не будет, поэтому вы и стесняетесь объяснять в чем смысл вашего кода, потому что объяснения вам самому покажут какая там ерунда написана.

на приктике такие конструкции не то что никому не нужны , они будут мешать. Поэтому так писать никто не будет, поэтому вы и стесняетесь объяснять в чем смысл вашего кода, потому что объяснения вам самому покажут какая там ерунда написана

Жаль, что здесь есть только две оценки для комментария: +1 и -1.
Очень, очень не хватает оценки facepalm. Хотя здесь бы более уместной была бы double-facepalm.

НЛО прилетело и опубликовало эту надпись здесь

да фиг с ним можно без всяких умных слов, простой вопрос:

вы действительно считаете что масив констант запихать на стек в виде:

    std::vector<int> vec { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };

и делать это при каждом вызове это нормально?

по поводу

Попробуйте это сделать с полиморфными пикселями на виртуальных функциях и посмотрите на производительность.

я честно говоря не ожидал что кто-то на уровне пикселей может рассуждать про применений виртуальных функций, пиксели это байты шорты или инты, если попытаться работать с ними как с объектами - это что-то странное для меня, видимо поэтому я вас и не понимаю, теперь я вижу откуда у нас разногласия идут. Но я на уровне обработки пикселей вообще на ассемблере писал тело функции которая вызывается из С++, мне и в голову не приходило применять там темплейты или виртуальные функции, там как раз надо MMX-ы и SSE применять, поэтому без ассемблера никуда.

Если каждый байт-чар, шорт или инт в коде представлен как какая-то структура (объект) как какой-то полиморфный пиксель, тут немудрено огрести проблемы с производительностью. Я никогда такого не делал на таком низком уровне.

НЛО прилетело и опубликовало эту надпись здесь

и последствия её неинлайнинга?

еще: если у вас функция на три строчки вызывается 1000 000 раз надо подумать о структуре кода-алгоритма, а не шаблоны городить которые пытаются лечить неэффективно построенный алгоритм.

я ж говорю вы пример приведите реальный я вам покажу как правильно его построить без всяких шаблонов, будет предметный разговор.

НЛО прилетело и опубликовало эту надпись здесь

сообщения от биржи у вас через сокет приходят? три строчки вы не заметите на фоне кода который из сокета читает, мне кажется вы не совсем коректно описываете проблему или причину проблемы которая у вас видимо действительно присутствует, мне кажется.

НЛО прилетело и опубликовало эту надпись здесь

вон вы про что! Ну тогда вам точно куски на ассемблере надо писать, а вы взялись темплейты с решениями на виртуальных функциях сравнивать. Не зря вы в начали написали что перешли на что-то другое от темплейтов. Виртуальные функции на этом уровне точно нет смысла применять что там сравнивать то.

10 - 20 даже 100 ассемблерных инструкций всегда проще понять и даже переписать если надо, чем выгребать все сайд эффекты с темплейтами помноженными на оптимизацию в компиляторе которая зависит от десятка настроек, и еще и меняется с версией компилятора. Дело даже не в скорости, темплейты на таком уровне это просто не надежное решение даже.

НЛО прилетело и опубликовало эту надпись здесь

Ворочающий миллионами в день и потенциально могущий привести к очень неприятным судебным процессам код нельзя писать на асме.

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

Я понял что система у вас очень сложная и неодназначная и поэтому вдвойне интересная, спасибо. Глобальные проблемы мы все равно не решим в чате.

вы же вот мне ассемблер демонстрируете, значит вы все равно проверяете что вам компилятор генерирует, только вы каким то косвенным методом работаете, пытаетесь изобрести С++ код по которому компилятор сгенерирует самый лучший ассемблер, так еще и настройки компилятора вам надо контролировать-выписывать.

Раз вы в состоянии проверить что ассемблер хороший, что вам мешает написать этот ассемблер напрямую без капризного посредника в виде С++ компилятора? Нафига вам темплейты сдались? У меня есть только одно объяснение: рассказы про темплейты ценятся гораздо больше чем рассказы про ассемблер. Ассемблер почему то воспринимается как что-то из прошлого века, но только без него ничего не работает в конечном итоге.

Как без шаблонов в одном случае владеть объектом «линейное преобразование входных данных», а в другом — «квадратичное»?

владение объектом с интерфейсом преобразование входных данных нет? не подходит? Почему?

Если бы вы посмотрели как строится плеер видеофайлов (или даже транскодер) вы бы обнаружили что никаких шаблонов там не используется - только интерфейсы при этом нет никаких проблем с производительностью при работе через виртуальные функции, вы же HD кино на компе смотрите? Представляете какой там трафик генерируется-обрабатывается?

Более того если бы видео плеер был построен с использованием шаблонов пришлось бы каждый раз все перекомпилировать при добавлении нового формата данных, нового кодека.

НЛО прилетело и опубликовало эту надпись здесь

Там нет цели минимизировать задержку, топовая производительность там не нужна.

я вам по секрету скажу что вы это сейчас рассказываете тому кто занимался, как раз, там, как раз, достижением Топовой Производительности со всеми MMX-ами, SSE-векторизациями, DirectX-ами, и фиг знает еще с чем. Ваш

лишний indirection в рантайме

это просто какой то ну 5-й класс средней школы по сравнению с какой-то академией если производить сравнение со всеми теми технодогиями который там используются для достижения Топовой Производительности.

НЛО прилетело и опубликовало эту надпись здесь

при этом нет никаких проблем с производительностью при работе через виртуальные функции

Потому что на 1 единицу затраты времени на вызов виртуальной функции приходится 1000 или 100000 затрат на энкодинг-декодинг, даже с учётом всего ускорения через вылизанный векторный код поверх последнего SSE, BMI2 и прочих вкусняшек.

И поэтому же какие-нибудь считаемые на GPU нейросети работают под запускалкой на Python - затраты Python, в 30-100 раз больше даже самого неоптимального кода на C, не имеют значения.

А вот где нет такого отношения времён, там вы не отделаетесь. Во внутренностях кодеков как раз инлайнинг на интринсике сидит, вектором погоняет, и виртуальным функциям там не место.

Более того если бы видео плеер был построен с использованием шаблонов пришлось бы каждый раз все перекомпилировать при добавлении нового
формата данных, нового кодека.

А теперь загляните внутрь самого кодека...

Виртуальный вызов много стоит, начиная от прямого оверхеда и заканчивая упущенными возможностями по инлайнингу и прочим последующим оптимизациям

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

НЛО прилетело и опубликовало эту надпись здесь

Так они и пишут бажный. :) Потом фиксят те баги, что возникают [почти] всегда, а остальные, что возникают не слишком часто, списывают на глюки железа, ОС, кривые настройки, вирусы и происки инопланетян. :)

НЛО прилетело и опубликовало эту надпись здесь

Примерно так. Если что-то написано на питоне и жрет ресурсы, как не в себя, это, по крайней мере, не вызывает такого недоумения, как если то же самое делает написанное на C/C++.

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

Исходя из моего (пусть и небольшого) опыта программирования на VisualBasic, Java и Ruby, это утверждение истинно не только для C++.

C++ (как и C) значительно хуже из-за массы неочевидного поведения, зашитого в стандарт, причем часто как UB, а также массового заблуждения, что писать код с UB допустимо и безопасно.

Мало кто толком понимает, как работает эта кухня, поэтому большинство лишь применяет то, что сделано "продвинутыми программистами"

А на какого размера выборке основываются ваши наблюдения о "мало кто толком понимает..."? Вы же вроде как чуть ли не в одиночку работаете.

Но такого уже почти не бывает, поэтому применение таких "умных" шаблонов обычно порождает множество лишних обращений к существующим переменным, временных переменных, вызовов, и редкий оптимизатор способен догадаться, что из этого можно безболезненно исключить.

Во-первых, тут бы хотелось бы пруфов. Но, сюрпрайз, сюрпрайз, их не будет. Немного предсказуемо, да.

Во-вторых, а на каком объеме исходного текста вы способны отслеживать качество результирующего машинного кода и для какой конкретно платформы?

Допустим, у вас 10KLOC и вы в состоянии оценить качество кода для семейства x86 процессоров. А если добавить сюда еще и пару-тройку ARM-ов? А если еще и e2k? А если еще что-нибудь?

А для проекта в 100KLOC вы в состоянии глобальное качество отслеживать?
А для проекта в 500KLOC?
А для проекта в 1MLOC?
И т.д.?

Может для проекта хотя бы в 100KLOC будет уже свой набор требований, в которых требования к производительности уже не будут приоритетом №1 (а если и будут, то не ко всему коду, а к отдельным его кускам)? Например, там будут иметь значения такие вещи, как обеспечение корректности, повторное использование и отсутствие копипасты с ее проблемами. Как раз те вещи, для обеспечения которых шаблоны (включая многоэтажные) хорошо себя зарекомендовали.

А на какого размера выборке основываются ваши наблюдения о "мало кто
толком понимает..."? Вы же вроде как чуть ли не в одиночку работаете.

Я на двух последних проектах работал в команде (считаем, по сотне человек в каждом). Телеком, полу-свои железки. Команда - люди стараются, конечно, но простые вызовы ASIO и замыкание на пару параметров для них предел. Уровень выше дают ну может до 5 из всех, скорее 3. Это пойдёт как уже значимая выборка? 3-5%.

(Как пример, дважды рассылался "циркуляр" про правильное использование erase-remove в итераторах, после того, как один кусок крэшился из-за erase() на map без него. Там вообще хватало простого clear(), но все пропустили.)

С остальным примерно согласен. Но при крайне слабом контроле качества кода это всё превращается в невнятную кашу.

Это пойдёт как уже значимая выборка? 3-5%.

Да.

Но при крайне слабом контроле качества кода это всё превращается в невнятную кашу.

Я вот прямо сейчас разбираюсь с кодом, в котором практически нет своих шаблонов, только контейнеры из STL и пара-тройка алгоритмов оттуда же. Но ощущение "невнятной каши" очень стойкое.

Так что предполагаю, что не шаблоны тому виной. Они лишь катализатор (в плохом смысле этого слова).

НЛО прилетело и опубликовало эту надпись здесь

Раз пошла такая пьянка — даже при предложении очень высоких зарплат очень тяжело найти человека, который бы действительно умел писать на шаблонах что-то нетривиальное.

Раз пошла такая пьянка, то по моим личным ощущениям (моим личным, это важно) C++ники вообще никому не нужны.

итерация по строкам на порядок медленнее, чем могла бы быть

Это о чем именно?

НЛО прилетело и опубликовало эту надпись здесь

Эта претензия - не к самому языку C++, а лишь к его стандартной библиотеке, которая написана на нем же. Многие настаивают на том, чтобы считать ее неотъемлемой частью языка, но это нелогично. :)

НЛО прилетело и опубликовало эту надпись здесь

претензия именно к самому языку C++, к самой ядерной его части и его семантике

К ним тоже есть претензии, но там бороться с недостатками куда проще.

почему это не часть языка?

Потому, что "язык" (знаковая система) - это средство выражения, записи программы. А стандартная библиотека - просто набор утилит, на которые можно сослаться из программы на этом языке. Она является частью "системы программирования на языке", но не самого языка. Так же какой-нибуд "Евгений Онегин" является частью русскоязычной культуры, но никак не русского языка, как знаковой системы.

НЛО прилетело и опубликовало эту надпись здесь

в чём вообще там проблема, как вы думаете?

В особенностях реализации std::string и std::vector, вестимо. Конкретно не вникал - сам не пользуюсь ни тем, ни другим. :) Побороть можно, скорее всего, введением в язык возможности более гибкого управления кодогенерацией/оптимизацией, и соответственно переписав реализацию string.

некоторые вещи в языке невыразимы без библиотеки.

Это означает, что или с языком, или с библиотекой что-то не так. Если библиотека предоставляет просто стандартную реализацию того же самого, что любой мог бы реализовать сам средствами языка (пусть и менее эффективно), то ее уместно называть "библиотекой". Если же она содержит нечто, что средствами языка выразить невозможно, то она перестала быть "библиотекой", и ее нужно назвать как-то иначе.

Русский язык — это не только набор букв и немного синтаксических правил

Здесь важно не путать язык (знаковую систему) и литературу, языковую культуру и прочее.

НЛО прилетело и опубликовало эту надпись здесь

char* может алиаситься с любым другим типом

При чем здесь типы? Совмещение/перекрытие происходит на уровне адресов - любой тип может оказаться [частично] совмещен с любым другим. Популярные компиляторы позволяют этим управлять, но везде по-разному. По-хорошему, это тоже должно управляться на уровне языка.

Язык включает в себя семантику, библиотека — часть этой семантики.

Исходный смысл термина "библиотека" - собрание литературы (то есть, продуктов, созданных при помощи естественных языков). То есть, библиотека вторична по отношению к языку.

Исходный смысл термина "библиотека программ" примерно такой же - коллекция программ, написанных на существующих языках, а не формирующих какие-то из этих языков.

То есть, утром - язык, вечером - библиотека, или вечером - язык, утром - библиотека, но язык вперед. :)