From: nmm1 on
In article <i0gdln$i05$1(a)usenet.stanford.edu>,
Seungbeom Kim <musiphil(a)bawi.org> wrote:
>On 2010-06-30 00:55, Kaba wrote:
>>
>> My opinion is also that unsigned should not be used for integer
>> quantities. My reasoning goes as follows:
>>
>> 1. Robustness
>[...]
>> 2. Preservation of information
>[...]
>> 3. Consistency and traps
>[...]
>> 4. Floating point analogue
>>
>> One can imagine an unsigned floating point type by stripping off the
>> sign bit, and perhaps giving an additional bit to the mantissa. Such a
>> type would have similar problems as listed here for the integers.
>> Interestingly, people don't seem to have anxiety over this lost bit,
>> although the situation is exactly as with the integers.
>
>Probably because floating-point types already have wider ranges,
>and probably because people already take it as a matter of fact
>that floating-point values are not accurate.

No, that's not the reason. They used to exist, on occasion, though
not as commonly as unsigned fixed-point (i.e. fractional) types.
But people decided that they weren't generally useful sometime
before 1965 - perhaps even considerably before.

>An IEEE single precision floating-point format can already represent
>24 bits of mantissa, i.e. about 7 decimal digits, which is enough for
>many purposes, and adding one bit doesn't change things that much:
>it doesn't make it capable of representing 1/3 or 0.1 exactly anyway.
>And that's "single" precision (usually the 4-byte type "float");
>an IEEE double precision floating-point format (usually the 8-byte type
>"double") has 53 bits of mantissa, i.e. about 16 decimal digits.
>And the inexactness stays the same.

Also, the problem with precision is different - and less precise :-)
It isn't what you can store that matters, it's how the errors build
up, and an extra bit isn't really very interesting.

>Things might have been different for integers in the old 8-bit and
>16-bit days, where the space was limited, out of which every possible
>bit had to be utilized. 32767 and 65536 make a big difference as
>the highest representable integer. And no inexactness is tolerable.
>That's probably why size_t had to be unsigned. In the 64-bit days,
>who cares if size_t cannot represent more than 2^63-1 instead of 2^64-1?

Yes, it was. And that's why the difference is almost entirely
restricted to languages derived from C - i.e. a language that was
originally designed as an assembler for minicomputers.

>> 5. Summary
>>
>> I think all of the previous can be summarized as follows. Most of the
>> time we are interested in modeling the ring of integers (math Z), even
>> though we'd only use the non-negative values. ...

Agreed.

>The points are all valid. However, it is also "given" that size_t is
>unsigned, and so is size_type for the standard containers. Employing
>signed integers for sizes and counts inevitably leads to mixing them
>with unsigned integers which are given by sizeof() and container.size(),
>and a flood of corresponding warnings:

Agreed. Mixing signed and unsigned integers is doubleplus ungood
in C and C++ - few people understand the arcane rules well enough
to avoid the gotchas. The warnings are there for a reason!

The reason that unsigned integers are a bad idea for sizes and counts
is precisely because they don't have any invalid ranges that can be
used for out-of-band values. However, that argument lost out in C
and C++ back in the early 1970s. In almost all C-derived languages,
sizes and counts are unsigned.


Regards,
Nick Maclaren.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Zeljko Vrba on
On 2010-07-01, Francis Glassborow <francis.glassborow(a)btinternet.com> wrote:
>
> The main reason fgor using default arguments was that it reduced
> problems with multiple constructors where you could not use a wrapper to
> forward to the genral version. That has been fixed in C++0x and so the
> largest motive for using default arguments has gone.
>
For me, the largest motive for using default arguments is to extend
functionality of methods without breaking existing code, where
overloading is not practical.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Johannes Schaub (litb) on
Edward Diener wrote:

