digitalmars.D - safer casts - take II
- Yigal Chripun (37/37) May 13 2008 since the other thread got completely off-topic and lost any connection
- BCS (4/7) May 13 2008 looks good. Excluding the Const stuff (and I've been ignoring all that f...
- Janice Caron (21/24) May 13 2008 Obviously, since I was partly involved in drafting this, I support it.
- terranium (2/4) May 13 2008 I don't think that such redesing is useful.
- Janice Caron (4/5) May 13 2008 Could you be a bit more specific?
- Paul D. Anderson (8/15) May 13 2008 My only concern is the re-use of '!'.
- Yigal Chripun (24/58) May 13 2008 to my defense, I'll note the fact that c++ provides its casts (except of
- Yigal Chripun (15/15) May 13 2008 I've just thought of an analogy to explain the different cast types:
- terranium (9/10) May 13 2008 http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars....
- BCS (7/10) May 13 2008 The proposed dynamic_cast template, can't be implemented safely and effi...
- terranium (2/6) May 13 2008 this should be deemed as sort of legacy functionality, so it need not to...
- BCS (4/15) May 13 2008 As far as I'm concerned it's still an open question if the dynamic_cast ...
- terranium (2/5) May 13 2008 Legaciness has nothing to do with frequency of use. I believe, legacy co...
- BCS (4/14) May 13 2008 So you are saying that the non-throwing cast should be treated as "the w...
- terranium (3/4) May 13 2008 Your argument is big need for if(auto y=cast(Y)x) ?
- BCS (4/12) May 13 2008 Yes, I see a bigger need for that than for the throwing kind.
- terranium (2/3) May 14 2008 In fact, I am the only who argued for throwing cast, it seems like every...
- Janice Caron (16/19) May 15 2008 I don't understand. In the next Phobos release, you will have your
- Bill Baxter (15/21) May 13 2008 I agree with BCS. There's nothing wrong with the null-returning dynamic...
- Bruno Medeiros (6/7) Jun 10 2008 ROFL, best interface name evar :P
- Yigal Chripun (23/42) May 13 2008 You want the RTTI cast to throw on error. I'm personally a bit torn here
- BCS (3/8) May 13 2008 force_cast!(T)
- Dee Girl (3/14) May 13 2008 What is object.d please?
- BCS (3/17) May 13 2008 all the stuff that you can't live without like the definition of Object,...
- terranium (3/8) May 13 2008 There is no need for proposals to implement such a template. My reason i...
- Dee Girl (3/18) May 13 2008 Maybe the way it should work is this. The language provides primitives. ...
- terranium (3/5) May 13 2008 The unwanted one (and forced to) should be unsafe functionality, rather ...
- BCS (7/11) May 13 2008 by that augment, "there is only minor need for /down/ casts, I believe, ...
- terranium (6/7) May 13 2008 void foo(T arg)
- BCS (10/19) May 13 2008 Where would the table be set up? for delegates to work you would need to...
- terranium (3/5) May 13 2008 yes, delegates sould be static functions or member calls
- BCS (6/12) May 13 2008 delegates can't be static functions (function pointers can) and member c...
- Janice Caron (7/7) May 13 2008 The case for dynamic cast is closed. I just heard from the powers that
- terranium (2/11) May 13 2008 I thought it's a known use case (in C# it's used widely and handles valu...
- BCS (2/5) May 13 2008 I've never seen it done in D.
- Dee Girl (3/11) May 13 2008 This is incomplete answer. In my compiler implementation for switch if-e...
- terranium (3/5) May 14 2008 don't forget, with if-else chain you do type check on every element, typ...
- Janice Caron (17/18) May 13 2008 We already have that.
- terranium (2/4) May 13 2008 c++ casts have uniform syntax of templated functions, D cast has syntax ...
- terranium (2/9) May 13 2008 just what I wrote about http://www.digitalmars.com/webnews/newsgroups.ph...
- Janice Caron (4/5) May 13 2008 Seriously - to!(T) is the D standard way of doing convertions that
- Leandro Lucarella (12/14) May 13 2008 It's generally a better idea to keep the original thread topic and start...
- Yigal Chripun (14/23) May 13 2008 come on, that's just hindsight.
- Bill Baxter (12/28) May 13 2008 Seriously, though, it sounds good to me. My initial impression was that...
- Jason House (2/49) May 13 2008
- Yigal Chripun (27/31) May 13 2008 That's a good point I want to address:
- Janice Caron (6/6) May 13 2008 Note that in addition, the ! form would also be the one to use for:
- Joel C. Salomon (27/31) May 14 2008 -----BEGIN PGP SIGNED MESSAGE-----
- Janice Caron (2/3) May 15 2008 Yep.
- Bruno Medeiros (28/65) Jun 10 2008 Sorry I'm late.
since the other thread got completely off-topic and lost any connection to the original discussion, here's a new clean thread, that will hopefully summarize the previous discussion and present the latest proposal so that hopefully more people join the debate without the need to go through all the previous posts (164 posts!). Here goes: the proposal is for a safer cast that will _replace_ the current cast. this is important both for a consistent syntax and to prevent subverting the system with the old style cast. there are there forms of cast: (a) cast(T)something (b) cast!(T)something (c) reinterpret_cast!(T) there is no need for language support for (c) since this can be implemented via a union and this is exactly what this library template does. the only reason for this is to have a standardized name. unless the user really knows what he's doing this should be avoided, since this is the most dangerous form of cast. goals of this design: 1. you can search/grep for all casts in your code. 2. constancy is cast explicitly so no more casting an invariant T to a mutable U in one cast. this prevents bugs. (a) will do would you'll expect in the common case. while (b) is for more "dangerous" casts. it can also be defined in all forms (implicit/explicit) by the user while (b) isn't. if T is a class then (a) uses RTTI cast (down casting) or a user defined conversion, otherwise (a) will do plain conversions like the current cast does. (b) is used for constancy casts and the specific use case of casting pointers to void. (more specific cases could be added in the future) for c++ people this translates to: (a) (T is a class) ? dynamic_cast : static_cast (b) const_cast (c) reinterpret_cast implemented in library also note that cast(T) for classes will return null on failure just like in current D. questions?
May 13 2008
Reply to Yigal,questions?looks good. Excluding the Const stuff (and I've been ignoring all that for months) it seems consistent and reasonably compact. As for the Const stuff, I'll let others pass jugment.
May 13 2008
On 13/05/2008, BCS <ao pathlink.com> wrote:looks good. Excluding the Const stuff (and I've been ignoring all that for months) it seems consistent and reasonably compact. As for the Const stuff, I'll let others pass jugment.Obviously, since I was partly involved in drafting this, I support it. Basically what this means is that, once the change is made, 99% of your code will compile, and maybe 1% wont. (I'm making these numbers up, by the way, just for illustration). So you look at the lines the don't compile, and ponder "Is this a bug, or is it correct?". If you decide it's correct, you change "cast" to "cast!" and recompile, and all should be well. If it /still/ doesn't compile, it's almost certainly a bug in your code. But not neccesarily, because there's still a chance you /might/ be doing two things at once, in which case, if you're really, really sure it's not a bug, you change your code from "cast!(T)" to "cast!(T)cast(U)", where U is some intermediate type (so the safe cast changes the type but not the constancy, and then the danger cast then changes the constancy). Now it should compile. And if it /still/ doesn't compile, it's either a bug or very badly designed code. In the latter case, you can use reinterpret_cast!(T) to force the line to compile. Simply put - this is a tool for finding bugs at compile time. Without this, those bugs could bring your program crashing down at run time. So yes, I love this idea.
May 13 2008
Yigal Chripun Wrote:also note that cast(T) for classes will return null on failure just like in current D.I don't think that such redesing is useful.
May 13 2008
On 13/05/2008, terranium <spam here.lot> wrote:I don't think that such redesing is useful.Could you be a bit more specific? Personally I think finding bugs is /very/ useful, especially since all that is really being asked of the programmer is an exclamation mark.
May 13 2008
Yigal Chripun Wrote:there are there forms of cast: (a) cast(T)something (b) cast!(T)something (c) reinterpret_cast!(T)questions?My only concern is the re-use of '!'. My first thought on reading your proposal was that 'cast!(T)' was some sort of template. I'm sure with a little practice I could get to where I immediately recognize it as a dangerous(!) cast, but it's just one more thing to learn. From my cursory examination of keyword usage I've concluded that the keywords that are problematic ('const', 'enum') are the ones that mean different (but related) things in different usages. I'm not at all convinced that parsimony in keywords is a good thing, but that seems to be a minority view (and it isn't Walter's view, as far as I can tell). We're a little more accustomed to re-definition of symbols, especially in a new context, but this isn't new -- it's a variable name followed by a '!'. Having said that, I don't have an alternative notation. Perhaps a long keyword llike 'const_cast', 'invariant_cast', etc., similar to the 'reinterpret_cast' usage. I do think it's a good idea, though to have the separate types of casts called out. Paul
May 13 2008
Paul D. Anderson wrote:Yigal Chripun Wrote:to my defense, I'll note the fact that c++ provides its casts (except of course the legacy C syntax) with a template syntax too, even though they don't have to be implemented in terms of templates. You can ask Walter how it's implemented in DMC. and it has some similarity in meaning as well, in a way it does behave like a template since the output is parametrized on the input type T. even though the cast isn't really a template, i think that both meanings are suitable here. look at it like this: cast(T) has similarities with a function in that it's make runtime checks for an RTTI cast for example, or behaves like a function that converts a value to a different type. the cast!(T) on the other hand is more in the realm of the static world of the compiler. it doesn't do all the checks the cast(T) does and in a way is more low-level. the reinterpret cast is a special case. it's very unsafe and very low-level and I wouldn't even provide it at all in the proposal since the experienced OS writer (as an example) which needs this feature can implement it himself via unions. the only benefit of providing it in the library is to have a standardized name for it. it should be discouraged and accompanied with warnings in the docs. since D is a Systems programming language, it's still possible to use it, only you need to be damn sure you know what you're doing when subverting the type system like that.there are there forms of cast: (a) cast(T)something (b) cast!(T)something (c) reinterpret_cast!(T)questions?My only concern is the re-use of '!'. My first thought on reading your proposal was that 'cast!(T)' was some sort of template. I'm sure with a little practice I could get to where I immediately recognize it as a dangerous(!) cast, but it's just one more thing to learn. From my cursory examination of keyword usage I've concluded that the keywords that are problematic ('const', 'enum') are the ones that mean different (but related) things in different usages. I'm not at all convinced that parsimony in keywords is a good thing, but that seems to be a minority view (and it isn't Walter's view, as far as I can tell). We're a little more accustomed to re-definition of symbols, especially in a new context, but this isn't new -- it's a variable name followed by a '!'. Having said that, I don't have an alternative notation. Perhaps a long keyword llike 'const_cast', 'invariant_cast', etc., similar to the 'reinterpret_cast' usage. I do think it's a good idea, though to have the separate types of casts called out. Paul
May 13 2008
I've just thought of an analogy to explain the different cast types: [take this with a grain of salt, it's not meant to be discussed seriously] casts are like doom cheats. the ones we used in doom 2 when we were just kids with a 486 computer. (my first real PC. I had a 386 which broke down after a few months which was then replaced to this model) cast(T) gives you a one time bonus amount of ammo. in a very hard level this can be understandable. cast!(T) give you 150% health. this is a much more serious cheat which in multi-player mode would be frowned upon unless everyone apply the same cheat, of course ;) reinterpret_cast!(T) is god mode and no one will want to play with you like that. this is serious cheating you'll only use in single-player mode. I'm sure I can Google the actual codes for those cheats ;) the must be documented somewhere... --Yigal
May 13 2008
Janice Caron Wrote:Could you be a bit more specific?http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=71111 my proposal would be to make cast safer 1) throw InvalidCastException on invalid cast 2) keep const const_cast, dynamic_cast, static_cast, reinterpret_cast templates can be implemented using this safe cast, they can be inefficient and ugly - it's normal, because they normally should not be used. This will break existing code a little 1) if(auto x=cast(X)y) will probably throw in a predicted location, workaround - when porting, replace cast with dynamic_cast template (which should be provided by standard library for porting legacy code) 2) won't compile if mutability is used - easy to fix.
May 13 2008
Reply to terranium,1) if(auto x=cast(X)y) will probably throw in a predicted location, workaround - when porting, replace cast with dynamic_cast template (which should be provided by standard library for porting legacy code)The proposed dynamic_cast template, can't be implemented safely and efficiently with the primitives you propose.* The primitives you propose can be safely and efficiently implemented with the ones Yigal proposed. *You either get a redundant downcast check, invoke the exception handling system or you need to use reinterpret_cast.
May 13 2008
BCS Wrote:The proposed dynamic_cast template, can't be implemented safely and efficiently with the primitives you propose.* *You either get a redundant downcast check, invoke the exception handling system or you need to use reinterpret_cast.this should be deemed as sort of legacy functionality, so it need not to be efficient.
May 13 2008
Reply to terranium,BCS Wrote:As far as I'm concerned it's still an open question if the dynamic_cast or force_cast (by whatever name) will be used more often. So I don't see how you can call it legacy.The proposed dynamic_cast template, can't be implemented safely and efficiently with the primitives you propose.* *You either get a redundant downcast check, invoke the exception handling system or you need to use reinterpret_cast.this should be deemed as sort of legacy functionality, so it need not to be efficient.
May 13 2008
BCS Wrote:As far as I'm concerned it's still an open question if the dynamic_cast or force_cast (by whatever name) will be used more often. So I don't see how you can call it legacy.Legaciness has nothing to do with frequency of use. I believe, legacy code is used more often, in fact, you're right here. Windows ANSI API is a good example. Total commander... :) Windows itself has workarounds for bugs in MS Office...
May 13 2008
Reply to terranium,BCS Wrote:So you are saying that the non-throwing cast should be treated as "the way we did it before we knew better"? If you want to go that way, in order to convince me, you will need to demonstrate a better way. So far no one has.As far as I'm concerned it's still an open question if the dynamic_cast or force_cast (by whatever name) will be used more often. So I don't see how you can call it legacy.Legaciness has nothing to do with frequency of use. I believe, legacy code is used more often, in fact, you're right here. Windows ANSI API is a good example. Total commander... :) Windows itself has workarounds for bugs in MS Office...
May 13 2008
BCS Wrote:you will need to demonstrate a better way. So far no one has.Your argument is big need for if(auto y=cast(Y)x) ? http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=71729
May 13 2008
Reply to terranium,BCS Wrote:Yes, I see a bigger need for that than for the throwing kind. I guess if you can convince me that I am in the minority here you might have something, but just saying you never use them won't do it.you will need to demonstrate a better way. So far no one has.Your argument is big need for if(auto y=cast(Y)x) ? http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmar s.D&article_id=71729
May 13 2008
BCS Wrote:I guess if you can convince me that I am in the minority hereIn fact, I am the only who argued for throwing cast, it seems like everyone else is against my proposal, so the result is obvious.
May 14 2008
On 14/05/2008, terranium <spam here.lot> wrote:BCS Wrote: > I guess if you can convince me that I am in the minority here In fact, I am the only who argued for throwing cast, it seems like everyone else is against my proposal, so the result is obvious.I don't understand. In the next Phobos release, you will have your wish. to!(T) will work as a throwing dynamic cast. It looks to me like you've actually got what you wanted. What's the problem? It would be very, very impractical to make cast(T) itself throw, because it would break a lot of a code. Obviously, my/Yigal's probosal will itself break lots of code, but in our case, the fix of adding an exclamation mark to the offending line will make it compile again, almost all of the time. But if cast(T) were to suddenly change its behavior to start throwing, there would be no compile errors for using it - just lots of runtime exceptions generated by existing code. And even once the cause is discovered, it's not clear how existing code would have to be rewritten in order to carry on working. The way I see it, the fact that you've got to!(T) coming means that you can write your code in the way that you want it, but also so can everyone else. What's wrong with that?
May 15 2008
terranium wrote:BCS Wrote:I agree with BCS. There's nothing wrong with the null-returning dynamic cast. It's exactly what dynamic_cast does in C++. Dynamic casts are particularly useful when working with interfaces in D, I think. You've got a big pool of objects and you get one and want to ask "Hey, object, do you implement the IHasCheezburger interface?" so you just cast to IHasCheezburger and do something if it does, something else if it doesn't. There is nothing "exceptional" happening there, so it doesn't make sense to throw an exception. I don't really understand what you were getting at with your hashtable example in your other post. But it sounds like you're saying we should re-implement a subset of the down-casting functionality that is already present in D objects instead of using the built-in dynamic cast capability. Why should we do that if D already manages it for us? --bbyou will need to demonstrate a better way. So far no one has.Your argument is big need for if(auto y=cast(Y)x) ? http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=71729
May 13 2008
Bill Baxter wrote:ask "Hey, object, do you implement the IHasCheezburger interface?" soROFL, best interface name evar :P (it's funny *and* follows my preferred name conventions) -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jun 10 2008
terranium wrote:Janice Caron Wrote:You want the RTTI cast to throw on error. I'm personally a bit torn here since on the one hand I do see your point and it is more "clean" for some examples. on the other hand it adds a performance penalty the others do not want. Casts shouldn't be normally used and if you do use them then you should pay the performance price, right? this current proposal suits everyone in that you can simply define a template my_cast that will call the cast(T) operator and on null will throw an exception. maybe a helper template like this could be added to the proposal as well since we already added the reinterpret_cast in a library form too. so D will have two basic language level constructs and two additional library helper templates: built into the language: cast(T) cast!(T) import std.cast for this: [the name is just an example, of course] reinterpret_cast!(T) strong_cast!(T) // like cast(T) only throws on error I don't add this to the "official" proposal yet, this is still just some thoughts not finalized into anything formal. feel free to discuss this and propose names for the strong_cast!(T) template.Could you be a bit more specific?http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=71111 my proposal would be to make cast safer 1) throw InvalidCastException on invalid cast 2) keep const const_cast, dynamic_cast, static_cast, reinterpret_cast templates can be implemented using this safe cast, they can be inefficient and ugly - it's normal, because they normally should not be used. This will break existing code a little 1) if(auto x=cast(X)y) will probably throw in a predicted location, workaround - when porting, replace cast with dynamic_cast template (which should be provided by standard library for porting legacy code) 2) won't compile if mutability is used - easy to fix.
May 13 2008
Reply to Yigal,I don't add this to the "official" proposal yet, this is still just some thoughts not finalized into anything formal. feel free to discuss this and propose names for the strong_cast!(T) template.force_cast!(T) and I'd put them in object.d
May 13 2008
BCS Wrote:Reply to Yigal,What is object.d please? Only now I understood something. It was in a early post. There is enforce already in std.contracts. Then enforce(cast(T) x) works. It is longer than force_cast!(T) x. But I prefer it because it respects composition principle. If I know what cast does and what enforce does then I know what enforce(cast(T) x) does. Thank you, Dee GirlI don't add this to the "official" proposal yet, this is still just some thoughts not finalized into anything formal. feel free to discuss this and propose names for the strong_cast!(T) template.force_cast!(T) and I'd put them in object.d
May 13 2008
Reply to Dee,BCS Wrote:all the stuff that you can't live without like the definition of Object, TypeInfo 'n friends, the Error and Exception class and whatnot.Reply to Yigal,What is object.d please?I don't add this to the "official" proposal yet, this is still just some thoughts not finalized into anything formal. feel free to discuss this and propose names for the strong_cast!(T) template.force_cast!(T) and I'd put them in object.d
May 13 2008
Yigal Chripun Wrote:You want the RTTI cast to throw on error. it adds a performance penaltyI don't think so. How does it add a performance penalty?this current proposal suits everyone in that you can simply define a template my_cast that will call the cast(T) operator and on null will throw an exception.There is no need for proposals to implement such a template. My reason is to force people to use safe cast, if you just write safe cast with template function, ugly syntax, ugly name, performance penalty (additional check for null) - no one will use it, even I.
May 13 2008
terranium Wrote:Janice Caron Wrote:Maybe the way it should work is this. The language provides primitives. Library constructs from primitives. But cast that throws is not good primitive. Because you need expensive operation to implement cast that returns null on failure. A better primitive is cast that returns null. You can implement cast that throws in a library. One more opinion I have. The pattern in Java with if (a isa Type) { Type t = (Type) a; ... } is very clunky. It is not inefficient. Because Java compilers all have special case for the sequence (peephole optimization). But it is verbose programming style with duplication. If you use cast that throws in D then you are forced in that pattern. Another reason cast that throws is not good. Thank you, Dee GirlCould you be a bit more specific?http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=71111 my proposal would be to make cast safer 1) throw InvalidCastException on invalid cast 2) keep const const_cast, dynamic_cast, static_cast, reinterpret_cast templates can be implemented using this safe cast, they can be inefficient and ugly - it's normal, because they normally should not be used. This will break existing code a little 1) if(auto x=cast(X)y) will probably throw in a predicted location, workaround - when porting, replace cast with dynamic_cast template (which should be provided by standard library for porting legacy code) 2) won't compile if mutability is used - easy to fix.
May 13 2008
Dee Girl Wrote:But cast that throws is not good primitive. Because you need expensive operation to implement cast that returns null on failure.There is only minor need for this silent cast, I believe, so 1) since this is rarely needed, performance penalty is acceptable, 2) if you don't want performance penalty, avoid need for silent cast.If you use cast that throws in D then you are forced in that pattern.The unwanted one (and forced to) should be unsafe functionality, rather than safe. The type switch from your example can be implemented in a more efficient way with a type hashtable.
May 13 2008
Reply to terranium,There is only minor need for this silent cast, I believe, so 1) since this is rarely needed, performance penalty is acceptable,by that augment, "there is only minor need for /down/ casts, I believe, since" the throwing kind is even rarer than the non throwing kind. In my experience that is the case. (note: paraphrased to draw attention to the parallel nature of the counter argument)The type switch from your example can be implemented in a more efficient way with a type hashtable.I'm not seeing it, example please?
May 13 2008
BCS Wrote:I'm not seeing it, example please?void foo(T arg) { auto handle=myhashtable[arg.classinfo]; //handle can be data or delegate for increased functionality }
May 13 2008
Reply to terranium,BCS Wrote:Where would the table be set up? for delegates to work you would need to set up the table every time the function is called (to get the context pointer right). The next best thing would be something like this: switch(myhashtable[arg.classinfo]) { case ClassEnum: ... } but then we might as well let switch take a classinfo struct and avoid the enum. But that looks just plain ugly.I'm not seeing it, example please?void foo(T arg) { auto handle=myhashtable[arg.classinfo]; //handle can be data or delegate for increased functionality }
May 13 2008
BCS Wrote:Where would the table be set up?wherever you want, static constructor is a good choise, maybe static initializer will work too.for delegates to workyes, delegates sould be static functions or member calls
May 13 2008
Reply to terranium,BCS Wrote:delegates can't be static functions (function pointers can) and member calls wouldn't give me access to local variables. even if all that is addressed, the best implementation of your proposal is a lot more hackish than if(auto a = cast(A)b) ...for delegates to workyes, delegates sould be static functions or member calls
May 13 2008
The case for dynamic cast is closed. I just heard from the powers that be that std.conv.to will support an exception-throwing dynamic cast in the next Phobos. So it's dst = cast(T)src; // non-throwing dynamic cast dst = to!(T)(src); // throwing dynamic cast Hopefully everyone's happy now. Does anyone have a problem with the proposal /apart/ from dynamic cast failure?
May 13 2008
Reply to Janice,Does anyone have a problem with the proposal /apart/ from dynamic cast failure?no
May 13 2008
Janice Caron Wrote:Hopefully everyone's happy now.of course, if you're happy, everyone's happy :)
May 14 2008
terranium Wrote:BCS Wrote:too).I'm not seeing it, example please?void foo(T arg) { auto handle=myhashtable[arg.classinfo]; //handle can be data or delegate for increased functionality }
May 13 2008
Reply to terranium,value types too).I've never seen it done in D.
May 13 2008
terranium Wrote:Dee Girl Wrote:In my code I use often capability test. So cast that returns null is good for me. If I want to make sure I check on my side. In those cases I assign it to a variable that lives longer. So there are few casts that should throw in my code. If you want to make general statement about frequency of cast at best you collect data from programs.But cast that throws is not good primitive. Because you need expensive operation to implement cast that returns null on failure.There is only minor need for this silent cast, I believe, so 1) since this is rarely needed, performance penalty is acceptable, 2) if you don't want performance penalty, avoid need for silent cast.This is incomplete answer. In my compiler implementation for switch if-else test is fast for 4 elements or less. Then linear search is fast up to 32 elements. Only then hash is best. But many variables influence this. Dee GirlIf you use cast that throws in D then you are forced in that pattern.The unwanted one (and forced to) should be unsafe functionality, rather than safe. The type switch from your example can be implemented in a more efficient way with a type hashtable.
May 13 2008
Dee Girl Wrote:In my code I use often capability test.I see no problem, if you want it, use it.Then linear search is fast up to 32 elements. Only then hash is best.don't forget, with if-else chain you do type check on every element, typecheck is implemented as looping through vtable. With type hashtable you process typeinfo only once, then you search for its hash.
May 14 2008
On 13/05/2008, terranium <spam here.lot> wrote:1) throw InvalidCastException on invalid castWe already have that. import std.conv; dst = to!(T)(src); I quote: <quote> The to family of functions converts a value from type Source to type Target. The source type is deduced and the target type must be specified, for example the expression to!(int)(42.0) converts the number 42 from double to int. The conversion is "safe", i.e., it checks for overflow; to!(int)(4.2e10) would throw the ConvOverflowError exception. Overflow checks are only inserted when necessary, e.g., to!(double)(42) does not do any checking because any int fits in a double. </quote> If std.conv.to doesn't do dynamic casting, it can easily be made to, so your base is already covered.
May 13 2008
Yigal Chripun Wrote:to my defense, I'll note the fact that c++ provides its casts (except of course the legacy C syntax) with a template syntax tooc++ casts have uniform syntax of templated functions, D cast has syntax of prefix operator, what syntax will have cast!()?
May 13 2008
Janice Caron Wrote:We already have that. import std.conv; dst = to!(T)(src); so your base is already covered.just what I wrote about http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=71725
May 13 2008
On 13/05/2008, terranium <spam here.lot> wrote:just what I wrote about http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=71725Seriously - to!(T) is the D standard way of doing convertions that will throw an exception on failure. It is the right function for dynamic-cast-with-throw.
May 13 2008
Yigal Chripun, el 13 de mayo a las 15:58 me escribiste:since the other thread got completely off-topic and lost any connection to the original discussion, here's a new clean thread, that willIt's generally a better idea to keep the original thread topic and start a new one with the new topic, because this way you have the (already polluted) "safer casts" thread splitted in 2 threads, making even more difficult to follow it. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Corrí muchas carreras, tratando de alcanzarte a vos. Pero corría sólo y siempre salí último.
May 13 2008
Leandro Lucarella wrote:Yigal Chripun, el 13 de mayo a las 15:58 me escribiste:come on, that's just hindsight. I agree of course that one thread for the topic is better than two, but since we are already in a situation with a thread that contains about 170 posts most of which are off topic, a new clearly named thread ("safer cast -take II" clearly suggests what the content is IMO) is better than just continue posting in the older thread. what else do you want me to do?? Go back in time and repost in a different thread?? since we already have one polluted (huge) thread I do not wish to discuss this here further, if you want, you can mail me personally and continue this discussion there (although i don't see a reason to do this) now, back on topic! what's your opinion on the proposal? please share your thoughts for the betterment of the D community. --Yigalsince the other thread got completely off-topic and lost any connection to the original discussion, here's a new clean thread, that willIt's generally a better idea to keep the original thread topic and start a new one with the new topic, because this way you have the (already polluted) "safer casts" thread splitted in 2 threads, making even more difficult to follow it.
May 13 2008
Yigal Chripun wrote:since the other thread got completely off-topic and lost any connection to the original discussion, here's a new clean thread, that will hopefully summarize the previous discussion and present the latest proposal so that hopefully more people join the debate without the need to go through all the previous posts (164 posts!). Here goes: the proposal is for a safer cast that will _replace_ the current cast. this is important both for a consistent syntax and to prevent subverting the system with the old style cast. there are there forms of cast: (a) cast(T)something (b) cast!(T)somethingNo no. "super cast(T)something" is what you're looking for. :-) [1](c) reinterpret_cast!(T)Seriously, though, it sounds good to me. My initial impression was that basically we needed just one alternative form of cast. Leave cast(T) for the "yes I'm casting but it's not a big deal" forms, and make some new form for the "Lookout! Crazy guy with a cast who's not afraid to use it, here!" And that's pretty much what you folks seem to have settled on. (Discounting the third form, reinterpret_cast, since it's just a library function -- but a good one to have, I'll agree) [1] (For those who don't recall "invariant" was slated to be called "super const" for a while...) --bb
May 13 2008
Long ago in one of the const threads, a few people settled on cast(break const) for what I think you're calling cast!(T). I like that better than using template syntax to mean less safe. Yigal Chripun Wrote:since the other thread got completely off-topic and lost any connection to the original discussion, here's a new clean thread, that will hopefully summarize the previous discussion and present the latest proposal so that hopefully more people join the debate without the need to go through all the previous posts (164 posts!). Here goes: the proposal is for a safer cast that will _replace_ the current cast. this is important both for a consistent syntax and to prevent subverting the system with the old style cast. there are there forms of cast: (a) cast(T)something (b) cast!(T)something (c) reinterpret_cast!(T) there is no need for language support for (c) since this can be implemented via a union and this is exactly what this library template does. the only reason for this is to have a standardized name. unless the user really knows what he's doing this should be avoided, since this is the most dangerous form of cast. goals of this design: 1. you can search/grep for all casts in your code. 2. constancy is cast explicitly so no more casting an invariant T to a mutable U in one cast. this prevents bugs. (a) will do would you'll expect in the common case. while (b) is for more "dangerous" casts. it can also be defined in all forms (implicit/explicit) by the user while (b) isn't. if T is a class then (a) uses RTTI cast (down casting) or a user defined conversion, otherwise (a) will do plain conversions like the current cast does. (b) is used for constancy casts and the specific use case of casting pointers to void. (more specific cases could be added in the future) for c++ people this translates to: (a) (T is a class) ? dynamic_cast : static_cast (b) const_cast (c) reinterpret_cast implemented in library also note that cast(T) for classes will return null on failure just like in current D. questions?
May 13 2008
Jason House wrote:Long ago in one of the const threads, a few people settled on cast(break const) for what I think you're calling cast!(T). I like that better than using template syntax to mean less safe.That's a good point I want to address: initially this is exactly what I proposed, albeit with some minor changes to syntax. [that was: cast(!const) where the ! was meant to be a "not" similar to your break. the problem is that it's not flexible enough. how do you cast the following: const(invariant(C)*)* ==> const(C*)* ? this is a contrived example of course, but with cast!(T) you can just use: auto newVal = cast!(const(C*)*)oldVal; this works since this passes the following simple test: if you remove all invariant/const modifiers in both the source and target types you need to get the exact same type. this is to make sure you only change constancy and not the type. in the above case you'll get: ((C)*)* ==> (C*)* and those two are identical. this only changes constancy and thus legal. had you tried to also change type you'd get an exception. with cast(break const) or cast(!const) this is not possible with just one cast. that kind of shortcut may be considered as well, but since you can always just specify the new constancy of the type this adds very little benefit but adds another syntax rule to the language. I think that Walter probably won't agree to add such a syntax rule and bloat the language without proper justification. with this I 100% sure that I prefer the minimalist approach and do not want to include this in the proposal. feel free to discuss this issue too and suggest use-cases where you think this syntax is needed.
May 13 2008
Note that in addition, the ! form would also be the one to use for: void[] p; T[] q = cast!(T[])p; So it's not /just/ removal of const that "danger cast" is for. It's also for casting from void to non-void. For that reason, calling it "break const" would be highly counterintuitive.
May 13 2008
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Yigal Chripun wrote:there are there forms of cast: (a) cast(T)something (b) cast!(T)something (c) reinterpret_cast!(T)So, for example, given the following definitions: class A {…} class B : A {…} class C : A {…} class D {…} we can write: const A ac; auto a = cast!(A)a; and: B b0; auto a = cast(A)b0; auto b = cast(B)a; // should succeed auto c = cast(C)a; // c is null and: A a; auto d = reinterpret_cast(D)a; // legal but unpredictable Are these all the intended uses? —Joel S. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFIKwxozLx4GzBL9dYRAlJMAJwIHL+xCS4ZYDk56JOj6yw4LocF/wCffK/e GSYe5sbxojtr6Ha47jyLP7E= =/jDq -----END PGP SIGNATURE-----
May 14 2008
On 14/05/2008, Joel C. Salomon <joelcsalomon gmail.com> wrote:Are these all the intended uses?Yep.
May 15 2008
Sorry I'm late. First of all, I agree with the general principle that D's cast system should be more safe. But there are some aspects of your proposal I don't agree. First is the cast(...) vs. cast!(...) syntax. I strongly disagree with it, I don't think such constructs should have such a similar syntax, particularly sharing the same base name, yet one looking like a function call, and the other like a template. I know that the rationale for cast!(...) would be to indicate that this is a compile time operation, unlike cast(...) but I still don't like it. But even further than that, I agree with Jason, in that the constancy cast construct should not require the type to cast, but just the const modifiers. That is, there should only be the forms "cast(const)", "cast(invariant)", and "cast(!const)". (Altough cast(!const) should really be called cast(mutable) , but that's another issue, about keywords) Some points were raised against it: Yigal Chripun wrote:Jason House wrote:use:Long ago in one of the const threads, a few people settled on cast(break const) for what I think you're calling cast!(T). I like that better than using template syntax to mean less safe.That's a good point I want to address: initially this is exactly what I proposed, albeit with some minor changes to syntax. [that was: cast(!const) where the ! was meant to be a "not" similar to your break. the problem is that it's not flexible enough. how do you cast the following: const(invariant(C)*)* ==> const(C*)* ? this is a contrived example of course, but with cast!(T) you can justauto newVal = cast!(const(C*)*)oldVal; this works since this passes the following simple test: if you remove all invariant/const modifiers in both the source and target types you need to get the exact same type. this is to make sure you only change constancy and not the type. in the above case you'll get: ((C)*)* ==> (C*)* and those two are identical. this only changes constancy and thus legal. had you tried to also change type you'd get an exception. with cast(break const) or cast(!const) this is not possible with just one cast. that kind of shortcut may be considered as well, but since you can always just specify the new constancy of the type this adds very little benefit but adds another syntax rule to the language. I think that Walter probably won't agree to add such a syntax rule and bloat the language without proper justification. with this I 100% sure that I prefer the minimalist approach and do not want to include this in the proposal. feel free to discuss this issue too and suggest use-cases where you think this syntax is needed.Well, it's true that you couldn't directly do that case "with just one cast", but one could define a template that did it with just one call: const(invariant(C)*)* foo; auto bar = const_cast!(const(C*)*, foo); So I don't think that would be a problem, right? Janice Caron wrote:Note that in addition, the ! form would also be the one to use for: void[] p; T[] q = cast!(T[])p; So it's not /just/ removal of const that "danger cast" is for. It's also for casting from void to non-void. For that reason, calling it "break const" would be highly counterintuitive.reinterpret_cast would serve that purpose just fine, wouldn't it? -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jun 10 2008