On Mon, 2 Mar 2020 at 03:16, Alexander Grund via Boost < boost@lists.boost.org> wrote:
Nothing stops you from converting to signed, do what you want including your "check for negative"-based overflow detection and finally converting back to unsigned when passing it to an API expecting an unsigned number (number not type, although the type is unsigned too, see above)
Could you please try and explain, why you think that signed is not a good type for a size (other than stating that "size cannot be negative"), what I am saying is that "valid-size cannot be negative"? You could also make the size a complex number, that would be an analogue. The imaginary-componant will have to be zero, but otherwise it would work just fine. The fact that that set is larger than the problem domain is IMO orthogonal to that.
Didn't you argue in the mail before that there will never be anything of size 2^32 and hence even not anything like 2^64? How could you overflow that then?
If you are manipulating (subtracting, adding differences) pointers, I thought I wrote that. The pointers might be pointers into Virtual Memory and can have any value [1, 2^56].
Finding bugs related to this is hard, using int's you'll know right away. How? Only if you underflow. On unsigned you'll get a very large number if you go below zero, on signed you get a negative number. Both can be detected. But you talked about overflow. For unsigned you'll get a small number (that is wrong obviously but you COULD check) but for signed you get UB and hence can't even check for that.
If you get an unsigned value there is no need to check for below zero, if you get a signed value you might. It is the same there is `not_null<T>` in GSL(?).
But you would need to check if it wrapped No. If you call `obj.size()` you get an unsigned value that is a valid unsigned value. It cannot wrap when returning (conditions apply).
Tautology: "... an unsigned value that is a valid unsigned value", they always are, whether it's the right number is another question. If obj.size() returns a signed value you'll got to check for <0 before
using the value unless the API somehow promises to not return negative values. Encoding this in the type is the natural thing to do.
No, it's not, unsigned types are good for bit-manipulation only, nothing else. Unsigned types don't follow the rules of mathematics, they are fundamentally flawed by nature. The fact that int's are limited in range is not flaw, but an implementation detail. The mathematically correct way of doing things (on a Turing-machine) is to use signed big-ints.
and if you start adding and subtracting these things See above. For a representation (and hence API) unsigned makes sense. For using arbitrary operations it may not. Use the types that fir your use case. Adding is save for unsigned, as you argued: The type is wide enough for all uses as a size of something. Subtraction might not but you can check first (`if(a <= size) return size - a; else throw `)
You've now just precluded the use of noexcept (noexcept move f.e., super-important in modern C++) and added a branch (cannot be removed by something clever, exactly because it is unsigned, the compiler can make no assumptions and the code has to go through the math) to your code, all that because it upsets you that something that should not occur in the first place in correct code can occur iff one is writing code that now (as one observed it got negative) is known to have a bug. What is much better is to use signed int's combined with assert's. The use of unsigned is false security (actually no security) and serves nothing. In the end, you still need to write correct code (so the signed int's WON'T BE negative, there where they shouldn't be), but this practice makes you're code less flexible, more verbose (the unavoidable casts add to that) and probably slower than using signed. All that because of this 'natural' way of looking at sizes.
I don't understand.
Maybe after the above? You want a guarantee to have a non-negative number. "unsigned" is that but it suffers from underflow going undetected. A `not_null<T>` like "wrapper" which otherwise behaves as T but guarantees the non-negativity would make the type suitable for representing an unsigned number in a signed type suitable for operations. Obviously if you subtract something from a `not_negative<int>` it will become a plain "int". Once you pass it to an API expecting a `not_negative<int>` the precondition will be checked.
Got it now, yeah that would be great, but for now that would be run-time, no? And I guess, due to the halting problem, it can never be compile-time, unless it's a limited problem. degski -- @systemdeg "We value your privacy, click here!" Sod off! - degski "Anyone who believes that exponential growth can go on forever in a finite world is either a madman or an economist" - Kenneth E. Boulding "Growth for the sake of growth is the ideology of the cancer cell" - Edward P. Abbey