Здравствуйте, samius, Вы писали:
PO>>В чем прелесть bool — в том что он гарантированно может хранить лишь два значения, отчего код по анализу параметра будет проще: S>нет такой гарантии
Это неопределённое поведение, ничем не лучше любого другого забега по памяти. При чём здесь bool?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, samius, Вы писали:
PO>>>В чем прелесть bool — в том что он гарантированно может хранить лишь два значения, отчего код по анализу параметра будет проще: S>>нет такой гарантии
К>Это неопределённое поведение, ничем не лучше любого другого забега по памяти. При чём здесь bool?
Я прикополся к выделенному в контексте сравнения bool с enum. Разница между ними лишь в том, что в bool сложнее засунуть что-то левое, но как и enum он может хранить левые значения.
Здравствуйте, samius, Вы писали:
К>>Это неопределённое поведение, ничем не лучше любого другого забега по памяти. При чём здесь bool? S>Я прикополся к выделенному в контексте сравнения bool с enum. Разница между ними лишь в том, что в bool сложнее засунуть что-то левое, но как и enum он может хранить левые значения.
Всё-таки разница здесь не количественная (проще-сложнее), а качественная. Формально, с точки зрения языка, bool не может содержать других значений.
4.1.8 The bool type
The bool type represents boolean logical quantities. The possible values of type bool are true and false.
4.1.9 Enumeration types
An enumeration type is a distinct type with named constants. Every enumeration type has an underlying type, which must be byte, sbyte, short, ushort, int, uint, long or ulong. The set of values of the enumeration type is the same as the set of values of the underlying type.
Но код, имеющий соответствующие привилегии, может наружить этот инвариант среды выполнения. Это же можно сделать, если залезть в процессор с паяльником.
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, samius, Вы писали:
S>>Я прикополся к выделенному в контексте сравнения bool с enum. Разница между ними лишь в том, что в bool сложнее засунуть что-то левое, но как и enum он может хранить левые значения.
N>Всё-таки разница здесь не количественная (проще-сложнее), а качественная. Формально, с точки зрения языка, bool не может содержать других значений.
Да, формально с точки зрения языка не может, но рассчитывать можно только на то что там либо false, либо все остальное, что интерпретируется как true, но может им и не являться. Т.к. платформа таки допускает другие значения.
Согласен, что разница качественная.
N>Но код, имеющий соответствующие привилегии, может наружить этот инвариант среды выполнения. Это же можно сделать, если залезть в процессор с паяльником.
А для такого кода нужны привилегии?
[StructLayout(LayoutKind.Explicit)]
struct BOOL
{
[FieldOffset(0)] public byte Byte;
[FieldOffset(0)] public bool Bool;
}
static void Main()
{
BOOL b = new BOOL {Byte = 3};
switch (b.Bool)
{
case false:
case true:
break;
default:
Console.WriteLine("Упс");
break;
}
}
Даже если нужны привилегии, то кривой bool мы можем получить как параметр, или в качестве результата другого метода.
Я не призываю проверять значения bool на допустимость, только лишь хотел уточнить, что нет гарантии того что там одно из двух значений.
Здравствуйте, samius, Вы писали:
N>>Всё-таки разница здесь не количественная (проще-сложнее), а качественная. Формально, с точки зрения языка, bool не может содержать других значений. S>Да, формально с точки зрения языка не может, но рассчитывать можно только на то что там либо false, либо все остальное, что интерпретируется как true, но может им и не являться. Т.к. платформа таки допускает другие значения. S>Согласен, что разница качественная.
Рассчитывать здесь можно на то, что там находится false, true и мусорные значения, интерпретируемые как попало в зависимости от настроения компилятора.
А настроение у оптимизирующего компилятора может быть очень весёлое.
В случае с энумом — использовать произвольные значения в пределах underlying type легально, это прописано в стандартах языков (C, C++, C#) и является распространённой практикой.
S>Я не призываю проверять значения bool на допустимость, только лишь хотел уточнить, что нет гарантии того что там одно из двух значений.
После забега по памяти вообще все гарантии кончились.
Для целочисленных типов нет априори-мусорных значений. Мусорность определяется уже программистом по месту использования. Ну там ожидаемая делимость, вхождение в диапазон, и т.д.
А вот для вещественных типов, ЕМНИП, можно сделать априори-мусорное значение (элементарно: денормализовать мантиссу). Дальше уже вопрос устойчивости психики у FPU — метнёт оно исключение или просто вычислит какую-нибудь ерунду.
Но это всё разновидности неопределённого поведения — одно повыше уровнем, другое пониже.
Работа с bool — на самом нижнем уровне, просто хотя бы потому, что логика — это первая вещь, которую пытаются оптимизировать.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, samius, Вы писали:
N>>>Всё-таки разница здесь не количественная (проще-сложнее), а качественная. Формально, с точки зрения языка, bool не может содержать других значений. S>>Да, формально с точки зрения языка не может, но рассчитывать можно только на то что там либо false, либо все остальное, что интерпретируется как true, но может им и не являться. Т.к. платформа таки допускает другие значения.
К>Рассчитывать здесь можно на то, что там находится false, true и мусорные значения, интерпретируемые как попало в зависимости от настроения компилятора.
Да, так будет правильнее. К>А настроение у оптимизирующего компилятора может быть очень весёлое.
К>В случае с энумом — использовать произвольные значения в пределах underlying type легально, это прописано в стандартах языков (C, C++, C#) и является распространённой практикой.
Легально все что не запрещено. Засовывать мусор в bool не запрещено, но и не является распространенной практикой. Естественно, засовывающие мусор в bool либо знают чего конкретно добиваются, либо ССЗБ.
S>>Я не призываю проверять значения bool на допустимость, только лишь хотел уточнить, что нет гарантии того что там одно из двух значений.
К>После забега по памяти вообще все гарантии кончились.
Дык и без забега почти, можно сказать. Радует то, что нельзя выравнять поля со ссылками. Но это уже не компилятор запрещает, а рантайм не хочет грузить сборку.
К>Для целочисленных типов нет априори-мусорных значений. Мусорность определяется уже программистом по месту использования. Ну там ожидаемая делимость, вхождение в диапазон, и т.д.
Да, bool таки представлен целочисленным ведь типом? К>А вот для вещественных типов, ЕМНИП, можно сделать априори-мусорное значение (элементарно: денормализовать мантиссу). Дальше уже вопрос устойчивости психики у FPU — метнёт оно исключение или просто вычислит какую-нибудь ерунду. К>Но это всё разновидности неопределённого поведения — одно повыше уровнем, другое пониже.
К>Работа с bool — на самом нижнем уровне, просто хотя бы потому, что логика — это первая вещь, которую пытаются оптимизировать.
UB так UB.
Но я не понимаю, чем так плох плюсовый подход к bool-у, когда легально есть FALSE, TRUE и все остальное? Зачем надо было объявлять в языке что может быть только 2 значения? Без каких либо изменений в коде, нужно было бы всего лишь специфицировать поведение компилятора при остальных значениях и ткнуть носом в корректную нормализацию bool-а для тех сценариев, где это важно (например, b = (b == true); — плохо, а b = (b != false); — хорошо)
S>Но я не понимаю, чем так плох плюсовый подход к bool-у, когда легально есть FALSE, TRUE и все остальное? Зачем надо было объявлять в языке что может быть только 2 значения? Без каких либо изменений в коде, нужно было бы всего лишь специфицировать поведение компилятора при остальных значениях и ткнуть носом в корректную нормализацию bool-а для тех сценариев, где это важно (например, b = (b == true); — плохо, а b = (b != false); — хорошо)
Это как раз не плюсовый подход. плюсовый -- это true или false + я хотел бы ключик компилятора который кидает исключение на других значениях.
иначе что мы должны делать здесь:
bool xor2( bool a, bool b )
{
return a != b;
}
если разрешить "все остальное"? и главное -- _зачем_?
в чем выигрыш от "всего остального"? встретив
bool f = 5;
компилятор сам засунет именно true.
Реально в bool может оказаться мусор либо в виде неинициализированной переменной, либо явного затирания через приведение указателя / потоптанной памяти.
Здравствуйте, samius, Вы писали:
К>>Для целочисленных типов нет априори-мусорных значений. Мусорность определяется уже программистом по месту использования. Ну там ожидаемая делимость, вхождение в диапазон, и т.д. S>Да, bool таки представлен целочисленным ведь типом?
Нет, bool — это самостоятельный тип, в числе других целочисленных типов.
S>Но я не понимаю, чем так плох плюсовый подход к bool-у, когда легально есть FALSE, TRUE и все остальное? Зачем надо было объявлять в языке что может быть только 2 значения? Без каких либо изменений в коде, нужно было бы всего лишь специфицировать поведение компилятора при остальных значениях и ткнуть носом в корректную нормализацию bool-а для тех сценариев, где это важно (например, b = (b == true); — плохо, а b = (b != false); — хорошо)
Если мы говорим о С++, то легально есть только true и false, нету никакого "всего остального":
Values of type bool are either true or false.42)
42) Using a bool value in ways described by this International Standard as ‘‘undefined,’’ such as by examining the value of an uninitialized automatic variable, might cause it to behave as if it is neither true nor false.
Здравствуйте, K13, Вы писали:
S>>Но я не понимаю, чем так плох плюсовый подход к bool-у, когда легально есть FALSE, TRUE и все остальное? Зачем надо было объявлять в языке что может быть только 2 значения? Без каких либо изменений в коде, нужно было бы всего лишь специфицировать поведение компилятора при остальных значениях и ткнуть носом в корректную нормализацию bool-а для тех сценариев, где это важно (например, b = (b == true); — плохо, а b = (b != false); — хорошо)
K13>Это как раз не плюсовый подход. плюсовый -- это true или false + я хотел бы ключик компилятора который кидает исключение на других значениях.
Значит попутал малосьть.
K13>иначе что мы должны делать здесь: K13>
K13>bool xor2( bool a, bool b )
K13>{
K13> return a != b;
K13>}
K13>
Здесь пусть будет как есть, естественно работать будет только на "хороших" булах.
K13>если разрешить "все остальное"? и главное -- _зачем_? K13>в чем выигрыш от "всего остального"? встретив K13>
bool f = 5;
K13>компилятор сам засунет именно true.
Я не совсем правильно выразился. Я не хотел на уровне языка засовывать в bool все остальное, я предложил что-то вроде "хоть мы и как-бы ограничили возможность инициализации bool только двумя значениями, но фактически там может оказаться что-то другое, и потому результат сравнения, либо переход по switch могут дать неожиданный результат. Нормализуйте bool сами там где это важно.".
А фактически мы имеем "The possible values of type bool are true and false." и всякое UB при impossible values.
K13>Реально в bool может оказаться мусор либо в виде неинициализированной переменной, либо явного затирания через приведение указателя / потоптанной памяти.
Как оказалось есть, вполне легальные способы получить мусор в bool через выравнивание полей. А единожды полученный, он может расползтись по программе через присваивания и давать неожиданные эффекты.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, samius, Вы писали:
К>>>Для целочисленных типов нет априори-мусорных значений. Мусорность определяется уже программистом по месту использования. Ну там ожидаемая делимость, вхождение в диапазон, и т.д. S>>Да, bool таки представлен целочисленным ведь типом? J>Нет, bool — это самостоятельный тип, в числе других целочисленных типов.
S>>Но я не понимаю, чем так плох плюсовый подход к bool-у, когда легально есть FALSE, TRUE и все остальное? Зачем надо было объявлять в языке что может быть только 2 значения? Без каких либо изменений в коде, нужно было бы всего лишь специфицировать поведение компилятора при остальных значениях и ткнуть носом в корректную нормализацию bool-а для тех сценариев, где это важно (например, b = (b == true); — плохо, а b = (b != false); — хорошо)
J>Если мы говорим о С++, то легально есть только true и false, нету никакого "всего остального": J>
J>Values of type bool are either true or false.42)
J>42) Using a bool value in ways described by this International Standard as ‘‘undefined,’’ such as by examining the value of an uninitialized automatic variable, might cause it to behave as if it is neither true nor false.
ООООООООООО!
Т.е. в случае плюсов мы готовы к тому что там может быть что-то еще. А в случае шарпа — нет.
Здравствуйте, samius, Вы писали:
J>>Если мы говорим о С++, то легально есть только true и false, нету никакого "всего остального": J>>
J>>Values of type bool are either true or false.42)
J>>42) Using a bool value in ways described by this International Standard as ‘‘undefined,’’ such as by examining the value of an uninitialized automatic variable, might cause it to behave as if it is neither true nor false.
S>ООООООООООО! S>Т.е. в случае плюсов мы готовы к тому что там может быть что-то еще. А в случае шарпа — нет.
Не понял, каким образом мы "готовы". Программа с неопределенным поведением — это некорректная программа, которая может делать все, что угодно (обычно она просто форматирует винчестер). Стандарт никак не описывает поведение некорректных программ.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, jazzer, Вы писали:
J>>Robert C. Martin's Clean Code Tip #12: Eliminate Boolean Arguments J>>http://www.informit.com/articles/article.aspx?p=1392524
PD>Кое-что по существу верно, но вообще — проблема ИМХО не стоит выеденного яйца.
Проблема, которая даёт такой неприятный для человека эффект (я про сложность вообще осознания того, что две схожие функции получают данные противоположным образом) — она очень даже стоит, и даже тысячи невыеденных яиц. Вообще, получился хороший пример как на ровном месте сделать obfuscating коду.
Здравствуйте, jazzer, Вы писали:
I>>Все в сослагательном наклонении, потому-что конкретная проблема надумана, аргумент конечно же должен задаваться в радианах. J>Можете выбрать любой цвет, при условии что вы выбираете черный :) J>Не все так однозначно. J>Градусы хороши своей целочисленностью.
Не целочисленностью, конечно же — вон Земля наклонена примерно под 23.45 градусов (23 градуса 27 минут). А значительно большей естественностью для человека. Анализировать внутри программы поворот на 30 градусов как-то проще, чем на 0.52 радиана.
Автопилот совершенно естественно может давать корректировки на нецелое число градусов (хотя вот он будет скорее всего считать в радианах).
I>>Возможно стоит добавить, что это преобразование нужно выполнять только при вводе информации от пользователя, внутри программа должна иметь дело только с радианами. J>см. выше. J>То же, кстати, относится к доброй половине финансовых программ, где цены, вроде как, не целые, но из лучше хранить как целые или как пару целых.
Там — да, тут — не вижу основания для перехода на целые.
I>>PS. Этот автор у тебя тоже в числе экспертов? J>Я *там* в качестве эксперта упоминал Глассборо — есть сомнения, что он эксперт? Тот, кого ты *там* нашел, я впервые увидел. Ладно, здесь это офтопик в любом случае. J>А эта конкретная статья в RSS прилетела, посмеялся, пока читал, решил сюда запостить. J>Надеюсь, что вы тоже посмеялись.
Скорее поплакали.:)))
J>С другой стороны, хоть и смешно, но проблема реальная: во многих признанных API (в винде, например) булевские переменные летают только в путь, в результате смотришь в вызов функции с пятью true, как дурак, и пытаешься понять, что же они все означают.
Ну там системное API, что поделать.
Хотя если бы аргументы были гарантированно названы и язык позволял (как C++) — можно было бы писать SysCloseDoor(hDoor, immediately = true, ignore_obstacle = true, lock = false). Я так делаю в Питоне, потому что удобнее.:) хотя в рантайме и чуть дороже.
J>Так что мысль вроде как и очевидна, да, видать, лень побеждает — bool же проще сунуть, чем целое перечисление объявлять или вообще специальный полноценный тип ваять.
Так её надо побеждать встречной ленью — дебажить полученное.;))
Здравствуйте, netch80, Вы писали:
J>>Градусы хороши своей целочисленностью.
N>Не целочисленностью, конечно же — вон Земля наклонена примерно под 23.45 градусов (23 градуса 27 минут). А значительно большей естественностью для человека. Анализировать внутри программы поворот на 30 градусов как-то проще, чем на 0.52 радиана.
Нет, именно целочисленностью. Всякие градусы типа 45, 90, 180, 360 имеют вполне однозначное толкование, в отличие от иррационального пи, которое непонятно с какой точностью записывать.
Например, поворот картинки на 180 тривиален, а на пи — попробуй еще разберись, что ошибка в 24-м знаке — это ошибка представления, а не то, что тебе нужно именно на такой вот кривой угод повернуть.
Естественность для человека тут ни при чем, просто целые радианы практического смысла не имеют никакого, в отличие от целых градусов (именно потому что круг поделили на целое количество частей).
N>Ну там системное API, что поделать. N>Хотя если бы аргументы были гарантированно названы и язык позволял (как C++) — можно было бы писать SysCloseDoor(hDoor, immediately = true, ignore_obstacle = true, lock = false). Я так делаю в Питоне, потому что удобнее. хотя в рантайме и чуть дороже.
Ну так от питона никто скорости и не ждет
так что в питоне все так делают
J>>Так что мысль вроде как и очевидна, да, видать, лень побеждает — bool же проще сунуть, чем целое перечисление объявлять или вообще специальный полноценный тип ваять.
N>Так её надо побеждать встречной ленью — дебажить полученное.)
не понял, кто в данном случае "встречно ленится"...
Здравствуйте, jazzer, Вы писали:
J>>>Градусы хороши своей целочисленностью. N>>Не целочисленностью, конечно же — вон Земля наклонена примерно под 23.45 градусов (23 градуса 27 минут). А значительно большей естественностью для человека. Анализировать внутри программы поворот на 30 градусов как-то проще, чем на 0.52 радиана. J>Нет, именно целочисленностью. Всякие градусы типа 45, 90, 180, 360 имеют вполне однозначное толкование, в отличие от иррационального пи, которое непонятно с какой точностью записывать. J>Например, поворот картинки на 180 тривиален, а на пи — попробуй еще разберись, что ошибка в 24-м знаке — это ошибка представления, а не то, что тебе нужно именно на такой вот кривой угод повернуть.
Твоя идея понятна, но не приемлема:
1. То, о чём ты говоришь, фактически означает не "целое число градусов", а "целое конкретное число градусов из набора фиксированных значений, которые имеют свой отдельный смысл" (180 — пол-круга, 90 — четверть круга или прямой угол, и так далее). Потому что поворот на 180, например, чётко определён именно в градусах как половина круга и это имеет смысл тем, что упрощает реализацию; а вот поворот на 25 или 26 градусов у тебя будет одинаково трудоёмок что в радианах, что в градусах.
2. В контексте исходной статьи это всё не имеет значения — задать самолёту разворот на 180 градусов, на 3.14 радиана или 3.15 — всё равно воздушные потоки и прочие левые факторы внесут свою коррективу, и на половине поворота (скорее даже раньше) придётся это исправлять.
J>Естественность для человека тут ни при чем, просто целые радианы практического смысла не имеют никакого, в отличие от целых градусов (именно потому что круг поделили на целое количество частей).
Целые радианы имеют значительно больше практического смысла, чем целые градусы. Радианы не только не зависят от того, сколько у тебя пальцев или чем ты думаешь — они упрощают практически все тригонометрические формулы. Иначе бы их не вводили. А градусы — это индивидуальны.
Не знаю, в курсе ли ты, но есть так называемые "грады", коих в прямом углу не 90, а 100. Они приняты в ряде специфических областей инженерии. И практически они не сильно хуже. А вот радианную меру ты на 1.2 или 0.9 не умножишь — чушь получится.
N>>Ну там системное API, что поделать. N>>Хотя если бы аргументы были гарантированно названы и язык позволял (как C++) — можно было бы писать SysCloseDoor(hDoor, immediately = true, ignore_obstacle = true, lock = false). Я так делаю в Питоне, потому что удобнее.:) хотя в рантайме и чуть дороже. J>Ну так от питона никто скорости и не ждет :) J>так что в питоне все так делают
А в компилируемых языках можно это возложить на компилятор. Просто не припекло.
J>>>Так что мысль вроде как и очевидна, да, видать, лень побеждает — bool же проще сунуть, чем целое перечисление объявлять или вообще специальный полноценный тип ваять. N>>Так её надо побеждать встречной ленью — дебажить полученное.;)) J>не понял, кто в данном случае "встречно ленится"...
Тот, кому это дальше расчищать и по последствиям расчистки — рефакторить.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, samius, Вы писали:
S>>Т.е. в случае плюсов мы готовы к тому что там может быть что-то еще. А в случае шарпа — нет.
J>Не понял, каким образом мы "готовы". Программа с неопределенным поведением — это некорректная программа, которая может делать все, что угодно (обычно она просто форматирует винчестер). Стандарт никак не описывает поведение некорректных программ.
мы "готовы" значит что программист, прочитавший спецификацию, предупрежден о том что там может быть не true и не false.
Здравствуйте, Кодт, Вы писали:
К>А вот для вещественных типов, ЕМНИП, можно сделать априори-мусорное значение (элементарно: денормализовать мантиссу).
Но как, Холмс? ЕМНИП мантисса вещественного числа хранится без старшего бита (который подразумевается единичным для всех значений экспоненты кроме 0 (0) и 3ff (NaN)) и не может быть ненормализованной. "Испортить" вещественное число наверно можно например записав в экспоненту 0 а в мантиссу не 0, хотя в этом случае FPU скорее всего просто проигнорирует биты мантиссы.
---
The optimist proclaims that we live in the best of all possible worlds; and the pessimist fears this is true
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, jazzer, Вы писали:
J>>>>Градусы хороши своей целочисленностью. N>>>Не целочисленностью, конечно же — вон Земля наклонена примерно под 23.45 градусов (23 градуса 27 минут). А значительно большей естественностью для человека. Анализировать внутри программы поворот на 30 градусов как-то проще, чем на 0.52 радиана. J>>Нет, именно целочисленностью. Всякие градусы типа 45, 90, 180, 360 имеют вполне однозначное толкование, в отличие от иррационального пи, которое непонятно с какой точностью записывать. J>>Например, поворот картинки на 180 тривиален, а на пи — попробуй еще разберись, что ошибка в 24-м знаке — это ошибка представления, а не то, что тебе нужно именно на такой вот кривой угод повернуть.
N>Твоя идея понятна, но не приемлема:
N>1. То, о чём ты говоришь, фактически означает не "целое число градусов", а "целое конкретное число градусов из набора фиксированных значений, которые имеют свой отдельный смысл" (180 — пол-круга, 90 — четверть круга или прямой угол, и так далее). Потому что поворот на 180, например, чётко определён именно в градусах как половина круга и это имеет смысл тем, что упрощает реализацию; а вот поворот на 25 или 26 градусов у тебя будет одинаково трудоёмок что в радианах, что в градусах.
ну то есть в основном одинаково трудоемко, но в градусной мере есть выделенные точки, в которых радикально менее трудоемко.
Стало быть, градусы лучше, чем радианы; непонятно, почему ты говоришь, что идея неприемлема
N>2. В контексте исходной статьи это всё не имеет значения — задать самолёту разворот на 180 градусов, на 3.14 радиана или 3.15 — всё равно воздушные потоки и прочие левые факторы внесут свою коррективу, и на половине поворота (скорее даже раньше) придётся это исправлять.
Это да. В этой конкретной задаче никакой разницы.
J>>Естественность для человека тут ни при чем, просто целые радианы практического смысла не имеют никакого, в отличие от целых градусов (именно потому что круг поделили на целое количество частей).
N>Целые радианы имеют значительно больше практического смысла, чем целые градусы. Радианы не только не зависят от того, сколько у тебя пальцев или чем ты думаешь — они упрощают практически все тригонометрические формулы. Иначе бы их не вводили. А градусы — это индивидуальны.
Да ладно. Все наоборот. Раз ты завёл речь о тригонометрии — чему равен синус 180 градусов? а синус 3.1415926? а синус 3.1415926535?
Формулам пофиг, там все с точностью до множителя, а вот в реальной машинной жизни все сильно портится, потому что этот множитель иррационален и непредставим в десятичной записи (вернее, ни в какой разрядной записи непредставим).
N>Не знаю, в курсе ли ты, но есть так называемые "грады", коих в прямом углу не 90, а 100. Они приняты в ряде специфических областей инженерии. И практически они не сильно хуже. А вот радианную меру ты на 1.2 или 0.9 не умножишь — чушь получится.
В курсе. и градусы, и грады лучше радианов, именно потому что целочисленные.
N>А в компилируемых языках можно это возложить на компилятор. Просто не припекло.
Мороки много просто. Есть же Boost.Parameter.