On Thursday, 28 March 2013 at 20:03:08 UTC, Adam D. Ruppe wrote:
I was working on a project earlier today that stores IP
addresses in a database as a uint. For some reason though, some
addresses were coming out as 0.0.0.0, despite the fact that
if(ip == 0) return; in the only place it actually saves them
(which was my first attempted quick fix for the bug).
Turns out the problem was this:
if (arg == typeid(uint)) {
int e = va_arg!uint(_argptr);
a = to!string(e);
}
See, I copy/pasted it from the int check, but didn't update the
type on the left hand side. So it correctly pulled a uint out
of the varargs, but then assigned it to an int, which the
compiler accepted silently, so to!string() printed -blah
instead of bigblah... which then got truncated by the database,
resulting in zero being stored.
I've since changed it to be "auto e = ..." and it all works
correctly now.
Anyway I thought I'd share this just because one of the many
times bearophile has talked about this as a potentially buggy
situation, I was like "bah humbug"... and now I've actually
been there!
I still don't think I'm for changing the language though just
because of potential annoyances in other places unsigned works
(such as array.length) but at least I've actually felt the
other side of the argument in real world code now.
IMHO, array.length is *the* place where unsigned does *not* work.
size_t should be an integer. We're not supporting 16 bit systems,
and the few cases where a size_t value can potentially exceed
int.max could be disallowed.
The problem with unsigned is that it gets used as "positive
integer", which it is not. I think it was a big mistake that D
turned C's "unsigned long" into "ulong", thereby making it look
more attractive. Nobody should be using unsigned types unless
they have a really good reason. Unfortunately, size_t forces you
to use them.