Topic: suppressing integral promotions / conversions


Author: a9804814@unet.univie.ac.at (Thomas Mang)
Date: Thu, 20 Mar 2003 18:13:27 +0000 (UTC)
Raw View

Victor Bazarov schrieb:

>
> I have never encountered (or cannot remember) a situation where
> standard arithmetic conversions were a bad thing.  So, you need
> to demonstrate that there is a problem.  "Has consequences all
> over" doesn't cut it (for me at least).

As already mentioned, take basic_string::operator=(charT).
charT is usually char, so the following is perfectly legal, but hardly what
the user intends:

std::string Pi;
Pi = 3.1415927.

As you know, integral promotions / conversions rank from (lowest precision)
char to (highest precision) long double. If a function takes a built in type
with precision at either edge, it is hardly intended to be called with a type
with precision at the other edge - either because we cut off significant
digits, or because it is likely we have missed to provide significant digits
[that doesn't mean a value representable by a char is always wrong when a
double is expected - it just is much more likely the caller didn't recognize
what was intended to provide as argument].

Most people say non-explicit constructors and conversion operators are bad and
shall be handled only with great care. I belong to them. However, the integral
promotions conversions are built in at the very core of the language. Yes, it
is often intended. The problem is the conversion take place wether it is one
of those "often" cases or one of those more rare not-intended cases. I am not
suggesting to remove the automatic conversion, I am suggesting to suppress
them on demand - to change runtime-conversions with either loss of precision /
lacking precision / undefined behavior due to not representable values against
a nice compile-time error.
Fortunately, C++ does not make automatic down-casts in hierarchies. We can do
it manually using one of the casting operators. But currently, we simply have
to accept integral conversions / promotions and lack a mechanism to disallow
them on demand.

>
>
> One could simulate the behaviour of your 'explicit' thing with
> a template, I believe:
>
>     template<class T> void foo(T t);
>     void foo(double d);
>
> For any call foo(t) where typeof(t) is not 'double', the template
> should be used, and if you don't define it, the undefined symbol
> error should pop up during linking.
>
> Of course, every function where you'd put the 'explicit' would
> require the mirroring template declaration...

I was thinking about this too, but I doubt it to be a good idea.
First, it delegates the error to linking, which is somewhat different from
compiling.
Second, it is a hack that hardly expresses what it is supposed to do.


best regards,

Thomas

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: v.Abazarov@attAbi.com ("Victor Bazarov")
Date: Thu, 20 Mar 2003 20:39:56 +0000 (UTC)
Raw View
"Thomas Mang" <a9804814@unet.univie.ac.at> wrote...
> Victor Bazarov schrieb:
> > I have never encountered (or cannot remember) a situation where
> > standard arithmetic conversions were a bad thing.  So, you need
> > to demonstrate that there is a problem.  "Has consequences all
> > over" doesn't cut it (for me at least).
>
> As already mentioned, take basic_string::operator=(charT).
> charT is usually char, so the following is perfectly legal, but hardly
what
> the user intends:
>
> std::string Pi;
> Pi = 3.1415927.
>
> As you know, integral promotions / conversions rank from (lowest
precision)
> char to (highest precision) long double. If a function takes a built in
type
> with precision at either edge, it is hardly intended to be called with a
type
> with precision at the other edge - either because we cut off significant
> digits, or because it is likely we have missed to provide significant
digits
> [that doesn't mean a value representable by a char is always wrong when a
> double is expected - it just is much more likely the caller didn't
recognize
> what was intended to provide as argument].
>
> Most people say non-explicit constructors and conversion operators are bad
and
> shall be handled only with great care. I belong to them. However, the
integral
> promotions conversions are built in at the very core of the language. Yes,
it
> is often intended. The problem is the conversion take place wether it is
one
> of those "often" cases or one of those more rare not-intended cases. I am
not
> suggesting to remove the automatic conversion, I am suggesting to suppress
> them on demand - to change runtime-conversions with either loss of
precision /
> lacking precision / undefined behavior due to not representable values
against
> a nice compile-time error.
> Fortunately, C++ does not make automatic down-casts in hierarchies. We can
do
> it manually using one of the casting operators. But currently, we simply
have
> to accept integral conversions / promotions and lack a mechanism to
disallow
> them on demand.
>
> >
> >
> > One could simulate the behaviour of your 'explicit' thing with
> > a template, I believe:
> >
> >     template<class T> void foo(T t);
> >     void foo(double d);
> >
> > For any call foo(t) where typeof(t) is not 'double', the template
> > should be used, and if you don't define it, the undefined symbol
> > error should pop up during linking.
> >
> > Of course, every function where you'd put the 'explicit' would
> > require the mirroring template declaration...
>
> I was thinking about this too, but I doubt it to be a good idea.
> First, it delegates the error to linking, which is somewhat different from
> compiling.
> Second, it is a hack that hardly expresses what it is supposed to do.


