Арифметика констант в языке Go
От: Aleх  
Дата: 16.05.17 14:40
Оценка: 6 (2) +2
Авторы языка посчитали, что с правилами приведения типов для чисел в языке Си имеются большие проблемы. Им показалось, что одной из существенных проблем в Си являются ошибки, связанные с неправильным использованием арифметических операторов для чисел разных типов. В результате они придумали нечто: https://blog.golang.org/constants Суть в том, что для констант действуют одни правила, а для переменных другие.

Это приводит к следующим эффектам:
var a = -1;
fmt.Println(uint32(a)); // OK
const b = -1;
fmt.Println(uint32(b)); constant -1 overflows uint32

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

Или таким:
var a = 9223372036854775296 + 1.0;
const b = 9223372036854775296 + 1.0;
fmt.Println(uint64(a), " ", uint64(b)); // 9223372036854775808   9223372036854775297

Сравним с C++:
auto a = 9223372036854775296 + 1.0;
constexpr auto b = 9223372036854775296 + 1.0;
std::cout << uint64_t(a) << " " << uint64_t(b); // 9223372036854775808 9223372036854775808


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

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

Что думаете об этом?
Re: Арифметика констант в языке Go
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 17.05.17 07:20
Оценка: 19 (2) +1
Здравствуйте, Aleх, Вы писали:

Ну, в C тоже полного единообразия нет. Целочисленная константа имеет тип, минимальный из того, во что она влезает (в стандарте определён порядок — signed int, unsigned int, signed long, unsigned long...; для oct/hex пробуются оба signed/unsigned, для десятичных — только один). Другой вопрос, что конверсию там не отсекают для констант, совершенно нормально передать -1 в unsigned, несмотря на то, что C не гарантирует использование дополнительного кода.

A>Авторы языка посчитали, что с правилами приведения типов для чисел в языке Си имеются большие проблемы. Им показалось, что одной из существенных проблем в Си являются ошибки, связанные с неправильным использованием арифметических операторов для чисел разных типов. В результате они придумали нечто: https://blog.golang.org/constants Суть в том, что для констант действуют одни правила, а для переменных другие.


A>Это приводит к следующим эффектам:

A>
A>var a = -1;
A>fmt.Println(uint32(a)); // OK
A>const b = -1;
A>fmt.Println(uint32(b)); constant -1 overflows uint32
A>

A>Почему для переменных переполнения разрешено, а для констант нет? (Потому что в одном случае в момент компиляции можно проверить, а в другом нет. Серьезно?)

Это как раз проблем ещё не составляет — по крайней мере, пока код не генерируется автоматом (а Go вообще имеет сильнейшее препятствие к этому, например, ошибками компиляции по неиспользованному импорту или переменной, поэтому на такое рассчитывать нельзя).

A>Или таким:

A>
A>var a = 9223372036854775296 + 1.0;
A>const b = 9223372036854775296 + 1.0;
A>fmt.Println(uint64(a), " ", uint64(b)); // 9223372036854775808   9223372036854775297
A>


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

A>Сравним с C++:

A>
A>auto a = 9223372036854775296 + 1.0;
A>constexpr auto b = 9223372036854775296 + 1.0;
A>std::cout << uint64_t(a) << " " << uint64_t(b); // 9223372036854775808 9223372036854775808
A>


Потому что в C при автоконверсии плавучие типы важнее целых, и неявная конверсия разрешена.

A>Мне такой подход кажется нелогичным из-за отсутствия единообразия в правилах вычисления переменных и констант. В подходе С++ нужно понять как работает приведение типов и арифметика. Константность выражения на способ вычисления не влияет. В Go, как и в любом другом языке с конечнозначными числами, от необходимости понимания арифметики уйти не получится, но в отличие от С++, придется помнить разные правила для констант и переменных.


Да

