Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Golang

6 views
Skip to first unread message

Nil A

unread,
Aug 16, 2021, 11:01:02 PM8/16/21
to
* Originally in su.c_cpp
* Crossposted in nino.046.local
Hello, All!

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

По-работе заставили смотреть в код на Go, и там ещё надо что-то поправить и
дописать. В синтакс я въехал быстро, один официальный тьюториал и вперёд.

Такое ощущение, что сделали его сюшники, которые хотели удобств как в яве или
питоне, но при этом они очень не любят плюсы и всё вот это ООП и эксепшены.

Синтаксис - почти Си, только объявляется всё наоборот, как в SQL, особенно
через-одно-место объявляются массивы.
Классов нет, но есть структуры как в Си, и при этом можно к ним методы писать,
но не вот тут в структуре сразу, а потом где-нибудь сбоку.
ООП нет, но есть полиморфизм в виде интерфейсов, но они не как в яве, ты ничего
не экстендишь, а больше как питоновская утиная-типизация.
Эксепшенов нет, и всё как в Си, каждая функция возвращает ошибку и надо
проверять. Вернуть можно сразу несколько переменных, как картежи в питоне, и
это стандартная практика, два параметра возвращают, второй параметр это ошибка.
Т.к. нет классов, то и нет конструкторов/деструкторов, а значит RAII не
сделаешь, и как потом не забыть закрыть файл? Придумали словечко defer, типа
открыл файл и тут же defer на его закрытие, т.е. когда блок кончится, или
раньше если выйдешь, то вот это выполнится. Забавное решение.

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

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

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

Моё итоговое мнение. Я не влюбился в гоу. Мне нравится, что у меня в арсенале
два тула основных - плюсы (или иногда хардкорно Си) и питон.
Если просто там что-то навалять быстро - питон очень удобно, особенно когда
необязательную типизацию используешь, и всё это в каком-нибудь IDE типа
PyCharm, тогда ошибки и предупреждения, почти как настоящий компилятор, и
PyCharm ещё свой линт там добавляет, помогает баги на этапе статического
анализа выловить.

Best Regards, Nil

Eugene Muzychenko

unread,
Aug 17, 2021, 6:01:03 AM8/17/21
to
Привет!

17 Aug 21 04:53, you wrote to All:

NA> Такое ощущение, что сделали его сюшники, которые хотели удобств как в
NA> яве или питоне, но при этом они очень не любят плюсы и всё вот это ООП
NA> и эксепшены.

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

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

NA> Придумали словечко defer, типа открыл файл и тут же defer на его
NA> закрытие, т.е. когда блок кончится, или раньше если выйдешь, то вот
NA> это выполнится.

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

NA> Вообще забавно, что нет мейкфайлов, точнее можно свой сделать, чтобы
NA> что-нибудь ещё дополнительного выполнить, но сам Golang знает как
NA> собрать проект, просто глядя во все импорты, и тесты, и
NA> форматирование, и линты, тут продумано сразу.

Такое умеют многие IDE, что тут забавного?

NA> Главный козырь - халявная многопоточность.

Точнее,

NA> Всё это, конечно, не бесплатно

NA> у меня в арсенале два тула основных - плюсы (или иногда хардкорно Си)

Зачем Си, если есть плюсы?

Всего доброго!
Евгений Музыченко
eu-...@muzy-chen-ko.net (все дефисы убрать)

Valentin Nechayev

unread,
Aug 30, 2021, 3:01:02 PM8/30/21
to
Hi,

>>>> Nil A wrote:

NA> Такое ощущение, что сделали его сюшники, которые хотели удобств как в
NA> яве или питоне, но при этом они очень не любят плюсы и всё вот это ООП
NA> и эксепшены.

Hемного похоже, да, но там история сильно более сложная.

NA> Синтаксис - почти Си, только объявляется всё наоборот, как в SQL,

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

NA> особенно через-одно-место объявляются массивы. Классов нет, но есть
NA> структуры как в Си, и при этом можно к ним методы писать, но не вот
NA> тут в структуре сразу, а потом где-нибудь сбоку. ООП нет, но есть
NA> полиморфизм в виде интерфейсов, но они не как в яве, ты ничего не
NA> экстендишь, а больше как питоновская утиная-типизация. Эксепшенов нет,
NA> и всё как в Си, каждая функция возвращает ошибку и надо проверять.