In many cases I've encountered, if conversions should have been
limited (suppressed, disallowed), then not to _a_particular_ one,
but to a _range_ of them. Example:

    short a = 42;
    int b = a / 2; // OK -- integral promotion
    int c = a * 0.5;  // arithmetic conversion to double -- would
                      // like to disable those (loss of fractions)

The most often used conversion for me is int into double (for the
literal 0) and bool into int (0 or 1, for expressions, I'd rather
write a + (somecondition) * b  than  a + (somecondition ? b : 0).
That may not be the best style, I will not argue about that, but
it's something that I've done and seen done quite often.

The main problem with your proposal is that it's not going to take
care of _partial_ limitation.  To achieve partial limitation with
help of your 'explicit' use, one would have to enumerate _all_
possibilities in overloaded functions and then channel them through
one, somehow obscure, implementation without 'explicit'.  That's
not a good idea either.

Victor
--
Please remove capital A's from my address when replying by mail


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: v.Abazarov@attAbi.com ("Victor Bazarov")
Date: Wed, 19 Mar 2003 19:53:28 +0000 (UTC)
Raw View
"Thomas Mang" <a9804814@unet.univie.ac.at> wrote...
> We have "explicit" to mark constructors which shall not act as
> conversion functions, which is often a good idea.
> We can also supply conversion operators to classes in the rare cases
> automatic conversions may take place.
>
> But there are hardly useful features to suppress integral promotions /
> conversions for arguments, e.g.
>
> void foo(long double d);
>
> int main()
> {
> foo('a');
> return 0;
> }
>
> is correct, but hardly the intent of foo. Trivial example, but has
> consequences all over C++, from member functions of basic_string to
> probably every program beyond "hello-world" .
>
> So why isn't there a mechanism to suppress integral promotions /
> conversions, something like:
>
> void foo(explicit double d);
>
> which can only be called passing in a double:
>
> foo(static_cast<double>('a'));   // OK, static_cast, users knows what he
> does
> foo(4.555);   // OK, double passed;
> foo(44);    // compile-error, int passed, double expected.
>
>
> What's your opinion about this ?


I have never encountered (or cannot remember) a situation where
standard arithmetic conversions were a bad thing.  So, you need
to demonstrate that there is a problem.  "Has consequences all
over" doesn't cut it (for me at least).

One could simulate the behaviour of your 'explicit' thing with
a template, I believe:

    template<class T> void foo(T t);
    void foo(double d);

For any call foo(t) where typeof(t) is not 'double', the template
should be used, and if you don't define it, the undefined symbol
error should pop up during linking.

Of course, every function where you'd put the 'explicit' would
require the mirroring template declaration...

There are probably holes in this suggestion, please do point them
out.

Victor
--
Please remove capital A's from my address when replying by mail


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: a9804814@unet.univie.ac.at (Thomas Mang)
Date: Mon, 17 Mar 2003 21:30:56 +0000 (UTC)
Raw View
Hi everybody,


We have "explicit" to mark constructors which shall not act as
conversion functions, which is often a good idea.
We can also supply conversion operators to classes in the rare cases
automatic conversions may take place.

But there are hardly useful features to suppress integral promotions /
conversions for arguments, e.g.

void foo(long double d);

int main()
{
foo('a');
return 0;
}

is correct, but hardly the intent of foo. Trivial example, but has
consequences all over C++, from member functions of basic_string to
probably every program beyond "hello-world" .

So why isn't there a mechanism to suppress integral promotions /
conversions, something like:

void foo(explicit double d);

which can only be called passing in a double:

foo(static_cast<double>('a'));   // OK, static_cast, users knows what he
does
foo(4.555);   // OK, double passed;
foo(44);    // compile-error, int passed, double expected.


What's your opinion about this ?


best regards,

Thomas

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hyrosen@mail.com (Hyman Rosen)
Date: Tue, 18 Mar 2003 01:02:40 +0000 (UTC)
Raw View
Thomas Mang wrote:
> So why isn't there a mechanism to suppress integral promotions / conversions

But there is. You write it like this:
     template <typename T> void foo(T);

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]