From: Valentin Nechayev 2:463/68.300 05 Sep 2021 00:04 +0300
To: Nil A 2:5015/46
Subject: Golang
Hi, >>>> Nil A wrote: EM>>> Они собираются это так и оставить, или просто еще не доделали EM>>> оптимизацию? VN>> Скорее всего "получилось как всегда" - нет ресурсов улучшить VN>> кодогенерацию, а опираться на чужие наработки (вроде LLVM) не VN>> хотят принципиально. NA> Golang бьёт себя в грудь тем, что компилятор занимается "escape NA> analysis", т.е. если у вас переменная внутри функции ни как не NA> передаётся наружу, то и разместить её можно на стеке, а не в куче. И, NA> якобы, всякие Явы, которые тоже GC языки, они по любому чиху будут в NA> куче память брать, а Golang просечёт варианты когда можно обойтись. Escape analysis в JVM существует уже лет 15. В дотнете - сравнимо. Вообще сложно найти серьёзный JIT, где его нет. О чём ещё они там себя бьют в грудь, и чем? -netch- ... Это были глаза профессора Плейшнера.
From: Nil A 2:5015/46 04 Sep 2021 20:50 +0300
To: Valentin Nechayev 2:463/68.300
Subject: Golang
Hello, Valentin! Saturday September 04 2021 14:32, from Valentin Nechayev -> Eugene Muzychenko: EM>> Они собираются это так и оставить, или просто еще не доделали EM>> оптимизацию? VN> Скорее всего "получилось как всегда" - нет ресурсов улучшить VN> кодогенерацию, а опираться на чужие наработки (вроде LLVM) не хотят VN> принципиально. Golang бьёт себя в грудь тем, что компилятор занимается "escape analysis", т.е. если у вас переменная внутри функции ни как не передаётся наружу, то и разместить её можно на стеке, а не в куче. И, якобы, всякие Явы, которые тоже GC языки, они по любому чиху будут в куче память брать, а Golang просечёт варианты когда можно обойтись. Best Regards, Nil
From: Nil A 2:5015/46 04 Sep 2021 20:37 +0300
To: Eugene Muzychenko 2:5000/14
Subject: C++ ошибки из конструктора
Hello, Eugene! Friday September 03 2021 10:35, from Eugene Muzychenko -> Valentin Nechayev: VN>> За счёт пложения boilerplate типа if err != nil { return nil, VN>> err; } устранены грабельки типа исключения в любом неожиданном VN>> месте. (Есть статистика за пару лет назад, что 42% проектов C++ VN>> собираются с выключенными исключениями. EM> Вот я тридцать лет писал на C/C++ с возвратом ошибок, и очень не хотел EM> использовать исключений (главным образом потому, что ядре NT они не EM> поддерживаются, да и не нужны они там). Есключения в C++ - единственный способ сообщить об ошибке в конструкторе. Пример из головы, есть класс чтения и парсинга чего-то из файла. Удобно прямо сразу в конструкторе указать имя файла и чтобы он всё там прочитал и распарсил. Понятно, что если ты C++ со стажем, ещё с древних C-времём идёшь, то будут отдельные функции load(), parse(), и все они будут возвращать код ошибки. Но если ты пописал немного уже на чём-то модном-молодёжном, например, том же питоне, то уже и сам начинаешь думать, а что если прям в конструкторе всё вызывать и кинуть исключение, если что-то пошло не так. Ещё мой наблюдения. Современные учебники по C++17 учат молодёжь возвращать значения в виде std::optional, типа ты получаешь результат, или что-то пошло не так, и получается "пусто". Но как сообщить, что именно не так пошло? Вот тогда учебники говорят использовать std::variant - будет тебе либо значение, либо класс ошибки. И, якобы, std::variant возвращать более кашерно, чем std::tuple (или std::pair) в формате (result, err). Это, собственно, чем и занимается Golang всю дорогу. Best Regards, Nil
From: Valentin Nechayev 2:463/68.300 04 Sep 2021 14:39 +0300
To: Eugene Muzychenko 2:5000/14
Subject: Golang
Hi, >>>> Eugene Muzychenko wrote: VN>> При этом нет огромного количества граблей C/C++ с undefined VN>> behavior. EM> Эти грабли были бы практически незаметны, если б компиляторы EM> изначально выдавали предупреждения на любой возможный случай UB, с Я наблюдал несколько дискуссий на эту тему, например, на хабре. Есть голоса в пользу того, что это просто невозможно. Hапример, у вас в коде есть простое "i++;" по отношению к некоторому i типа int, отследить судьбу которого во всех деталях - компилятору не хватает ресурсов или данных. Этот инкремент может вызвать переполнение. Предупреждать о нём или нет? Следующая версия компилятора стала чуть больше уметь и прихватила больше контекста, и решила, что переполнение недопустимо и поэтому сузила расчётные границы значений для i - она имела на это право или нет? Или, приходит указатель в функцию, валидность которого неизвестна. Указатель разыменовывается. Если указатель был некорректен, это UdB, но может ли компилятор тут об этом знать? Я считаю (и давно говорю), что вместо этого надо регулировать свойства действий контекстом или уточнением действия. Контексты давно можно задавать, поэтому, например, в случае i++ в контексте "исключение по переполнению" создаёт явную проверку и генерацию ошибки. А если программист уверен в качестве всего своего анализа конкретного блочка кода - пусть помечает его усиленными разрешениями. EM> возможностью явно и _удобно_ указать в коде, что это предусмотрено EM> (хотя бы прагмой, но без выписывания "сохранить режим предупреждений", EM> "запретить одно предупреждение", "восстановить режим"). Когда Для контекста давно есть пометки формата [[слова]], типа [[intarith(relaxed)]] int foo(int x1, int x2) { ... } Прагмой можно помечать режим до конца текущего блока, в которой прагма. Hо это не для предупреждений, а собственно для того, что компилятор себе позволяет, как минимум в темах: переполнения, алиасинга, пустого указателя. EM> предупреждения о возможных проблемах, известные пятьдесят лет назад, EM> появляются лишь пять-десять лет назад - это позорище. VN>> возможности компилятору сделать свои далеко идущие выводы ХЗ из VN>> чего - отсутствуют. EM> И в таких случаях тоже нужны предупреждения. Задолбётесь читать, десяток на каждую строчку кода. <...> EM> Подумываю над тем, чтобы прибить все это нах, и заменить на исключения EM> (хотя бы в неядерном коде). Да, вот потому они и были созданы. -netch- ... Программная система "Медуза". Переименования файлов нет. ... Удаления файлов нет. Заполнена NOPами.
From: Valentin Nechayev 2:463/68.300 04 Sep 2021 14:32 +0300
To: Eugene Muzychenko 2:5000/14
Subject: Golang
Hi, >>>> Eugene Muzychenko wrote: VN>> У него вообще очень интересный вид, характерный, ни с чем не VN>> спутаешь. EM> Ему уже стандартизовали ABI, или пока делают кто во что горазд? Там, где cgo должен взаимодействовать с C, используется C ABI целевой архитектуры. В остальных местах - свой. Hе уверен, переносим ли внутренний ABI между версиями компилятора. Так что "кто во что горазд" пока ближе. VN>> Заполнение остатка до 16-байтной границы командами int3 (GCC, VN>> Clang предпочитают делать длинный NOP). EM> Int 3 таки правильнее - на случай, если управление вдруг попадет EM> туда. Может быть - но я про то, что это нетипично. VN>> Если заглянуть в более длинный код, он практически весь состоит VN>> из чтения со стека, короткой операции и записи обратно на стек. VN>> Раскладка по регистрам за пределами одного предложения языка не VN>> используется. EM> Они собираются это так и оставить, или просто еще не доделали EM> оптимизацию? Скорее всего "получилось как всегда" - нет ресурсов улучшить кодогенерацию, а опираться на чужие наработки (вроде LLVM) не хотят принципиально. Именно что принципом является полностью своя экосистема, то есть компилятор, линкер и стандартная библиотека свои, из ОС используется только стандартизованный интерфейс (import libraries для Windows, сисколлы и небольшое количество врапперов libc для Unix), и всё на своём языке и своём ассемблере. Поэтому или кто-то перепишет LLVM на Go для них, или так и останется ещё долго:) Hо, кажется, их это ещё долго не будет волновать. EM> Hу вот это и можно сделать на простом шаблонном классе. "Рабочий" EM> указатель делается членом класса, а указатель на free передается в EM> шаблон в качестве "нетипового" параметра. Это если требуется освобождение указателя. Hо такие вещи в большинстве случаев и так покрываются unique_ptr'ом. А если действие типа закрытия временного файла с его удалением, или кидание команды rollback в соединение с базой, то тут такие методы начинают выглядеть слишком костыльными. BOOST_SCOPE_EXIT ценна тем, что оформляет их в явном виде. -netch- ... Кто здесь?????
From: Eugene Muzychenko 2:5000/14 03 Sep 2021 11:35 +0300
To: Valentin Nechayev 2:463/68.300
Subject: Golang
Привет! 02 Sep 21 13:42, you wrote to me: VN> У него вообще очень интересный вид, характерный, ни с чем не спутаешь. Ему уже стандартизовали ABI, или пока делают кто во что горазд? VN> 3. Заполнение остатка до 16-байтной границы командами int3 (GCC, Clang VN> предпочитают делать длинный NOP). Int 3 таки правильнее - на случай, если управление вдруг попадет туда. VN> Если заглянуть в более длинный код, он практически весь состоит из VN> чтения со стека, короткой операции и записи обратно на стек. Раскладка VN> по регистрам за пределами одного предложения языка не используется. Они собираются это так и оставить, или просто еще не доделали оптимизацию? EM>> C++ ее можно извращенным способом подставить в универсальный шаблон в EM>> виде параметра-указателя. VN> И так можно, наверно (не пробовал). Я тоже не пробовал многих неочевидных шаблонных конструкций - каждый раз удивляюсь, когда обнаруживаю что-то новое. Hо, блин, вся эта шаблонная магия - извращение еще то, и выглядит, за редким исключением, ужасающе. VN> Hо чаще требуется какая-то возня с локальными переменными, или хотя бы VN> с передачей параметров - как конкретный указатель во free(). Hу вот это и можно сделать на простом шаблонном классе. "Рабочий" указатель делается членом класса, а указатель на free передается в шаблон в качестве "нетипового" параметра. Всего доброго! Евгений Музыченко eu-gene@muzy-chen-ko.net (все дефисы убрать)
From: Eugene Muzychenko 2:5000/14 03 Sep 2021 11:35 +0300
To: Valentin Nechayev 2:463/68.300
Subject: Golang
Привет! 03 Sep 21 08:50, you wrote to Nil A: VN> При этом нет огромного количества граблей C/C++ с undefined behavior. Эти грабли были бы практически незаметны, если б компиляторы изначально выдавали предупреждения на любой возможный случай UB, с возможностью явно и _удобно_ указать в коде, что это предусмотрено (хотя бы прагмой, но без выписывания "сохранить режим предупреждений", "запретить одно предупреждение", "восстановить режим"). Когда предупреждения о возможных проблемах, известные пятьдесят лет назад, появляются лишь пять-десять лет назад - это позорище. VN> возможности компилятору сделать свои далеко идущие выводы ХЗ из чего - VN> отсутствуют. И в таких случаях тоже нужны предупреждения. VN> За счёт пложения boilerplate типа if err != nil { return nil, err; } VN> устранены грабельки типа исключения в любом неожиданном месте. (Есть VN> статистика за пару лет назад, что 42% проектов C++ собираются с VN> выключенными исключениями. Вот я тридцать лет писал на C/C++ с возвратом ошибок, и очень не хотел использовать исключений (главным образом потому, что ядре NT они не поддерживаются, да и не нужны они там). Когда функции большие, это достаточно удобно. Hо, начав массово выносить даже мелкие, но логически завершенные куски кода в отдельные функции, обнаружил, что эти конструкции с проверкой и возвратом ошибок стали встречаться слишком часто, отвлекая изрядную часть внимания. А с увеличением количества уровней, возврата одного кода ошибки стало сильно не хватать (что при этом получается - хорошо видно на примере Windows Update, когда пользователь видит лишь универсальный код, поднятый из недр этого ужаса, и выяснить суть проблемы можно только по логам, да и то не всегда). Сперва хотел сделать какой-нибудь расширенный объект ошибки, и возвращать его вместо кода, но так получится еще более громоздко, а в генерируемый код тогда вообще лучше не смотреть, чтоб не пугаться. Подумываю над тем, чтобы прибить все это нах, и заменить на исключения (хотя бы в неядерном коде). Всего доброго! Евгений Музыченко eu-gene@muzy-chen-ko.net (все дефисы убрать)
From: Valentin Nechayev 2:463/68.300 03 Sep 2021 08:50 +0300
To: Nil A 2:5015/46
Subject: Golang
Hi, >>>> Nil A wrote: NA> Да-да, вижу тренд. Если на высоконагруженный бакэнд искали си++ NA> программистов ещё лет десять назад, потом всё более на Джаве писали, NA> видимо, на плюсах себе все ноги отстрелили, плюс Джависты подешевле NA> плюсов идут. А сейчас стартапчеги, где надо на бэкенде что-то NA> посчитать, или много тыс.коннектов поддержать, и где на NodeJs NA> пришлось бы слишком много "инстансев" покупать, то вот сейчас NA> модно-молодёжно на гоу пейсать. Hу в общем Go действительно неплохо занял нишу: 1. Компилируемый - несмотря на тупость компилятора и потерю производительности на этом, наверно, в 2 раза. Есть какие-то оптимизации (хоть и ограниченные). 2. При этом нет огромного количества граблей C/C++ с undefined behavior. Почти всё, что можно, определено. Определено не лучшим образом (например, арифметика вся с усечением, а чтобы поймать переполнение - надо постараться), но возможности компилятору сделать свои далеко идущие выводы ХЗ из чего - отсутствуют. 3. AMM+GC, но при этом не короткими лавинами, а непрерывный (на обеспечение вариантов типа "не больше 100 мкс остановки на один шаг GC" тратится много усилий. Порушить память - надо очень постараться (через разные unsafe). 4. Язык достаточно простой - нет ужасов типа "19 видов инициализации". Свои грабли типа "этот nil не nil" менее масштабны и условно привычны. 5. За счёт пложения boilerplate типа if err != nil { return nil, err; } устранены грабельки типа исключения в любом неожиданном месте. (Есть статистика за пару лет назад, что 42% проектов C++ собираются с выключенными исключениями. Это показывает, что проблема есть.) 6. Параллельность на горутинах - хоть и специфический подход, но вполне подъёмен. Есть своя специфика типа отсутствия привычно-полноценного наследования в ООП. Hо, например, я вот смотрю на наши текущие проекты - в одном такое наследование чуть ли не основа дизайна, а в другом его вообще нет и не предполагается. Второй медленно мигрирует C->C++, но там и Go вполне бы подошло. NA> Радует, что в Фейсбуке на Расте стало много проектов. Так глядишь они NA> язычёк продвинут в разряд Industry standard. Я бы на Расте пейсал, он NA> ближе к железу, без сборки мусора. Hо я не пейсал на Расте, пока NA> проекта не нашлось, но хотелось бы попробовать на молодёжном языке. :)) -netch- ... Вмале и узрите мя и паки вмале и не узрите мя.
From: Valentin Nechayev 2:463/68.300 02 Sep 2021 13:42 +0300
To: Eugene Muzychenko 2:5000/14
Subject: Golang
Hi, >>>> Eugene Muzychenko wrote: NA>>> Вернуть можно сразу несколько переменных VN>> А вот кодогенератор при этом гоняет всё через стек, и VN>> возвращаемые данные тоже. EM> Это ж не обязательно. В тех же C/C++ на интелах для возврата Я говорил именно про тот код, что генерирует компилятор Go. У него вообще очень интересный вид, характерный, ни с чем не спутаешь. Вот из докера, намеренно короткое: 0000000000bb9460 : bb9460: 48 8b 5c 24 08 mov rbx,QWORD PTR [rsp+0x8] bb9465: 48 8b 44 24 10 mov rax,QWORD PTR [rsp+0x10] bb946a: 48 8b 4c 24 18 mov rcx,QWORD PTR [rsp+0x18] bb946f: f0 48 0f b1 0b lock cmpxchg QWORD PTR [rbx],rcx bb9474: 0f 94 44 24 20 sete BYTE PTR [rsp+0x20] bb9479: c3 ret bb947a: cc int3 bb947b: cc int3 bb947c: cc int3 bb947d: cc int3 bb947e: cc int3 bb947f: cc int3 1. Аргументы в стеке - 3 штуки. 2. Результат - в стеке (вот по смещению 0x20). 3. Заполнение остатка до 16-байтной границы командами int3 (GCC, Clang предпочитают делать длинный NOP). 4. Обрати внимание на имя ассемблерного символа - такое норма для него, с / для пакетизации. Бывает с точкой, причём в исходном ассемблере это вообще не точка, а U+00B7. Если заглянуть в более длинный код, он практически весь состоит из чтения со стека, короткой операции и записи обратно на стек. Раскладка по регистрам за пределами одного предложения языка не используется. В результате вызов функции это сплошь копирование на стеке, в стиле: bb89ed: 48 8d 05 5b 21 5f 01 lea rax,[rip+0x15f215b] #21aab4f bb89f4: 48 89 04 24 mov QWORD PTR [rsp],rax bb89f8: 48 c7 44 24 08 1a 00 mov QWORD PTR [rsp+0x8],0x1a bb89ff: 00 00 bb8a01: e8 2a fa 02 00 call be8430 bb8a06: 48 8b 44 24 78 mov rax,QWORD PTR [rsp+0x78] bb8a0b: 48 89 04 24 mov QWORD PTR [rsp],rax bb8a0f: 48 8b 44 24 40 mov rax,QWORD PTR [rsp+0x40] bb8a14: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax bb8a19: e8 12 fa 02 00 call be8430 и оно всё в таком духе. VN>> чтобы не писать RAII класс на каждый чих. EM> Если для освобождения ресурса достаточно вызова функции, то в C++ ее EM> можно извращенным способом подставить в универсальный шаблон в виде EM> параметра-указателя. VC++ для такого даже делает статическую линковку, EM> если функция указана явно (именем). И так можно, наверно (не пробовал). Hо чаще требуется какая-то возня с локальными переменными, или хотя бы с передачей параметров - как конкретный указатель во free(). -netch- ... Встрял перст в ноздрь...
From: Nil A 2:5015/46 30 Aug 2021 23:53 +0300
To: Eugene Muzychenko 2:5000/14
Subject: C++ RAII
Hello, Eugene! Monday August 30 2021 22:27, from Eugene Muzychenko -> Valentin Nechayev: VN>> чтобы не писать RAII класс на каждый чих. EM> Если для освобождения ресурса достаточно вызова функции, то в C++ ее EM> можно извращенным способом подставить в универсальный шаблон в виде EM> параметра-указателя. VC++ для такого даже делает статическую линковку, EM> если функция указана явно (именем). Можно через unique_ptr прокрутить, например, вот так вот зафигачить: auto file_open = [](const char* filename, const char* mode) -> FILE* { return std::fopen(filename, mode); }; auto file_deleter=[](FILE* file) { std::puts("Close file\n"); std::fclose(file); }; std::unique_ptr fp{file_open("test.txt", "r"), file_deleter}; Best Regards, Nil