A>Выглядит так, что хотели обезопасить программистов от "сложных" правил арифметики чисел, а в итоге только всё усложнили и сделали менее удобным. Это не та область программирования, в которой нужно что-то пытаться упростить. Кажущаяся сложность арифметики чисел является неустранимой. Невозможно писать качественный код, не зная и не думая об этом.


Go вообще представляет в этом плане собой дикую смесь продвинутых решений и самого дикого мракобесия.
  • Заточка на дополнительный код для отрицательных и фиксированные размеры типов — ok, не он первый (Java, C#, Javascript...); вообще, я бы сказал, что поскольку других платформ нет и долго не будет, дополнительный код можно ставить умолчанием.
  • Требование явной конверсии между числовыми типами — в плюс (когда оно таки требуется — по примеру выше, тут грубая недоработка).
  • Принудительность арифметики с заворотом (остаются младшие N бит) — в принципе тоже на пользу (особенно, например, по сравнению с такими
    Автор: Кодт
    Дата: 18.06.14
    ситуациями; хотя я бы категорически предпочёл более гибкое синтаксическое регулирование), но как минимум надо было в стандартную библиотеку добавить функции контроля (типа таких).
  • Мелочи, но вкусные, типа "битовые сдвиги не усекают ширину сдвига до ширины слова" (хотя тоже желательно бы видеть в библиотеке оптимизированные машинные операции, для которых обеспечить адекватную ширину — проблема программиста).
  • И вообще, группа ситуаций, где C говорит про undefined behavior или implementation defined, получили однозначное решение.

    С другой стороны, древности и глупости
  • Тупейшие правила "неиспользованная переменная, импорт => ошибка компиляции" (автогенерация пошла лесом)
  • Отказ от исключений и дженериков
  • Нормирование экспорта по регистру первого символа
  • Отсутствие private в классах
  • Синтаксические неровности типа "в import надо кавычки на пакет, а в package — нет"
  • Совсем тупые древности типа префикса 0 для восьмеричных констант
  • Ляпы в работе с каналами
  • Странная логика понятия "новый тип, такой же, как старый" (алиасы нельзя вводить; в Ada это решили явным new в type X is new Y) (UPD: в последних версиях добавили)
  • При компиляции — отказ от стандартных фреймворков и "закат солнца вручную" со своим кодогенератором и оптимизатором, заведомо более слабыми, чем майнстрим вроде LLVM (несмотря на то, что сишный код интерфейса к ОС никуда не девается).
  • Неизменяемая заточка GC на минимум задержек, хотя далеко не всем задачам это нужно.

    можно продолжать.

    Вместе с невменяемой "харизмой" авторов это приводит к тому, что всем критикам говорят "не нравится — чемодан, вокзал, Java" (или другой язык, подставить по вкусу), а в пользователях — к формированию клуба фанатиков вместо трезвых пользователей (например, на DOU два таких уже задолбали всех).
  • The God is real, unless declared integer.
    Отредактировано 14.07.2019 6:09 netch80 . Предыдущая версия . Еще …
    Отредактировано 17.05.2017 13:53 netch80 . Предыдущая версия .
    Re[2]: Арифметика констант в языке Go
    От: vsb Казахстан  
    Дата: 17.05.17 07:56
    Оценка: 10 (1) +1
    Здравствуйте, netch80, Вы писали:

    N>Неизменяемая заточка GC на минимум задержек, хотя далеко не всем задачам это нужно.


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

    Проблема Go (и некоторых других технологий вроде React) в том, что это огрызки от внутренней кухни корпораций, которые они выбрасывают в публику. Само по себе это круто, лучше иметь, чем не иметь, тем боле опен-сорс, но по факту имеем именно огрызки и кучу копошащейся мелкоты вокруг, которые пытаются из этих огрызков собрать что-то вменяемое. Если сравнить с Java или .NET, то тут всё наоборот, эти технологии само по себе ключевые и тот же MS хоть и использует .NET, но ничего не скрывает и релизит всё всем точно так же, как для себя, пользуется той же Visual Studio, которую раздаёт всем остальным и тд. Т.е. для MS продажа .NET это важная часть бизнеса, а для Google это просто внутренний инструмент который по определённым причинам открыли, но если вдруг решат закрыть, доходам Google это вообще никак не скажется. Соответственно надо или использовать эти технологии, в том случае, когда они хорошо подходят под твой случай (или ты настолько крут, что можешь их доработать), или просто использовать те технологии, создатели которых более ответственно подходят ко всему этому.

    А пока Go создаётся внутри гугла и главная цель его — обслуживать специфические интересы гугла, приоритет будет отдаваться тому, что важно для гугла. И если для гугла генерики не важны, их там не будет.
    Отредактировано 17.05.2017 7:56 vsb . Предыдущая версия .
    Re[2]: Арифметика констант в языке Go
    От: D. Mon Великобритания http://thedeemon.livejournal.com
    Дата: 18.05.17 05:02
    Оценка:
    Здравствуйте, netch80, Вы писали:

    N>
  • При компиляции — отказ от стандартных фреймворков и "закат солнца вручную" со своим кодогенератором и оптимизатором, заведомо более слабыми, чем майнстрим вроде LLVM

    У них одна из важнейших целей — скорость компиляции, ради нее готовы идти на дурацкую грамматику и отсуствие оптимизации. А LLVM тормозной как гад.
  • Re[3]: Арифметика констант в языке Go
    От: netch80 Украина http://netch80.dreamwidth.org/
    Дата: 18.05.17 06:12
    Оценка:
    Здравствуйте, vsb, Вы писали:

    N>>Неизменяемая заточка GC на минимум задержек, хотя далеко не всем задачам это нужно.


    vsb>А тут что не так? Ниша го это мелкие веб-сервисы, где важно отвечать быстро, при этом общая производительность менее важна, т.к. если сервер не справляется, его надо просто масштабировать.


    Если они целятся на паузы до 100 мкс, то это уже никак не веб-сервисы. Это уровень, который приближается к мелкому HFT.

    vsb> Понятно, что хорошо, если есть куча GC на все случаи жизни, как в Java, но это денег стоит, вообще-то. Или в самом языке есть какие-то решения, которые не дают делать другие GC?


    Вроде нет таких. Вообще, stop the world можно сделать с любым языком.

    vsb>Проблема Go (и некоторых других технологий вроде React) в том, что это огрызки от внутренней кухни корпораций, которые они выбрасывают в публику.


    Долго думал, чем возразить, но не нашёл. Будем считать справедливым.

    vsb>А пока Go создаётся внутри гугла и главная цель его — обслуживать специфические интересы гугла, приоритет будет отдаваться тому, что важно для гугла. И если для гугла генерики не важны, их там не будет.


    Похоже на то. Они и в C++ не разрешают исключения.
    The God is real, unless declared integer.
    Re[3]: Арифметика констант в языке Go
    От: netch80 Украина http://netch80.dreamwidth.org/
    Дата: 18.05.17 10:54
    Оценка:
    Здравствуйте, D. Mon, Вы писали:

    N>>* При компиляции — отказ от стандартных фреймворков и "закат солнца вручную" со своим кодогенератором и оптимизатором, заведомо более слабыми, чем майнстрим вроде LLVM


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


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

    DM> А LLVM тормозной как гад.


    На оптимизации, наверно. Парсеры вполне приемлемые по скорости, как для обычных задач такого языка.
    The God is real, unless declared integer.
    Re[4]: Арифметика констант в языке Go
    От: D. Mon Великобритания http://thedeemon.livejournal.com
    Дата: 18.05.17 15:38
    Оценка:
    Здравствуйте, netch80, Вы писали:

    N>С оптимизацией ещё кое-как согласен, но при чём тут грамматика?


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