Здравствуйте, netch80, Вы писали:
N>Ну вот навскидку уже видно, где нужно сделать послабление: правила для констант
Проще тип констант выводить из типов других операндов, или подразумеваемого результата выражения.
N>32 бита на всё? Хм, даже в 90е годы это было не так. Например, FreeBSD принципиально сделала off_t 64-битным ещё в 2.0 — это чтобы потом не иметь проблем с совместимостью.
Там, где использовались величины вроде байтового смещения на внешнем носителе, издавна 64-разрядные значения. А по уму, всяких "type_t" должно быть побольше. Например, тип размера строки или структуры разумно было бы сделать отдельным от типа размера произвольного блока памяти — сколько мы во всех программах мира насчитаем строк или структур размером больше 4 Гб?
N>А всякие Linux & Solaris протормозили с этим и имели неожиданные проблемы.
Если бы вместо этого ввели гибкую систему типов — возможно, и не имели бы проблем.
N>Я не вижу тут принципиальных проблем даже с x86 с его лёгким раздувательством.
Арифметико-логический код раздувается на 20-30%. Это уже, как бы, не совсем "легкое".
N>UdB даёт сильно больше возможностей для оптимизации. Там стараются этим пользоваться.
Пока это один и тот же UB. short = int + int полностью аналогично short = short (int + int). Вопрос лишь в том, чтобы первое не могло проскочить незаметно.
N>Вот почему при этом перекошенность, что unsigned работает по модулю, а signed не должно переполняться, и что это сохраняют до сих пор
Где сохраняют? Всю жизнь int работал по модулю, и переполнялся соответственно.
Re[10]: Есть ли практический смысл в неявном усечении значений?
Здравствуйте, _NN_, Вы писали:
N>>Я вижу пока только один вариант — вводить [[атрибутами]] контексты, где действуют новые правила. _NN>Есть вариант в стиле C#, ключевые слова checked, unchecked:
Я на него намекал в том числе. Но ключевые слова наверняка не дадут вводить, а вот пространство атрибутов — оно отдельное, конфликты минимальны, и там это сделать будет сильно проще.
The God is real, unless declared integer.
Re[3]: Есть ли практический смысл в неявном усечении значений?
Здравствуйте, _NN_, Вы писали:
_NN>Есть вариант в стиле C#, ключевые слова checked, unchecked:
Проверки к коду умеют добавлять и некоторые компиляторы C++. Проблема в том, что реальные усечения еще нужно выловить.
Ну и напомню, что самый геморрой вовсе не с проверками, а с количеством вариантов перегруженных/шаблонных функций, которые компилятор считает подходящими для конкретного набора параметров.
Re[9]: Есть ли практический смысл в неявном усечении значений?
Здравствуйте, Евгений Музыченко, Вы писали:
N>>Вот почему при этом перекошенность, что unsigned работает по модулю, а signed не должно переполняться, и что это сохраняют до сих пор ЕМ>Где сохраняют? Всю жизнь int работал по модулю, и переполнялся соответственно.
про переполнение, и пяток аналогичных. Хотя ты работаешь вроде только с MSVC, там могли это обойти как-то иначе.
N>>Ну вот навскидку уже видно, где нужно сделать послабление: правила для констант ЕМ>Проще тип констант выводить из типов других операндов, или подразумеваемого результата выражения.
Ну где-то так и делают во многих местах. Вначале они нетипизированные и безразмерные (или максимального размера), а потом компилятор смотрит, во что он может ту константу ужать.
N>>32 бита на всё? Хм, даже в 90е годы это было не так. Например, FreeBSD принципиально сделала off_t 64-битным ещё в 2.0 — это чтобы потом не иметь проблем с совместимостью.
ЕМ>Там, где использовались величины вроде байтового смещения на внешнем носителе, издавна 64-разрядные значения. А по уму, всяких "type_t" должно быть побольше. Например, тип размера строки или структуры разумно было бы сделать отдельным от типа размера произвольного блока памяти — сколько мы во всех программах мира насчитаем строк или структур размером больше 4 Гб?
Вот неготов я занимать тут какую-то конкретную позицию. Да, таких строк вряд ли будет, но ограничивать из-за этого, с учётом того, что всё равно расход памяти на саму строку, на структуру вокруг неё и т.д., регистры уже отведены... по-моему, тут как раз экономия копеечная, а неожиданные проблемы неприятны.
N>>А всякие Linux & Solaris протормозили с этим и имели неожиданные проблемы. ЕМ>Если бы вместо этого ввели гибкую систему типов — возможно, и не имели бы проблем.
Гибкую — это как? off_t как BigInteger?
N>>Я не вижу тут принципиальных проблем даже с x86 с его лёгким раздувательством. ЕМ>Арифметико-логический код раздувается на 20-30%. Это уже, как бы, не совсем "легкое".
Ты не понял. Код уже раздулся от широких констант, REX префиксов и так далее. Речь о выборе между тем, что long при переходе на 64 бита станет тоже 64, или не станет.
Кто и зачем будет заведомо использовать long для "арифметичеко-логического кода" там, где он идентичен int, но при этом не 64 бита?
N>>UdB даёт сильно больше возможностей для оптимизации. Там стараются этим пользоваться.
ЕМ>Пока это один и тот же UB. short = int + int полностью аналогично short = short (int + int). Вопрос лишь в том, чтобы первое не могло проскочить незаметно.
С тем, что не должно проходить незаметно — я как раз согласен.
The God is real, unless declared integer.
Re[10]: Есть ли практический смысл в неявном усечении значений?
Не читал — я редко интересуюсь подобными случаями, предпочитаю избегать таких конструкций.
ЕМ>>Если бы вместо этого ввели гибкую систему типов — возможно, и не имели бы проблем.
N>Гибкую — это как? off_t как BigInteger?
Разные типы для разных видов смещений. Смещение члена класса внутри объекта, или символа в строке — это таки несколько иное, чем смещение произвольного байта на произвольном носителе.
N>Код уже раздулся от широких констант, REX префиксов и так далее.
Это отдельно. Я говорю о раздувании кода в одной и той же 64-разрядной функции после замены 32-разрядной арифметики на 64-разрядныю.
N>Кто и зачем будет заведомо использовать long для "арифметичеко-логического кода" там, где он идентичен int, но при этом не 64 бита?
Ну, лично я бы использовал long там, где сейчас еще хватает int, но в будущем уже хватать перестанет. Там, где уже сейчас 32 разряда впритык, лучше сразу закладываться на 64. А еще лучше — вводить отдельный тип для таких значений.
Re[11]: Есть ли практический смысл в неявном усечении значений?
про переполнение, и пяток аналогичных. ЕМ>Не читал — я редко интересуюсь подобными случаями, предпочитаю избегать таких конструкций.
Ты-то их можешь избегать сколько угодно. Главное, чтобы они избегали тебя
А с нынешними тенденциями долго сидеть в уютном мирке MSVC, боюсь, не очень получится.
ЕМ>>>Если бы вместо этого ввели гибкую систему типов — возможно, и не имели бы проблем. N>>Гибкую — это как? off_t как BigInteger? ЕМ>Разные типы для разных видов смещений. Смещение члена класса внутри объекта, или символа в строке — это таки несколько иное, чем смещение произвольного байта на произвольном носителе.
Понятно. Но я думаю, что аргументы вроде тех, что я приводил, стали причиной того, что это не стали делать.
Да, есть заморочки типа того, что почти все нынешние 64-разрядные платформы не смогут нормально работать при объёме кода больше 2GB. Да, типичное смещение элемента структуры влазит даже не в 32 бита, а в 12, чем пользуется половина RISCʼов. Но всё равно делать из-за этого 1000 разных размеров — смысла не увидели, и я понимаю, почему.
Если где-то он вдруг есть (сложно представить себе такой контекст), там можно и специализированную версию построить.
N>>Код уже раздулся от широких констант, REX префиксов и так далее. ЕМ>Это отдельно. Я говорю о раздувании кода в одной и той же 64-разрядной функции после замены 32-разрядной арифметики на 64-разрядныю.
А зачем её там так менять, если в 32 всё работает?
N>>Кто и зачем будет заведомо использовать long для "арифметичеко-логического кода" там, где он идентичен int, но при этом не 64 бита? ЕМ>Ну, лично я бы использовал long там, где сейчас еще хватает int, но в будущем уже хватать перестанет. Там, где уже сейчас 32 разряда впритык, лучше сразу закладываться на 64.
Ну вот именно потому, если 64 желательно, лучше, чтобы long стал 64
EM> А еще лучше — вводить отдельный тип для таких значений.
Тут другая тема. Вводить тип ты можешь сколько угодно, а как ты опознаешь приближение к моменту переполнения или само переполнение, если оно происходит?
Это то, почему я сейчас считаю, что в любом языке, который может быть применён где-то за пределами сверхслабого embedded, допустимым (а в debug и основным по умолчанию) должен быть режим проверки всех операций и генерации ошибки, если что не так. А в небольшом количестве узких мест можно и отменять эти проверки.
The God is real, unless declared integer.
Re[4]: Есть ли практический смысл в неявном усечении значений?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, _NN_, Вы писали:
_NN>>Есть вариант в стиле C#, ключевые слова checked, unchecked:
ЕМ>Проверки к коду умеют добавлять и некоторые компиляторы C++. Проблема в том, что реальные усечения еще нужно выловить.
ЕМ>Ну и напомню, что самый геморрой вовсе не с проверками, а с количеством вариантов перегруженных/шаблонных функций, которые компилятор считает подходящими для конкретного набора параметров.
При чём здесь перегрузки ?
Для каждого выражения просто задаём желаемое поведение.
А в случае переполнения скажем вызывать std::integer_overflow, который можно переопределить как хотим.
К примеру C#:
using static System.Console;
public class Program
{
static int f() { unchecked { return int.MaxValue + 10; } } // делаем что хотимpublic static void Main()
{
int x = checked ( f()*int.MaxValue ); // проверяем и кидаем исключение
WriteLine(x);
}
}
Здравствуйте, _NN_, Вы писали:
_NN>При чём здесь перегрузки ? _NN>Для каждого выражения просто задаём желаемое поведение. _NN>А в случае переполнения скажем вызывать std::integer_overflow, который можно переопределить как хотим. _NN>К примеру C#:
В этом варианте тоже есть проблемы. Знак + для невстроенных типов превращается в op_Add, так?
Но она одна для checked и unchecked контекста. А почему? Получается, для таких типов надо указывать режим в общих свойствах типов, или в типах операций? Неаккуратненько
Уточню: я категорически "за" разделение checked/unchecked; это уже колоссальный прогресс даже в варианте, как сейчас.
Но и тут есть куда двигаться дальше.
Здравствуйте, netch80, Вы писали:
ЕМ>>говорю о раздувании кода в одной и той же 64-разрядной функции после замены 32-разрядной арифметики на 64-разрядныю.
N>А зачем её там так менять, если в 32 всё работает?
Я уже объяснял — надоели преобразования из size_t в UINT и обратно, и одновременно показалось, что 64-разрядные значения будут обрабатываться эффективнее. Обнаружил подвох лишь через некоторое время после того, как все поменял.
N>Это то, почему я сейчас считаю, что в любом языке, который может быть применён где-то за пределами сверхслабого embedded, допустимым (а в debug и основным по умолчанию) должен быть режим проверки всех операций и генерации ошибки, если что не так. А в небольшом количестве узких мест можно и отменять эти проверки.
Согласен. Но при этом хочется возможности и ограничить вольности компилятора, чтобы не вылавливать такие ошибки тестами вместо исправления на ранних этапах.
Re[5]: Есть ли практический смысл в неявном усечении значений?
Здравствуйте, Евгений Музыченко, Вы писали:
_NN>>Для каждого выражения просто задаём желаемое поведение.
ЕМ>Это для run-time. Я говорю прежде всего о compile-time.
Т.е. вам нужны зависимые типы ?
Этого боюсь точно не добавят.
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, _NN_, Вы писали:
_NN>>При чём здесь перегрузки ? _NN>>Для каждого выражения просто задаём желаемое поведение. _NN>>А в случае переполнения скажем вызывать std::integer_overflow, который можно переопределить как хотим. _NN>>К примеру C#:
N>В этом варианте тоже есть проблемы. Знак + для невстроенных типов превращается в op_Add, так? N>Но она одна для checked и unchecked контекста. А почему? Получается, для таких типов надо указывать режим в общих свойствах типов, или в типах операций? Неаккуратненько
Почему это будут две перегрузки ?
Есть только одна.
Что внутри там делает это дело функции.
Хочет будет внутри checked, хочет нет.
Здравствуйте, _NN_, Вы писали:
_NN>Почему это будут две перегрузки ? _NN>Есть только одна. _NN>Что внутри там делает это дело функции. _NN>Хочет будет внутри checked, хочет нет.
И как оно внутри узнает про выбранный режим (checked/unchecked)? Он в C# синтаксический, а не где-то в опциях текущей нитки или аналогичном месте.
Вот см. таблицу — в unchecked сгенерируется add, а в checked — add.ovf или add.ovf.un. Но это делает сам компилятор, у него под это специальные заточки есть.
Как чужой функции узнать этот контекст?
The God is real, unless declared integer.
Re[7]: Есть ли практический смысл в неявном усечении значений?
Здравствуйте, _NN_, Вы писали:
_NN>Т.е. вам нужны зависимые типы ?
Не. Мне нужно, чтобы в ситуации, когда есть версии перегруженной функции для наборов параметров, скажем, (int, int) и (long, long), и есть вызов с фактическими параметрами (int, long), компилятор не изображал философа, утверждая, что он в равной степени мог бы применить и то, и другое.
Re[8]: Есть ли практический смысл в неявном усечении значени
Здравствуйте, netch80, Вы писали:
N>И как оно внутри узнает про выбранный режим (checked/unchecked)? Он в C# синтаксический, а не где-то в опциях текущей нитки или аналогичном месте. N>Вот см. таблицу — в unchecked сгенерируется add, а в checked — add.ovf или add.ovf.un. Но это делает сам компилятор, у него под это специальные заточки есть. N>Как чужой функции узнать этот контекст?
Узнает где ?
checked/unchecked не идёт дальше функции:
В настройками по умолчанию (unchecked) этот код выводит -4
using static System.Console;
public class Program
{
static int Q()
{
int i = int.MaxValue;
int j = 2;
return i * j;
}
static int F()
{
return Q() * 2;
}
public static void Main()
{
checked
{
int i = F();
WriteLine(i);
}
}
}
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, _NN_, Вы писали:
_NN>>Т.е. вам нужны зависимые типы ?
ЕМ>Не. Мне нужно, чтобы в ситуации, когда есть версии перегруженной функции для наборов параметров, скажем, (int, int) и (long, long), и есть вызов с фактическими параметрами (int, long), компилятор не изображал философа, утверждая, что он в равной степени мог бы применить и то, и другое.
Т.е. просто запретить преобразование long => int ?
В C# примерно так и есть: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/implicit-numeric-conversions-table
_NN>>В C# примерно так и есть:
ЕМ>Очень рад, но мне-то нужно в C++.
Тут варианта два.
Один протолкнуть в стандарт, там через https://stdcpp.ru/ или ещё как-нибудь.
Второй в компилятор добавить опцию ловить такое поведение.
Если ещё такого нет, то можно предложить.