C++ Logo

std-proposals

Advanced search

Re: [std-proposals] D3666R0 Bit-precise integers

From: Hans Åberg <haberg_1_at_[hidden]>
Date: Wed, 3 Sep 2025 15:58:42 +0200
> On 3 Sep 2025, at 15:37, David Brown <david.brown_at_[hidden]> wrote:
>
> On 03/09/2025 14:42, Hans Åberg wrote:
>>> On 3 Sep 2025, at 11:01, David Brown <david.brown_at_[hidden]> wrote:
>>>
>>> The awkward thing here is that bool has virtually no operations in itself - pretty much everything is done after implicitly converting it to int. You can't even compare two bool's for equality without them being subject to integer promotions - so if you simply dropped implicit conversion to int, you'd now have to write "if (int(bool_a) == int(bool_b))".
>> That is a problem with all built-in types, I think, that they are not classes.
>
> No, many types have operations defined on them directly - including int. But bool is not the only type that is always promoted or otherwise changed before most operations - char and other smaller integer types are also promoted and don't have their own operations, while C-style array types are converted to pointers to their first element in many situations.

It reflects what is going on at the assembler level, I think. But a more robust interface could have been built.

>>> I agree with your aim here, but it would unfortunately be difficult to achieve with a change to existing C++.
>> One might create a new syntactic environment:
>> new_c++ {
>> // Conditionals only accept values of a new Boolean type; not int.
>> }
>
> I hope not! If someone wants to take the best of C++, remove the old cruft, and make a new better language, it is best to do it much more completely. Carbon and Cpp2 are two experimental attempts at this.

The strength of C++ is that one knows the stuff is there. New C++ style languages, the little I have seen, keep the multiparadigm instead of attempting to make a more consistent logical model, and strip away a lot of useful features. So in the end, not much is gained.

>> It is the other conversion, from int to bool that causes problems, in the conditionals. That is, the conditionals should only accept Boolean values.
>
> Conditionals in C++ have "contextual conversion to bool" - that is, when you write "if (x)" it is as though you had written "if (bool(x))". You get the conversion to bool even for classes for which the conversion is marked "explicit". This is because it is incredibly useful.

It is also gets in the way in som circumstances. :-)

> You are concerned that the conversion from int to bool loses information - it is much better to think of it as extracting a small amount of useful information. People don't convert int to bool accidentally, thinking it preserves value (in the way that they might accidentally convert a bigger integer type to a smaller one).

The conversion to int is needed for switch statements, and the conversion to bool for conditionals, but the example I gave, converting to int and then to bool, gives the wrong result, and there seems to be no way around it.

>>>>>>> Some changes /do/ make sense, such as the removal of the increment and decrement operators on bool in C++17. I think it might make sense to limit other arithmetic operators on bools, or at least when operating on two bools - the promotion of bool to int can be convenient in some expressions.
>>>>>> The current bool is useful, as there may not be good support on the assembler level for other types.
>>>>>
>>>>> I don't follow. The current bool is useful - of that there is no doubt. That is the case regardless of what cpu instruction level support there might be for things that are a bit like bool, but which behave somewhat differently.
>>>> Requiring bool to have modular arithmetic might burden it, so since there are no good use cases, not worth to pursue.
>>>
>>> Supporting one-bit modular arithmetic is not going to be challenging on any real-world hardware. Modular addition (and subtraction) is just logical xor, and modular multiplication is just logical and.
>> Looking at ARM64, one cannot pass a boolean value to it; it must be first converted to a 32- or 64-bit variable, and likewise, a test sets a flag which can be extracted by adding to such a variable. Perhaps not demanding on today's computers, but it might be the reason bool started off as int in C.
>
> Operations on many RISC architectures are often done full-width, and occasionally that means extending a smaller value. This is often done in combination with a load, and is thus basically free.
>
> C started off as a simpler language. There was a great deal that it did not have in its early days - it picked up a lot of features for C90, and many more for C99 (a number of these features - including _Bool - were based on early C++ features).

It has picked up in later years, but was used for a long time for its stability.

>>>> Then I have problems with the implicit conversions. The undefined value is converted to int -1, but there is always the risk it gets further converted to a bool, and then it becomes true.
>>>
>>> When it is your own type, /you/ control which conversions are implicit, explicit, or not allowed at all.
>> Conversions to int are necessary for use in switch statements.
>
> Yes, but those do not need to be /implicit/ conversions - you can use /explicit/ conversions. (You would not normally want a switch on a bool, but you might use one for tri-value logic types.)
>
> A better solution might be to hold the tri-value logic internally as a strong enumeration type within the class, and then support implicit conversion to that type. Switch cases of the enumeration type would be clearer and harder to get wrong than switch cases of an internal integer value.

I tried different variations, and the one I gave proved most convenient.
https://cgit.git.savannah.gnu.org/cgit/metalogic-inference.git/tree/src/kleenean.hh

Received on 2025-09-03 13:59:00