In a Going Native 2013 talk, the panel had suggested avoiding unsigned integer types
when specifying variables that "can't be negative".
12:15: "Use signed integers unless you need 2's compliment arithmetic or a bit pattern."
12:55: "Use ints until you have a reason not to. Don't use unsigned unless you are fiddling with bit patterns, and never mix signed and unsigned."
42:45: "Whenever you mix signed and unsigned numbers you get trouble. The rules are just very surprising, and they turn up in code in the strangest places. They correlate very strongly with bugs. When people use unsigned integer numbers, they usually have a reason. The reason will be something like "well, it can't be negative" ... When you think you can't have negative numbers, you will have someone who initializes your unsigned with -2, and think they get -2. It is just highly error prone. ... There are far too many integer types. There are far too lenient rules for mixing them together, and it's a major bug source. Which is why I'm saying, stay as simple as you can. Use integers until you really really need something else."
This is understood, but there is no mention to alternatives when designing interfaces that must only accept positive numbers. I could document it:
//NOTE: i must be positive!
void function(int i);
I could rely on debug assertions everywhere:
void function(int i){
assert(i >= 0);
}
What I'd really like, is to specify it at the type level. This is a stronger contract. I want to make sure the function is incapable of accepting an integer that is negative. This is where I would normally choose an unsigned, but given that this is a discouraged practice, what are my alternatives?
Can a type like this be created to satisfy the value constraint?
void function(positive<int> i);
Does it make sense to do this?
The reason why having the parameter unsigned
solves nothing is because passing a run-time negative value into such a function checks nothing. -1
will be reinterpreted as 4294967295
and the program will silently continue.
Only if you try to pass a compile-time known constant a warning will be raised.
If you want to check every parameter you pass into your function, even at run-time, having an assert is the simplest way.
If you want to be more fancy and descriptive, you can define your own type positive
which would:
int
(demotion)int
, but performing an assert
when doing so (promotion)This will definitely make your code ``cleaner'' with a clear intent - but that is much more coding.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With