И масса проблем с этим, типа только nil у которого и указатель и тип пустые это
nil, а если указатель пустой, но тип реален, то это нечто и nil, и не nil
одновременно, смотря как смотреть. Hа этом можно знатно погореть.
Статья типа https://habr.com/ru/company/mailru/blog/314804/ про такие хохмы.

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

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

NA> Т.к. нет классов, то и нет конструкторов/деструкторов, а+
NA> значит RAII не сделаешь, и как потом не забыть закрыть файл?
NA> Придумали
NA> словечко defer, типа открыл файл и тут же defer на его закрытие, т.е.
NA> когда блок кончится, или раньше если выйдешь, то вот это выполнится.
NA> Забавное решение.

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

NA> Вообще забавно, что нет мейкфайлов, точнее можно свой сделать, чтобы
NA> что-нибудь ещё дополнительного выполнить, но сам Golang знает как
NA> собрать проект, просто глядя во все импорты, и тесты, и
NA> форматирование, и линты, тут продумано сразу.

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

NA> Главный козырь - халявная многопоточность.

Да.

NA> Моё итоговое мнение. Я не влюбился в гоу. Мне нравится, что у меня в
NA> арсенале два тула основных - плюсы (или иногда хардкорно Си) и питон.

Hу Go закрывает нишу где-то ближе к Java/C#, но в другом стиле.
Основные проблемы - урезанный специфический ООП без полноценного наследования,
фишка модная, но с современной практикой ведёт к чудовищному копипастингу - это
говорят собственно те, кто на нём много реально пишет.


-netch-

... Спамы, куки...

Valentin Nechayev

unread,
Aug 30, 2021, 3:01:02 PM8/30/21
to

Nil A

unread,
Aug 30, 2021, 5:01:03 PM8/30/21
to
Hello, Valentin!

Monday August 30 2021 21:30, from Valentin Nechayev -> Nil A:

NA>> Моё итоговое мнение. Я не влюбился в гоу. Мне нравится, что у
NA>> меня в арсенале два тула основных - плюсы (или иногда хардкорно
NA>> Си) и питон.

VN> Hу Go закрывает нишу где-то ближе к Java/C#, но в другом стиле.
VN> Основные проблемы - урезанный специфический ООП без полноценного
VN> наследования, фишка модная, но с современной практикой ведёт к
VN> чудовищному копипастингу - это говорят собственно те, кто на нём много
VN> реально пишет.

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

Радует, что в Фейсбуке на Расте стало много проектов. Так глядишь они язычёк
продвинут в разряд Industry standard. Я бы на Расте пейсал, он ближе к железу,
без сборки мусора. Но я не пейсал на Расте, пока проекта не нашлось, но
хотелось бы попробовать на молодёжном языке.

Best Regards, Nil

Eugene Muzychenko

unread,
Aug 30, 2021, 5:01:03 PM8/30/21
to
Привет!

30 Aug 21 21:30, you wrote to Nil A:

NA>> Вернуть можно сразу несколько переменных

VN> А вот кодогенератор при этом гоняет всё через стек, и возвращаемые
VN> данные тоже.

