## digitalmars.D - Casts and conversions done right

• Lars T. Kyllingstad (31/31) Jul 20 2009 The subject of casts has come up in various forms now and then, and with...
• Michiel Helvensteijn (5/6) Jul 20 2009 But what does the to function do, exactly? I'd prefer to use one of floo...
• Lars T. Kyllingstad (11/18) Jul 20 2009 I could perhaps have found a better example than rounding conversions
• bearophile (4/7) Jul 20 2009 I think this topic needs quite more thinking, but I agree that the curre...
• Daniel Keep (13/32) Jul 20 2009 This is a bit of a bug-bear of mine, too. I originally wrote Tango's
• Lars T. Kyllingstad (16/52) Jul 21 2009 Recently, Julien Leclercq posted an enhancement request for Phobos
• Daniel Keep (13/49) Jul 21 2009 Why would it?
• Lars T. Kyllingstad (5/23) Jul 23 2009 Ah, I misunderstood your "lock cast(T) away in a box and electrocute the...
"Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
```The subject of casts has come up in various forms now and then, and with
D2 nearing completion (or whatever you'd like to call it) I think it
should be discussed properly.

Basically, we can divide (explicit) casts into two groups: safe and
unsafe. The safe ones include

- checked base-to-derived casting of class references
- checked casts between struct types
- numeric conversions

while the unsafe are things like

- pointer reinterpretation
- casting away constness
- cast(public), cf. dsimcha's recent proposal

There are probably others I have forgotten. It pains me that I can use
the same keyword to do these two things:

double pi = 3.14;
int i = cast(int) pi;
int j = *cast(int*) &pi;

The former is very common and ought to be done using some (library)
function with a specific rounding mode, not with a cast. The spec
doesn't even say how numbers are rounded when cast is used.

The latter is a very unsafe operation, which should of course be allowed
in a language like D, but it should be clearly marked as unsafe.

Instead, I propose the above operations be written like this:

int i = to!int(pi);    // The to function already exists in std.conv
int j = cast!int(pi);

I've never liked the syntax of cast expressions in D -- they look like
nothing else in the entire language -- and changing it like this would
make sure no invalid or dangerous casts are left lying around in old
code causing trouble.

What do you think?

-Lars
```
Jul 20 2009
Michiel Helvensteijn <m.helvensteijn.remove gmail.com> writes:
```Lars T. Kyllingstad wrote:

int i = to!int(pi);    // The to function already exists in std.conv

But what does the to function do, exactly? I'd prefer to use one of floor,
round or ceil. Wouldn't you? I'm sure they are available as well.

--
Michiel Helvensteijn
```
Jul 20 2009
"Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
```Michiel Helvensteijn wrote:

int i = to!int(pi);    // The to function already exists in std.conv

But what does the to function do, exactly? I'd prefer to use one of floor,
round or ceil. Wouldn't you? I'm sure they are available as well.

I could perhaps have found a better example than rounding conversions
since there are so many ways to perform those. But that is beside the
point, which was that safe type conversions should be clearly separated
from unsafe ones.

Regarding your question, currently I think std.conv.to just checks for
over-/underflow and performs a cast. :) If such casts were to be
disallowed, it would of course need to be rewritten.

In any case, the documentation for both cast and std.conv.to should say
which rounding mode is used.

-Lars
```
Jul 20 2009
bearophile <bearophileHUGS lycos.com> writes:
```Lars T. Kyllingstad:
Instead, I propose the above operations be written like this:
int i = to!int(pi);    // The to function already exists in std.conv
int j = cast!int(pi);

I think this topic needs quite more thinking, but I agree that the current
casts of D are not good enough and have to be improved. Probably your solution
isn't the best design, but it's looks better than the current one. Merging all
different kinds of casts in a single syntax is bad.

Bye,
bearophile
```
Jul 20 2009
Daniel Keep <daniel.keep.lists gmail.com> writes:
```Lars T. Kyllingstad wrote:
The subject of casts has come up in various forms now and then, and with
D2 nearing completion (or whatever you'd like to call it) I think it
should be discussed properly.

...

Instead, I propose the above operations be written like this:

int i = to!int(pi);    // The to function already exists in std.conv
int j = cast!int(pi);

I've never liked the syntax of cast expressions in D -- they look like
nothing else in the entire language -- and changing it like this would
make sure no invalid or dangerous casts are left lying around in old
code causing trouble.

What do you think?

-Lars

This is a bit of a bug-bear of mine, too.  I originally wrote Tango's
to!(T) template with the express condition that it would only ever
perform value conversions.

We could probably write another template called reinterpret!T or
recast!T or something that explicitly takes a collection of bits and
reinterprets them as another type (ie: the *cast(int*)&pi case).

If we also added, say, objcast!T that only accepted object types, then
we could lock cast(T) away in a box and electrocute the lid.  :D

As for people wanting to control the rounding mode, etc., that's what
functions are for.  My personal position is that stuff like to!T should
exist to do perform a sane default conversion; if you want more control,
you should use a more specialised function.
```
Jul 20 2009
"Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
```Daniel Keep wrote:

The subject of casts has come up in various forms now and then, and with
D2 nearing completion (or whatever you'd like to call it) I think it
should be discussed properly.

...

Instead, I propose the above operations be written like this:

int i = to!int(pi);    // The to function already exists in std.conv
int j = cast!int(pi);

I've never liked the syntax of cast expressions in D -- they look like
nothing else in the entire language -- and changing it like this would
make sure no invalid or dangerous casts are left lying around in old
code causing trouble.

What do you think?

-Lars

This is a bit of a bug-bear of mine, too.  I originally wrote Tango's
to!(T) template with the express condition that it would only ever
perform value conversions.

We could probably write another template called reinterpret!T or
recast!T or something that explicitly takes a collection of bits and
reinterprets them as another type (ie: the *cast(int*)&pi case).

Wouldn't this by necessity have to be a built-in feature of the language?

If we also added, say, objcast!T that only accepted object types, then
we could lock cast(T) away in a box and electrocute the lid.  :D

As for people wanting to control the rounding mode, etc., that's what
functions are for.  My personal position is that stuff like to!T should
exist to do perform a sane default conversion; if you want more control,
you should use a more specialised function.

Recently, Julien Leclercq posted an enhancement request for Phobos
entitled "'std.conv.to': check for a custom 'to' method in classes/structs".

http://d.puremagic.com/issues/show_bug.cgi?id=3189

I think it would be a very good idea to make to!(T) *the* convention for
built-in, standard library and user types. It would make for a unified,
consistent approach to conversions:

double x = 3.14;
MyFloat y = 2.72;

int i = to!int(x);
int j = to!int(y);
string s = to!string(x);
string t = to!string(y);

Beautiful, no? :)

-Lars
```
Jul 21 2009
Daniel Keep <daniel.keep.lists gmail.com> writes:
```Lars T. Kyllingstad wrote:
Daniel Keep wrote:
...

We could probably write another template called reinterpret!T or
recast!T or something that explicitly takes a collection of bits and
reinterprets them as another type (ie: the *cast(int*)&pi case).

Wouldn't this by necessity have to be a built-in feature of the language?

Why would it?

ref T recast(T,U)(ref U v) if( T.sizeof <= U.sizeof )
{
return *cast(T*)&v;
}

Or something similar should be possible.

...

As for people wanting to control the rounding mode, etc., that's what
functions are for.  My personal position is that stuff like to!T should
exist to do perform a sane default conversion; if you want more control,
you should use a more specialised function.

Recently, Julien Leclercq posted an enhancement request for Phobos
entitled "'std.conv.to': check for a custom 'to' method in
classes/structs".

http://d.puremagic.com/issues/show_bug.cgi?id=3189

Tango already does this.  Actually, it goes a few better than that: any
user-defined type can have to(T), to_{type_name} or to{TypeName} members
that it will use to do conversions as well as static from(T),
from_{type_name} or from{TypeName} methods to do reverse conversions.

I think it would be a very good idea to make to!(T) *the* convention for
built-in, standard library and user types. It would make for a unified,
consistent approach to conversions:

double x = 3.14;
MyFloat y = 2.72;

int i = to!int(x);
int j = to!int(y);
string s = to!string(x);
string t = to!string(y);

Beautiful, no? :)

-Lars

Again; why do you think I wrote Tango's to(T) template in the first
place?  :D
```
Jul 21 2009
"Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
```Daniel Keep wrote:
Daniel Keep wrote:
...

We could probably write another template called reinterpret!T or
recast!T or something that explicitly takes a collection of bits and
reinterprets them as another type (ie: the *cast(int*)&pi case).

Wouldn't this by necessity have to be a built-in feature of the language?

Why would it?

ref T recast(T,U)(ref U v) if( T.sizeof <= U.sizeof )
{
return *cast(T*)&v;
}

Or something similar should be possible.

Ah, I misunderstood your "lock cast(T) away in a box and electrocute the
lid" comment to mean that the current cast(T) should be entirely removed
from the language. (Which is something I personally wouldn't be opposed to.)

-Lars
```
Jul 23 2009