> On 6/28/2010 9:32 PM, Johannes Schaub (litb) wrote:
>> Olve Maudal wrote:
>>
>>> At the NDC2010 conference, I gave a presentation where I demonstrated
>>> Solid C++ code by example:
>>>
>>> http://www.slideshare.net/olvemaudal/solid-c-by-example
>>>
>>> It would be great to have your opinion about the examples I present.
>>> Is this solid code, or can it be improved even further?
>>>
>>
>> One thing i really don't agree with is depending on things included by
>> other 3rd party headers.
>>
>> I would also not recommend using a "size_t" to store an offset containing
>> "12" - i think it's bad to use "unsigned" just to signify a quantity is
>> unsigned.
>
> I have never understood such reasoning. If I have an integer value which
> I know must be unsigned, why would I not use an unsigned integer rather
> than a signed integer ?
>

I think there is not a single reason to use unsigned. Why will you use
"unsigned"?

But there are many problems you start to get. Imagine you take the offset
integer and compare it to the result of subtracting pointers... and that the
subtraction result in -1 ... You are then lost since it will convert to
UINT_MAX during comparison and then compare greater.

A simple loop starting from the offset going down to including zero suddenly
becomes not so easy as it's supposed to be anymore... Well sure it's
possible, and sure you can convert the unsigned integer to "int" before
doing comparisons... but why do you want to make life harder for no reason?

I think unsigned should only be used for two reasons

1. You want to cover a range that actually *has* to advance beyond INT_MAX,
and you can't rely on "long" being greater.
2. If you need the wrap-around behavior of unsigned. For hashing, and stuff.

I think case 1. only happens very seldomly. If "INT_MAX" isn't enough
values, 2*INT_MAX is likely to be not enough either, and a greater bit-range
has to be taken anyway.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Alf P. Steinbach /Usenet on
* Mathias Gaunard, on 01.07.2010 16:23:
> On Jun 30, 9:14 am, "Alf P. Steinbach /Usenet"<alf.p.steinbach
> +use...(a)gmail.com> wrote:
>
>> Point 8 "importing a namespace in implementation files is usually not a good
>> idea". Hm. Again it is a matter of context. In a "complex" system (spaghetti)
>> using qualified names everywhere might reduce some symptoms and reduce time
>> wasted on bug-hunting. But otherwise, readability reduces programmers' time,
>> i.e. improves programmer efficiency. Some people do maintain that to their eyes
>> std::cout is more readable than cout, they swallow their colons for breakfast
>> every day& enjoy it. Not for me though; if one is not going to use namespaces
>> as they were intended, including "using", then just stick to C prefixes. :-)
>
> Actually, it could be argued that importing a namespace anywhere is
> *never* a good idea, because unqualified calls in C++ are extremely
> dangerous due to ADL.

Depends. In ordinary code, if ADL selects something that is unacceptable then
that is most probably a design problem that should be fixed. IMHO.

But in Boost-like code and other TMP code that routinely exploits the most
subtle and intricate features of C++ it may perhaps be extremely dangerous to
let anything be implicit except where the implicit selection is the point.


> I know for example that there are a lot of subtle bugs in Boost that
> are caused by this.

Well. Perhaps the cause can be attributed to other aspects of that code. For
example, in a gas chamber breathing normally without a gas mask (like explicit
qualification) can be deadly. The cause of death might be attributed to the
normal breathing without gas mask. Or it might be attributed to the gas.

One solution might be to always have gas mask on, no matter the context. I
actually considered this solution when I lived in Bod�, because there was this
unbelievable stench from a fish oil factory. And I did have a gas mask, I was in
the national guard at that time, but people would perhaps think I was odd?

And it is a bit impractical with the gas mask on all the time, e.g. eating.

So it not only looks odd and makes everyone look the same, which might have
negative effects; it's actually an obstacle for many common activities.

So, another solution might be to avoid the gas.


Cheers,

- Alf

