Сообщение Re[23]: Carbon от 19.04.2024 9:07
Изменено 19.04.2024 9:08 vdimas
Re[23]: Carbon
Здравствуйте, Sinclair, Вы писали:
S>Ну, например, поставили фейспалм на простое утверждение "UB, из которого язык состоит чуть менее, чем полностью".
S>Вот я вижу, что интовая арифметика используется примерно в каждой первой программе.
По моему опыту, в плюсах беззнаковые используются часто, почти всегда чаще знаковых.
Знаковые целые нужны редко, в основном для оперирования сущностями, близкому по смыслу к "разница", "текущий остаток", или для традиционного возврата кодов или признаков ошибок.
У меня обсуждаемая проблема вечно вылазит в дотнете, бо системное АПИ расписано на знаковых, даже где это выглядит абсурдом.
Причина известна — не во всех языках есть беззнаковый тип, поэтому платформа затачивалась на слабое звено. ))
В итоге, у меня полно кода, дублирующего базовую библиотеку (не просто дублирующего, конечно, многие вещи сделаны легковеснее), но с активным использованием беззнаковых, что резко упрощает целевой прикладной код, расписаный по большей части в беззнаковых.
S>То есть если покрасить исходный код более-менее любого проекта в красный там, где "возможно UB", то его будет больше, чем не красного.
Переполнения принято производить с беззнаковыми, а со знаковыми принято оперировать так, чтобы переполнения не возникало.
В любом случае, реинтерпретация беззнакового как знакового допустима, а вот обратная реинтерпретация — это UB.
CC>>Если ударяться в странные конструкции и потом бороться со странностями compile time вычислений — то гемора будет побольше.
S>Что вы называете "странными конструкциями"? Мы кагбэ просто взяли сложение и сравнение — чо уж тут странного-то?
Что код примера не обязательно выполняется в реальном железе, а порой только на этапе компиляции.
S>Compile-time вычисления сами по себе штука хорошая, поскольку позволяют сильно улучшить перформанс программ без потери общности. Те самые zero-cost abstractions, ради которых люди и выбирают C++ вместо менее упоротых языков.
CC>>Если придерживаться KISS и писать просто и строго по делу, не растекаясь шаблонами по шаблонам — таких проблем не будет.
S>Ооо, мне нравится ваш задор. Давайте попробуем починить UB в функции, написанной просто и строго по делу, безо всяких шаблонов:
S>
Хороший пример, кстате.
Что в дотнете, что в плюсах такими вещами упражняюсь путём приведения к более широкому типу, поэтому int64 пролетает.
И это известная практика именно с давних времён.
Еще оттуда же практика замены вычисления с плавающей точкой на работу с рациональными дробями (умножение с делением), где для корректной работы аналогично исходные числа сначала расширяются для промежуточных вычислений, потом сужаются.
Да и в железе тоже порой обитают инструкции двойного по ширине результата после умножения и деления удвоенной ширины делимого на делитель шириной в слово.
S>А перенос вычислений в рантайм заставил сработать оптимизацию, которая воспользовалась UB в полном соответствии со стандартом языка.
Наверно, наоборот, compile-time вычисления произошли из предположения, что никакого UB не возникает, и тогда результат всегда false.
Кстате, мне Решарпер в C# иногда подсвечивает "тут у вас всегда true" (или всегда false), т.е. намекает на мёртвые ветки кода, хотя не факт.
Спасает то, что компилятор C# и JIT пока мест не делают суровых оптимизаций.
(можно сказать, что компилятор C# не делает никаких оптимизаций от слова вообще, кроме совсем скромных манипуляций локальными переменными)
Когда в дотнете, наконец, случится обещанная тобой еще 20 лет назад суровая оптимизация — напорешься на аналогичные эффекты. ))
CC>>Это архитектурный баг компиляторостроителей, который можно починить но никто не станет, ибо пуристы упрутся рогом.
S>Это интересная гипотеза, но она не подтверждается практикой.
Есть такое.
С++ — это, в первую очередь, инструмент для порождения произвольных по сложности матрёшек абстракций с нулевым пенальти.
Пресловутая "упорость" любителей плюсов сидит только в этом и ни в чём больше, а иначе покажите другой инструмент с тем же свойством, но в чём-то более удобный — и все туда быстренько убегут.
А так-то, забесплатно можно расписать, к примеру, корректное сравнение знакового с беззнаковым:
(можно в более общем коде для любых интегральных, не хотел просто засорять исходник, показал суть)
Еще популярный сценарий — индексы беззнаковые, а разница индексов знаковая, расписываются операции сложения беззнаковых индексов со знаковой разницей с контролем переполнения.
S>Ну, например, поставили фейспалм на простое утверждение "UB, из которого язык состоит чуть менее, чем полностью".
S>Вот я вижу, что интовая арифметика используется примерно в каждой первой программе.
По моему опыту, в плюсах беззнаковые используются часто, почти всегда чаще знаковых.
Знаковые целые нужны редко, в основном для оперирования сущностями, близкому по смыслу к "разница", "текущий остаток", или для традиционного возврата кодов или признаков ошибок.
У меня обсуждаемая проблема вечно вылазит в дотнете, бо системное АПИ расписано на знаковых, даже где это выглядит абсурдом.
Причина известна — не во всех языках есть беззнаковый тип, поэтому платформа затачивалась на слабое звено. ))
В итоге, у меня полно кода, дублирующего базовую библиотеку (не просто дублирующего, конечно, многие вещи сделаны легковеснее), но с активным использованием беззнаковых, что резко упрощает целевой прикладной код, расписаный по большей части в беззнаковых.
S>То есть если покрасить исходный код более-менее любого проекта в красный там, где "возможно UB", то его будет больше, чем не красного.
Переполнения принято производить с беззнаковыми, а со знаковыми принято оперировать так, чтобы переполнения не возникало.
В любом случае, реинтерпретация беззнакового как знакового допустима, а вот обратная реинтерпретация — это UB.
CC>>Если ударяться в странные конструкции и потом бороться со странностями compile time вычислений — то гемора будет побольше.
S>Что вы называете "странными конструкциями"? Мы кагбэ просто взяли сложение и сравнение — чо уж тут странного-то?
Что код примера не обязательно выполняется в реальном железе, а порой только на этапе компиляции.
S>Compile-time вычисления сами по себе штука хорошая, поскольку позволяют сильно улучшить перформанс программ без потери общности. Те самые zero-cost abstractions, ради которых люди и выбирают C++ вместо менее упоротых языков.
CC>>Если придерживаться KISS и писать просто и строго по делу, не растекаясь шаблонами по шаблонам — таких проблем не будет.
S>Ооо, мне нравится ваш задор. Давайте попробуем починить UB в функции, написанной просто и строго по делу, безо всяких шаблонов:
S>
S>long avg(long a, long b, long c)
S>{
S> return (a+b+c)/3;
S>}
S>
Хороший пример, кстате.
Что в дотнете, что в плюсах такими вещами упражняюсь путём приведения к более широкому типу, поэтому int64 пролетает.
И это известная практика именно с давних времён.
Еще оттуда же практика замены вычисления с плавающей точкой на работу с рациональными дробями (умножение с делением), где для корректной работы аналогично исходные числа сначала расширяются для промежуточных вычислений, потом сужаются.
Да и в железе тоже порой обитают инструкции двойного по ширине результата после умножения и деления удвоенной ширины делимого на делитель шириной в слово.
S>А перенос вычислений в рантайм заставил сработать оптимизацию, которая воспользовалась UB в полном соответствии со стандартом языка.
Наверно, наоборот, compile-time вычисления произошли из предположения, что никакого UB не возникает, и тогда результат всегда false.
Кстате, мне Решарпер в C# иногда подсвечивает "тут у вас всегда true" (или всегда false), т.е. намекает на мёртвые ветки кода, хотя не факт.
Спасает то, что компилятор C# и JIT пока мест не делают суровых оптимизаций.
(можно сказать, что компилятор C# не делает никаких оптимизаций от слова вообще, кроме совсем скромных манипуляций локальными переменными)
Когда в дотнете, наконец, случится обещанная тобой еще 20 лет назад суровая оптимизация — напорешься на аналогичные эффекты. ))
CC>>Это архитектурный баг компиляторостроителей, который можно починить но никто не станет, ибо пуристы упрутся рогом.
S>Это интересная гипотеза, но она не подтверждается практикой.
Есть такое.
С++ — это, в первую очередь, инструмент для порождения произвольных по сложности матрёшек абстракций с нулевым пенальти.
Пресловутая "упорость" любителей плюсов сидит только в этом и ни в чём больше, а иначе покажите другой инструмент с тем же свойством, но в чём-то более удобный — и все туда быстренько убегут.
А так-то, забесплатно можно расписать, к примеру, корректное сравнение знакового с беззнаковым:
#include <iostream>
enum int_t : int;
enum uint_t : unsigned int;
bool operator<(int_t a, uint_t b) {
using uint = unsigned int;
return int(a) < 0 || uint(a) < b;
}
int main()
{
auto result = int_t(-42) < uint_t(42);
std::cout << result << std::endl;
return 0;
}
(можно в более общем коде для любых интегральных, не хотел просто засорять исходник, показал суть)
Еще популярный сценарий — индексы беззнаковые, а разница индексов знаковая, расписываются операции сложения беззнаковых индексов со знаковой разницей с контролем переполнения.
Re[23]: Carbon
Здравствуйте, Sinclair, Вы писали:
S>Ну, например, поставили фейспалм на простое утверждение "UB, из которого язык состоит чуть менее, чем полностью".
S>Вот я вижу, что интовая арифметика используется примерно в каждой первой программе.
По моему опыту, в плюсах беззнаковые используются часто, почти всегда чаще знаковых.
Знаковые целые нужны редко, в основном для оперирования сущностями, близкому по смыслу к "разница", "текущий остаток/баланс", или для традиционного возврата кодов или признаков ошибок.
У меня обсуждаемая проблема вечно вылазит в дотнете, бо системное АПИ расписано на знаковых, даже где это выглядит абсурдом.
Причина известна — не во всех языках есть беззнаковый тип, поэтому платформа затачивалась на слабое звено. ))
В итоге, у меня полно кода, дублирующего базовую библиотеку (не просто дублирующего, конечно, многие вещи сделаны легковеснее), но с активным использованием беззнаковых, что резко упрощает целевой прикладной код, расписаный по большей части в беззнаковых.
S>То есть если покрасить исходный код более-менее любого проекта в красный там, где "возможно UB", то его будет больше, чем не красного.
Переполнения принято производить с беззнаковыми, а со знаковыми принято оперировать так, чтобы переполнения не возникало.
В любом случае, реинтерпретация беззнакового как знакового допустима, а вот обратная реинтерпретация — это UB.
CC>>Если ударяться в странные конструкции и потом бороться со странностями compile time вычислений — то гемора будет побольше.
S>Что вы называете "странными конструкциями"? Мы кагбэ просто взяли сложение и сравнение — чо уж тут странного-то?
Что код примера не обязательно выполняется в реальном железе, а порой только на этапе компиляции.
S>Compile-time вычисления сами по себе штука хорошая, поскольку позволяют сильно улучшить перформанс программ без потери общности. Те самые zero-cost abstractions, ради которых люди и выбирают C++ вместо менее упоротых языков.
CC>>Если придерживаться KISS и писать просто и строго по делу, не растекаясь шаблонами по шаблонам — таких проблем не будет.
S>Ооо, мне нравится ваш задор. Давайте попробуем починить UB в функции, написанной просто и строго по делу, безо всяких шаблонов:
S>
Хороший пример, кстате.
Что в дотнете, что в плюсах такими вещами упражняюсь путём приведения к более широкому типу, поэтому int64 пролетает.
И это известная практика именно с давних времён.
Еще оттуда же практика замены вычисления с плавающей точкой на работу с рациональными дробями (умножение с делением), где для корректной работы аналогично исходные числа сначала расширяются для промежуточных вычислений, потом сужаются.
Да и в железе тоже порой обитают инструкции двойного по ширине результата после умножения и деления удвоенной ширины делимого на делитель шириной в слово.
S>А перенос вычислений в рантайм заставил сработать оптимизацию, которая воспользовалась UB в полном соответствии со стандартом языка.
Наверно, наоборот, compile-time вычисления произошли из предположения, что никакого UB не возникает, и тогда результат всегда false.
Кстате, мне Решарпер в C# иногда подсвечивает "тут у вас всегда true" (или всегда false), т.е. намекает на мёртвые ветки кода, хотя не факт.
Спасает то, что компилятор C# и JIT пока мест не делают суровых оптимизаций.
(можно сказать, что компилятор C# не делает никаких оптимизаций от слова вообще, кроме совсем скромных манипуляций локальными переменными)
Когда в дотнете, наконец, случится обещанная тобой еще 20 лет назад суровая оптимизация — напорешься на аналогичные эффекты. ))
CC>>Это архитектурный баг компиляторостроителей, который можно починить но никто не станет, ибо пуристы упрутся рогом.
S>Это интересная гипотеза, но она не подтверждается практикой.
Есть такое.
С++ — это, в первую очередь, инструмент для порождения произвольных по сложности матрёшек абстракций с нулевым пенальти.
Пресловутая "упорость" любителей плюсов сидит только в этом и ни в чём больше, а иначе покажите другой инструмент с тем же свойством, но в чём-то более удобный — и все туда быстренько убегут.
А так-то, забесплатно можно расписать, к примеру, корректное сравнение знакового с беззнаковым:
(можно в более общем коде для любых интегральных, не хотел просто засорять исходник, показал суть)
Еще популярный сценарий — индексы беззнаковые, а разница индексов знаковая, расписываются операции сложения беззнаковых индексов со знаковой разницей с контролем переполнения.
S>Ну, например, поставили фейспалм на простое утверждение "UB, из которого язык состоит чуть менее, чем полностью".
S>Вот я вижу, что интовая арифметика используется примерно в каждой первой программе.
По моему опыту, в плюсах беззнаковые используются часто, почти всегда чаще знаковых.
Знаковые целые нужны редко, в основном для оперирования сущностями, близкому по смыслу к "разница", "текущий остаток/баланс", или для традиционного возврата кодов или признаков ошибок.
У меня обсуждаемая проблема вечно вылазит в дотнете, бо системное АПИ расписано на знаковых, даже где это выглядит абсурдом.
Причина известна — не во всех языках есть беззнаковый тип, поэтому платформа затачивалась на слабое звено. ))
В итоге, у меня полно кода, дублирующего базовую библиотеку (не просто дублирующего, конечно, многие вещи сделаны легковеснее), но с активным использованием беззнаковых, что резко упрощает целевой прикладной код, расписаный по большей части в беззнаковых.
S>То есть если покрасить исходный код более-менее любого проекта в красный там, где "возможно UB", то его будет больше, чем не красного.
Переполнения принято производить с беззнаковыми, а со знаковыми принято оперировать так, чтобы переполнения не возникало.
В любом случае, реинтерпретация беззнакового как знакового допустима, а вот обратная реинтерпретация — это UB.
CC>>Если ударяться в странные конструкции и потом бороться со странностями compile time вычислений — то гемора будет побольше.
S>Что вы называете "странными конструкциями"? Мы кагбэ просто взяли сложение и сравнение — чо уж тут странного-то?
Что код примера не обязательно выполняется в реальном железе, а порой только на этапе компиляции.
S>Compile-time вычисления сами по себе штука хорошая, поскольку позволяют сильно улучшить перформанс программ без потери общности. Те самые zero-cost abstractions, ради которых люди и выбирают C++ вместо менее упоротых языков.
CC>>Если придерживаться KISS и писать просто и строго по делу, не растекаясь шаблонами по шаблонам — таких проблем не будет.
S>Ооо, мне нравится ваш задор. Давайте попробуем починить UB в функции, написанной просто и строго по делу, безо всяких шаблонов:
S>
S>long avg(long a, long b, long c)
S>{
S> return (a+b+c)/3;
S>}
S>
Хороший пример, кстате.
Что в дотнете, что в плюсах такими вещами упражняюсь путём приведения к более широкому типу, поэтому int64 пролетает.
И это известная практика именно с давних времён.
Еще оттуда же практика замены вычисления с плавающей точкой на работу с рациональными дробями (умножение с делением), где для корректной работы аналогично исходные числа сначала расширяются для промежуточных вычислений, потом сужаются.
Да и в железе тоже порой обитают инструкции двойного по ширине результата после умножения и деления удвоенной ширины делимого на делитель шириной в слово.
S>А перенос вычислений в рантайм заставил сработать оптимизацию, которая воспользовалась UB в полном соответствии со стандартом языка.
Наверно, наоборот, compile-time вычисления произошли из предположения, что никакого UB не возникает, и тогда результат всегда false.
Кстате, мне Решарпер в C# иногда подсвечивает "тут у вас всегда true" (или всегда false), т.е. намекает на мёртвые ветки кода, хотя не факт.
Спасает то, что компилятор C# и JIT пока мест не делают суровых оптимизаций.
(можно сказать, что компилятор C# не делает никаких оптимизаций от слова вообще, кроме совсем скромных манипуляций локальными переменными)
Когда в дотнете, наконец, случится обещанная тобой еще 20 лет назад суровая оптимизация — напорешься на аналогичные эффекты. ))
CC>>Это архитектурный баг компиляторостроителей, который можно починить но никто не станет, ибо пуристы упрутся рогом.
S>Это интересная гипотеза, но она не подтверждается практикой.
Есть такое.
С++ — это, в первую очередь, инструмент для порождения произвольных по сложности матрёшек абстракций с нулевым пенальти.
Пресловутая "упорость" любителей плюсов сидит только в этом и ни в чём больше, а иначе покажите другой инструмент с тем же свойством, но в чём-то более удобный — и все туда быстренько убегут.
А так-то, забесплатно можно расписать, к примеру, корректное сравнение знакового с беззнаковым:
#include <iostream>
enum int_t : int;
enum uint_t : unsigned int;
bool operator<(int_t a, uint_t b) {
using uint = unsigned int;
return int(a) < 0 || uint(a) < b;
}
int main()
{
auto result = int_t(-42) < uint_t(42);
std::cout << result << std::endl;
return 0;
}
(можно в более общем коде для любых интегральных, не хотел просто засорять исходник, показал суть)
Еще популярный сценарий — индексы беззнаковые, а разница индексов знаковая, расписываются операции сложения беззнаковых индексов со знаковой разницей с контролем переполнения.