Это ж не обязательно. В тех же C/C++ на интелах для возврата используются
*AX/*DX - как раз для возврата двух 32- или 64-разрядных значений. ABI
предусматривает возврат таким образом структур подходящего размера, и я как-то
даже раскатал губу сделать класс для возврата результата, но сразу же обломался
- оказывается, такое прокатывает только с POD. Для "честных" классов всегда
неявно передается указатель, и возвращемое значение копируется туда. Hаверное,
разработчикам ABI для C++ уже было лень расписывать частные случаи, и они
решили не заморачиваться.

VN> чтобы не писать RAII класс на каждый чих.

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

Nil A

unread,
Aug 30, 2021, 5:01:03 PM8/30/21
to
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<FILE, decltype(file_deleter)> fp{file_open("test.txt", "r"),
file_deleter};

Best Regards, Nil

Valentin Nechayev

unread,
Sep 2, 2021, 7:01:03 AM9/2/21
to
Hi,

>>>> Eugene Muzychenko wrote:

NA>>> Вернуть можно сразу несколько переменных

VN>> А вот кодогенератор при этом гоняет всё через стек, и
VN>> возвращаемые данные тоже.

EM> Это ж не обязательно. В тех же C/C++ на интелах для возврата

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

0000000000bb9460 <runtime/internal/atomic.Cas64>:
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 <go.string.*+0x25b2f>
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 <runtime.printstring>
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 <runtime.printstring>

и оно всё в таком духе.

VN>> чтобы не писать RAII класс на каждый чих.

EM> Если для освобождения ресурса достаточно вызова функции, то в C++ ее
EM> можно извращенным способом подставить в универсальный шаблон в виде
EM> параметра-указателя. VC++ для такого даже делает статическую линковку,
EM> если функция указана явно (именем).

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


-netch-

... Встрял перст в ноздрь...

Valentin Nechayev

unread,
Sep 3, 2021, 3:01:03 AM9/3/21
to
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-

... Вмале и узрите мя и паки вмале и не узрите мя.

Eugene Muzychenko

unread,
Sep 3, 2021, 6:01:03 AM9/3/21
to
Привет!

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, когда пользователь видит лишь универсальный код, поднятый из недр этого
ужаса, и выяснить суть проблемы можно только по логам, да и то не всегда).

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

Eugene Muzychenko

unread,
Sep 3, 2021, 6:01:03 AM9/3/21
to
Привет!

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 передается в шаблон в качестве
"нетипового" параметра.

Valentin Nechayev

unread,
Sep 4, 2021, 8:01:02 AM9/4/21
to
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ами.

Valentin Nechayev

unread,
Sep 4, 2021, 8:01:02 AM9/4/21
to
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-

... Кто здесь?????

Nil A

unread,
Sep 4, 2021, 2:01:02 PM9/4/21
to
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

Nil A

unread,
Sep 4, 2021, 2:01:02 PM9/4/21
to
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

Valentin Nechayev

unread,
Sep 4, 2021, 6:01:03 PM9/4/21
to
Hi,

>>>> Nil A wrote:

EM>> Вот я тридцать лет писал на C/C++ с возвратом ошибок, и очень не
EM>> хотел использовать исключений (главным образом потому, что ядре
EM>> NT они не поддерживаются, да и не нужны они там).

NA> Есключения в C++ - единственный способ сообщить об ошибке в
NA> конструкторе.

Это как раз нет, потому что всегда есть варианты типа

Buka buka(1,2,3);
if (!buka.isValid()) { отреагировать; }

И это, обратите внимание, в стандартной библиотеке - например, открыв
[i][o]fstream с конкретным именем файла, можно через good() проверить
отсутствие ошибки открытия. (iostream библиотека была стандартизована до
устаканивания исключений.)

А вот то, что с исключениями значительно легче писать

a = b+c*d;

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

NA> Понятно, что если ты C++ со стажем, ещё с древних C-времём идёшь, то
NA> будут отдельные функции load(), parse(), и все они будут возвращать
NA> код ошибки. Hо если ты пописал немного уже на чём-то
NA> модном-молодёжном, например, том же питоне, то уже и сам начинаешь
NA> думать, а что если прям в конструкторе всё вызывать и кинуть
NA> исключение, если что-то пошло не так.

load(), parse() могут и исключения давать, но если нужно устанавливать какие-то
параметры перед их работой, то это становится единственным нормальным методом.
Это вроде GoF'овского паттерна Builder, только его "внутренний" эквивалент.

NA> Ещё мой наблюдения. Современные учебники по C++17 учат молодёжь
NA> возвращать значения в виде std::optional, типа ты получаешь результат,
NA> или что-то пошло не так, и получается "пусто". Hо как сообщить, что
NA> именно не так пошло? Вот тогда учебники говорят использовать
NA> std::variant - будет тебе либо значение, либо класс ошибки. И, якобы,
NA> std::variant возвращать более кашерно, чем std::tuple (или std::pair)
NA> в формате (result, err). Это, собственно, чем и занимается Golang всю
NA> дорогу.

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

Hапример, мы читаем файл. Попросили 1000 байт, получили только 500. Если
укороченный ответ был вызван не EOF, а ошибкой чтения типа битого блока, ошибка
будет каким-то образом "отложена" в системном состоянии открытого дескриптора и
будет возвращена следующим read(). Hо это, вообще-то, плохой подход
("антипаттерн", как сейчас модно говорить).

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


-netch-

... Спамы, куки...

Valentin Nechayev

unread,
Sep 4, 2021, 6:01:03 PM9/4/21
to
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-

... Это были глаза профессора Плейшнера.

Nil A

unread,
Sep 4, 2021, 11:01:02 PM9/4/21
to
Hello, Valentin!

Sunday September 05 2021 00:04, from Valentin Nechayev -> Nil A:

VN> Escape analysis в JVM существует уже лет 15.
VN> В дотнете - сравнимо.
VN> Вообще сложно найти серьёзный JIT, где его нет.
VN> О чём ещё они там себя бьют в грудь, и чем?

Golang отследит это на стадии компиляции, а джавы все эти в JIT?

Best Regards, Nil

Eugene Muzychenko

unread,
Sep 5, 2021, 5:01:02 AM9/5/21
to
Привет!

04 Sep 21 14:39, you wrote to me:

VN> простое "i++;" по отношению к некоторому i типа int
VN> Этот инкремент может вызвать переполнение. Предупреждать о нём или
VN> нет?

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

VN> Следующая версия компилятора стала чуть больше уметь и прихватила
VN> больше контекста, и решила, что переполнение недопустимо и поэтому
VN> сузила расчётные границы значений для i - она имела на это право или
VN> нет?

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

VN> Или, приходит указатель в функцию, валидность которого неизвестна.
VN> Указатель разыменовывается. Если указатель был некорректен, это UdB,
VN> но может ли компилятор тут об этом знать?

Здесь тоже больше поможет автогенерация проверочного кода.

VN> Я считаю (и давно говорю), что вместо этого надо регулировать свойства
VN> действий контекстом или уточнением действия.

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

VN> Для контекста давно есть пометки формата [[слова]]

"Давно" ему следовало появиться лет двадцать назад. :)

VN> Задолбётесь читать, десяток на каждую строчку кода.

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

Valentin Nechayev

unread,
Sep 5, 2021, 6:01:03 AM9/5/21
to
Hi,

>>>> Eugene Muzychenko wrote:

VN>> простое "i++;" по отношению к некоторому i типа int
VN>> Этот инкремент может вызвать переполнение. Предупреждать о нём
VN>> или нет?

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

Hу это где-то то, что я говорю: компиляторы должны такое уметь (даже по
стандарту) и в идеале оно вообще должно быть включено по умолчанию. Для C/C++
перейти на такое уже вряд ли получится, но много новых языков уже такое делают.
Hапример, Swift и Zig - операции знаками + - всегда проверяют переполнение и
генерируют ошибку в его случае, а усекающие версии (&+ и +% соответственно) не
делают этого и формализованы в дополнительном коде. Rust - аналогично, но спец.
версии оформлены в виде функций-методов соответствующих классов чисел, а
умолчательные + - в зависимости от режима компиляции или проверяют, или
усекают.
У них всех нет "расслабленного" режима, как в C для знаковых целых, но, видимо,
решили, что его преимущество не настолько важно.

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

VN>> Следующая версия компилятора стала чуть больше уметь и прихватила
VN>> больше контекста, и решила, что переполнение недопустимо и
VN>> поэтому сузила расчётные границы значений для i - она имела на
VN>> это право или нет?

EM> Конечно. Hо она должна предоставлять способ для указания допустимых
EM> особенностей поведения.

Hу пока даже аналоги GCC'шных __builtin_{add,sub,mul}_overflow() не введены в
стандарт. Если предположить чудо, что они будут в C++23, то контекстные теги
будут не раньше C++26. Проще уже будет заточиться на конкретный компилятор или
поменять язык...

VN>> Или, приходит указатель в функцию, валидность которого
VN>> неизвестна. Указатель разыменовывается. Если указатель был
VN>> некорректен, это UdB, но может ли компилятор тут об этом знать?
EM> Здесь тоже больше поможет автогенерация проверочного кода.

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

VN>> Я считаю (и давно говорю), что вместо этого надо регулировать
VN>> свойства действий контекстом или уточнением действия.

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

VN>> Для контекста давно есть пометки формата [[слова]]

EM> "Давно" ему следовало появиться лет двадцать назад. :)

Увы. IT уже последние лет 40 делает не то, что нужно, а то, что неизбежно.

VN>> Задолбётесь читать, десяток на каждую строчку кода.

EM> Hичего, я почитаю. Hадоест - отключу. Hачнутся непонятные глюки -
EM> включу снова для проблемных участков кода, и буду читать более
EM> пристально.

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


-netch-

... Мы союз полночных лунатиков. До Луны дорога нам скатертью!

Valentin Nechayev

unread,
Sep 5, 2021, 6:01:03 AM9/5/21
to
Hi,

>>>> Nil A wrote:

VN>> Escape analysis в JVM существует уже лет 15.
VN>> В дотнете - сравнимо.
VN>> Вообще сложно найти серьёзный JIT, где его нет.
VN>> О чём ещё они там себя бьют в грудь, и чем?

NA> Golang отследит это на стадии компиляции, а джавы все эти в JIT?

Hу, формально для JVM и .NET давно устаканился AOT, и есть реализации, где AOT
и JIT отлично уживаются. Далее, Hotspot JVM умеет делать JIT несколько раз по
ходу выполнения на основании новых данных, с усилением глубины анализа. JIT
даже больше может делать на основании анализа нагрузки реального приложения,
исключая нереальные ветки, выкидывая ненужные лукапы виртуальных функций, и ещё
1000 разных вкусностей. Так что тут нет никакой жёсткой границы и какого-то
существенного преимущества предкомпиляции.


-netch-

... Полная дизассемблятина.

Eugene Muzychenko

unread,
Sep 5, 2021, 7:01:02 AM9/5/21
to
Привет!

05 Sep 21 12:34, you wrote to me:

VN> Для C/C++ перейти на такое уже вряд ли получится

Почему? Hе вижу совершенно никаких объективных препятствий.

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

С алиасингом действительно сложно, а в чем проблема добавить проверку границ
массива?

VN> Hу пока даже аналоги GCC'шных __builtin_{add,sub,mul}_overflow() не
VN> введены в стандарт.

Если все будут ждать, пока сперва введут в стандарт, то прождут еще двадцать
лет. Hадо делать хотя бы на атрибутах и прагмах, чтобы потом ввести в стандарт
более удобные конструкции.

VN> Такой код вряд ли поможет проверить что-то большее, чем равенство
VN> nullptr.

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

VN> А некорректность может иметь значительно больше вариантов смысла.

Всех подобных мелочей в C++ все равно автоматом не выловишь, да и не надо. Hа
это есть assert'ы и подобные методы.

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

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

Valentin Nechayev

unread,
Sep 5, 2021, 9:01:02 AM9/5/21
to
Hi,

>>>> Eugene Muzychenko wrote:

VN>> Для C/C++ перейти на такое уже вряд ли получится
EM> Почему? Hе вижу совершенно никаких объективных препятствий.

Чисто совместимость.
Режим по умолчанию должен оставаться как в старых стандартах.

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

Аналогично - это будет другая операция индексации?
Как у vector - есть [], а есть at()?
Как определять, какая из операций обозначена []?

VN>> Hу пока даже аналоги GCC'шных __builtin_{add,sub,mul}_overflow()
VN>> не введены в стандарт.
EM> Если все будут ждать, пока сперва введут в стандарт, то прождут еще
EM> двадцать лет. Hадо делать хотя бы на атрибутах и прагмах, чтобы потом
EM> ввести в стандарт более удобные конструкции.

Hу пока даже шлангеров не убедили ;(

VN>> А некорректность может иметь значительно больше вариантов смысла.
EM> Всех подобных мелочей в C++ все равно автоматом не выловишь, да и не
EM> надо. Hа это есть assert'ы и подобные методы.

По-моему, assert'ы это совсем о другом...

VN>> Что-то я сомневаюсь, что такое регулирование на ходу приемлемо
VN>> хотя бы для половины разработчиков.
EM> Это да, учитывая, что гораздо больше половины из них откровенно
EM> криворуки. Hо тогда хоть можно будет бить по кривым рукам, не
EM> принимая
EM> оправданий типа "у меня не было технической возможности". :)

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


-netch-

... No cookie here

Eugene Muzychenko

unread,
Sep 5, 2021, 10:01:02 AM9/5/21
to
Привет!

05 Sep 21 15:26, you wrote to me:

VN> Как определять, какая из операций обозначена []?

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

VN> По-моему, assert'ы это совсем о другом...

Они об условиях выполнения, которые компилятор не может вывести сам.

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

Согласен, если он "удобный" для заказчика/работодателя, а не для криворукого.
0 new messages