--
blog at <url: http://alfps.wordpress.com>


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Kaba on
Edward Diener wrote:
> On 6/30/2010 3:55 AM, Kaba wrote:
> > 1. Robustness
> >
> > 1a) The neighborhood of zero is perhaps the most used of all integer
> > values.
>
> You seem to be claiming that comparing an unsigned to 0 or setting an
> unsigned to 0 does not work. Care to explain why ? Maybe I have missed
> something deep in C++. The last I heard was that the range of an
> unsigned is 0 to some positive number, that 0 is a perfectly valid value
> for an unsigned number, and that one never has to specify 0U to make it so.

Well that is not what I claim. I am saying that usually the integer
values you have are on some reasonable range, say -10^6 to 10^6, instead
of some values being 10^675. The set of used values are "centered" and
"grouped" around the zero. When this is not the case, arbitrary
precision integers need to be used instead of native types.

I just learned a new term a week ago, so I'll apply it: I think this
part of your reply is a fine example of a strawman argument:)

http://en.wikipedia.org/wiki/Strawman

> > 1b) It is easy to get buggy computations off by few, leading to negative
> > values. Negative values then get wrapped to positive values, and these
> > can't be taken as a bug, because there are no invalid values.
> > 1c) More robust programs are created by allowing for negative values so
> > that they can be used to detect bugs. You can also do this with unsigned
> > values by allocating the last half to this purpose, but that does not
> > correspond with logic anymore.
>
> So for non-negative values you use a type which can be negative and then
> you check to see if you have a bug if something does not work by seeing
> if any of the values are negative ? This is surely not the way I
> program. I use unit tests instead with possibly random input.

For non-negative integer values I use a type which can be negative. If
in the function I except a non-negative value, and I get a negative
value, then I can deduce that I have a bug somewhere and report it. My
point is that the integer values should be transmitted for further
computation (integer operations), not for storage.

This does not have to do with unit tests. It has to do with precondition
testing, which is important for robust programs. Every function should
test its preconditions, at least in debug mode. For example, given a
function to compute the binomial coefficient (choose i from n):

double choose(integer n, integer i)
{
assert(n >= 0);
assert(i >= 0);
assert(i <= n);
// ...
}

My preconditions would be n >= 0, i >= 0, and i <= n, which I check here
with assert. Testing a precondition for n >= 0 is no different to
testing for n >= 5 or n >= -5. Here's a function whose precondition is
xMin < xMax:

double randomUniform(double xMin, double xMax)
{
assert(xMin < xMax);
// ....
}

> > 2. Preservation of information
> >
> > 2a) Unsigned<->signed conversions are, in general, lossy.
>
> On which CPUs is this supposed to occur.

The point is that the meaning of the value changes in conversion, for
some values.

> > 2c) When used to model the ring of integers, unsigned integers have
> > robustness issues, as explained in 1), and they can't, by definition,
> > deal with negative integers.
> > 2d) Therefore signed integers are the proper model for the ring of
> > integers.
>
> If I wanted to model a ring of integers I would not include a
> non-negative value in that ring to begin with.

I think you meant to write here "negative value" instead of "non-
negative value", in which case you would be referring to natural numbers
(N), not integers (Z).

> > 3. Consistency and traps
> >
> > 3a) Try to for-loop from positive n to zero using an unsigned integer
> > index: it never finishes, although no negatives are conceptually used.
> > 3b) Is there a difference between looping in the range [-4, 15] or [0,
> > 15]? What about forward or backwards? It makes code more consistent to
> > always use a signed integer, and you will never have to think things
> > like 3a).
>
> Your 3a is imaginary since of course it finishes:
>
> unsigned int x;
> for (x = 50 /* or any valid non-negative value */; x != 0; --x ) { /* do
> something with x */ }
>
> Pray tell me why the above "for loop" never finishes.

Your loop does finish, but it only iterates in the range [1, 50]: the
problem is to iterate in [0, 50]. The answer to why such a loop never
finishes is that x >= 0 is always true for an unsigned integer.

> Your arguments don't even begin to convince me. Only 1c has any
> practical value but since I don't program/debug the way you do, I can
> forgo such an exotic reason.

It's ok, I am not trying to convince anyone.

--
http://kaba.hilvi.org

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]