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...
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*) π 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
Lars T. Kyllingstad wrote:int i = to!int(pi); // The to function already exists in std.convBut 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
Michiel Helvensteijn wrote:Lars T. Kyllingstad wrote: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. -Larsint i = to!int(pi); // The to function already exists in std.convBut 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.
Jul 20 2009
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
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? -LarsThis 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
Daniel Keep wrote:Lars T. Kyllingstad wrote:Wouldn't this by necessity have to be a built-in feature of the language?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? -LarsThis 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.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
Lars T. Kyllingstad wrote:Daniel Keep wrote: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.... 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?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.... 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=3189I 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? :) -LarsAgain; why do you think I wrote Tango's to(T) template in the first place? :D
Jul 21 2009
Daniel Keep wrote:Lars T. Kyllingstad wrote: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.) -LarsDaniel Keep wrote: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.... 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?
Jul 23 2009