D - casts
- Pavel Minayev (12/12) Nov 23 2001 The specification says that all casts of objects are
- Walter (4/16) Nov 23 2001 But all the "is" operator would do is check the cast for a null return. ...
- Pavel Minayev (5/7) Nov 23 2001 It
- Walter (3/10) Nov 23 2001 ok, I understand.
- Russell Borogove (19/32) Nov 24 2001 Whether we have casts return null or throw exception, it's possible
- Pavel Minayev (18/24) Nov 24 2001 The problem is somewhat different. In general, I suppose that an object
- Russell Borogove (18/35) Nov 24 2001 I do understand your point, but some people design their code differentl...
- Pavel Minayev (30/45) Nov 24 2001 IMHO it's better to make a separate operator to check for the class.
- Russell Borogove (15/29) Nov 24 2001 It's possible that I've been poisoned by years of working with
- Pavel Minayev (14/27) Nov 24 2001 It's a common style that I use as well, I just ain't satisfied
- Walter (5/10) Nov 25 2001 No, I had missed that.
- Sean L. Palmer (12/24) Nov 29 2001 This sounds like fine syntax to me. I still think that once you've
- Sean L. Palmer (7/22) Nov 29 2001 Nope, that won't catch the case where entity is actually a class derived
- a (30/60) Nov 29 2001 This post just gave me a thought. It probably isn't appropriate for D
- Russell Borogove (9/38) Nov 29 2001 I like it, but I will be perpetually confused because I'll think of
- a (10/50) Nov 29 2001 I saw it as meaning the child class was everything the parent was and
- Russ Lewis (15/26) Nov 29 2001 If you think of a class as a set of objects, then the parent is the larg...
- a (9/28) Nov 29 2001 It would have to be an arbitrary rule. Just pick a semantic model. I
- Russ Lewis (9/14) Nov 30 2001 It's thinking about this that caused me to ponder the greatestCommonClas...
- a (20/33) Nov 30 2001 A nifty idea, but it seems more appropriate in a dynamically typed
- Russ Lewis (27/60) Nov 30 2001 Sure it does!
- a (27/94) Nov 30 2001 I hadn't thought of that. I don't know if switch was intended to work
- Russ Lewis (27/27) Dec 01 2001 How about this class hierarchy:
- a (20/49) Dec 01 2001 I see how it works, but it is not very general purpose. If Apple and
- Russ Lewis (13/31) Dec 03 2001 But if the programmer has declared (by the class structure) that Fruit a...
- Russ Lewis (8/13) Dec 01 2001 heh. Well, it can be an if...else if otherwise. Would be cool if switc...
- Sean L. Palmer (8/16) Dec 02 2001 Walter says D's switch statement allows strings. I don't see why it has...
- a (6/27) Dec 02 2001 I believe if was suppose to be the high level equivalent of a
- Sean L. Palmer (17/22) Dec 03 2001 There's nothing stopping a D compiler from turning a suitable switch int...
- Pavel Minayev (7/14) Dec 03 2001 compare
- Walter (11/18) Dec 05 2001 compare
- Russell Borogove (4/16) Dec 05 2001 Will that break structs that include class members?
- Pavel Minayev (6/10) Dec 05 2001 I've also thought of it... maybe a built-in assign() method
- Russell Borogove (10/26) Dec 05 2001 As long as the referenced object gets its refcount increased, I suppose
- Pavel Minayev (4/6) Dec 05 2001 Ref counts? I've always thought there are none in D,
- Sean L. Palmer (20/38) Dec 06 2001 Walter, the more I hear you talk, the more I think D may not be for me.
- Walter (16/61) Dec 11 2001 It's entirely possible we have different philosophies on what makes a gr...
- Sean L. Palmer (13/19) Dec 02 2001 The ability to store an object's type to a file and then once you reload
- Pavel Minayev (4/4) Dec 02 2001 Speaking of virtual constructors (which are probably
- Russ Lewis (16/16) Nov 29 2001 Another idea...it might be useful to include some sort of "greatest comm...
The specification says that all casts of objects are done with run-time checking - and that's good - and if the type doesn't match, null is returned! I don't think it's a good idea, since you could make a cast in one place of the program, and any error would get unnoticed, and then try to use the null-pointer in other place somewhere hundred lines after... could be VERY hard to find the actual reason of crash. Maybe it's better to throw an exception on bad cast - like it's done in C++ (and in Delphi by the way). On other hand, we need an "is" or "instanceof" operator then...
Nov 23 2001
But all the "is" operator would do is check the cast for a null return. It seems redundant. "Pavel Minayev" <evilone omen.ru> wrote in message news:9tmb6p$2snv$1 digitaldaemon.com...The specification says that all casts of objects are done with run-time checking - and that's good - and if the type doesn't match, null is returned! I don't think it's a good idea, since you could make a cast in one place of the program, and any error would get unnoticed, and then try to use the null-pointer in other place somewhere hundred lines after... could be VERY hard to find the actual reason of crash. Maybe it's better to throw an exception on bad cast - like it's done in C++ (and in Delphi by the way). On other hand, we need an "is" or "instanceof" operator then...
Nov 23 2001
"Walter" <walter digitalmars.com> wrote in message news:9tmi2t$31hm$1 digitaldaemon.com...But all the "is" operator would do is check the cast for a null return.Itseems redundant.No. My proposal is to throw an exception on bad cast rather than return null, to prevent further errors.
Nov 23 2001
ok, I understand. "Pavel Minayev" <evilone omen.ru> wrote in message news:9tni37$ir0$1 digitaldaemon.com..."Walter" <walter digitalmars.com> wrote in message news:9tmi2t$31hm$1 digitaldaemon.com...But all the "is" operator would do is check the cast for a null return.Itseems redundant.No. My proposal is to throw an exception on bad cast rather than return null, to prevent further errors.
Nov 23 2001
Pavel Minayev wrote:"Walter" <walter digitalmars.com> wrote in message news:9tmi2t$31hm$1 digitaldaemon.com...Whether we have casts return null or throw exception, it's possible to wrap the language's standard cast in order to simulate the other behavior. Considered from that point, it's (a) slightly easier to have the standard cast return null and write a wrapper that throws than vice versa[1], and (b) faster in run-time to return null than to throw an exception. The same argument can be made regarding memory allocation[2], of course, or file I/O, and then we're back to testing the return value from every function.[3] So it really comes down to whether or not you consider throwing a bunch of objects which have "void in common" into the same container to be good programming practice, or no. -RB [1] Two ways come to mind: "if (obj == null) throw" or "obj->Method()". [2] Which is why my memory manager offers an interface which includes a "this allocation is non-critical, so don't work too hard, and return NULL if you have to" flag as an option. [3] ...the way god intended you to write code.But all the "is" operator would do is check the cast for a null return.Itseems redundant.No. My proposal is to throw an exception on bad cast rather than return null, to prevent further errors.
Nov 24 2001
"Russell Borogove" <kaleja estarcion.com> wrote in message news:3BFF539D.40808 estarcion.com...Whether we have casts return null or throw exception, it's possible to wrap the language's standard cast in order to simulate the other behavior. Considered from that point, it's (a) slightly easier to have the standard cast return null and write a wrapper that throws than vice versa[1], and (b) faster in run-time to return null than to throw an exception.The problem is somewhat different. In general, I suppose that an object to be casted should always conform to the new type, for classes at least - what are you going to do with a wrongly-casted pointer anyhow? So it is a deliberate error, and is supposed to never occur in a final version of the program (dreams...). So in most cases you don't in fact write any checking code, you just rely on it always working properly. And when debugging the program, if the cast is wrong, you'd most likely want to know about it - and you will if it throws an exception. On other hand, null pointer is just silently accepted and at some later point you get an access violation. If you do the cast in a function call, and the function transfers it further... you could end with an exception in some completely different module (long, long ago in a function far, far away =)) staring on the screen and thinking, "WHAT the hell can be wrong with this???" - well you might know the feeling.... Or maybe introduce two cast keywords - one for safe and one for unsafe cast? Pascal syntax, maybe? LOL
Nov 24 2001
Pavel Minayev wrote:"Russell Borogove" <kaleja estarcion.com> wrote in message news:3BFF539D.40808 estarcion.com...I do understand your point, but some people design their code differently. It may or may not be an error. Say we're talking about game code, and you're iterating over a collection of objects derived from class Entity, checking to see if they're castable to class ThinkingEntity, and if so, calling their Think() method. There are any number of good reasons to maintain all your entities in a single collection even though they're not completely compatible in some contexts. The alternative is to bloat the base class with a bunch of virtual functions which will be no-op in the majority of cases. (Not to mention that sometimes you won't be allowed to mess with the base class.) My point is that from a single cast-else-null primitive, you can build cast-else-throw and and is-safe-to-cast? operations easily and efficiently; if the primitive is cast-else-throw, then the is-safe-to-cast? operation _must_ (as you noted) be provided by the language in a way that doesn't internally generate an exception, for performance reasons. -RBWhether we have casts return null or throw exception, it's possible to wrap the language's standard cast in order to simulate the other behavior. Considered from that point, it's (a) slightly easier to have the standard cast return null and write a wrapper that throws than vice versa[1], and (b) faster in run-time to return null than to throw an exception.The problem is somewhat different. In general, I suppose that an object to be casted should always conform to the new type, for classes at least - what are you going to do with a wrongly-casted pointer anyhow? So it is a deliberate error, and is supposed to never occur in a final version of the program (dreams...).
Nov 24 2001
"Russell Borogove" <kaleja estarcion.com> wrote in message news:3BFFFBB3.4070707 estarcion.com...It may or may not be an error. Say we're talking about game code, and you're iterating over a collection of objects derived from class Entity, checking to see if they're castable to class ThinkingEntity, and if so, calling their Think() method. There are any number of good reasons to maintain all your entities in a single collection even though they're not completely compatible in some contexts. The alternative is to bloat the base class with a bunch of virtual functions which will be no-op in the majority of cases. (Not to mention that sometimes you won't be allowed to mess with the base class.)IMHO it's better to make a separate operator to check for the class. Again, an excelent (IMHO) implementation of this is Delphi: Class(object) // cast to Class, no type-check object as Class // cast to Class, throw exception on error object is Class // true if object is instance of Class So to call ThinkingEntity.Think(), you'd require the following code, supposing that "is" operator is supported in D: if (entity is ThinkingEntity) entity.Think(); Your code would look very similar: if (cast(ThinkingEntity) Entity) entity.Think(); So no real advantage here.My point is that from a single cast-else-null primitive, you can build cast-else-throw and and is-safe-to-cast? operations easily and efficiently; if the primitive is cast-else-throw, then theThe problem is that every cast operation must be wrapped in an if-block to throw exceptions. This is like, say, wrapping each C function call checking if it returns an error code and throwing an exception. IMHO, typechecking and typecasting should be _separate_ operations, not mixed. Because typecasting is usually performed on the generic pointer actually pointing to the child class when you know for sure that it does, and typechecking is used when you don't know what object your pointer references. These are two distinct things, let's not mix them.is-safe-to-cast? operation _must_ (as you noted) be provided by the language in a way that doesn't internally generate an exception, for performance reasons.BTW I've just thought that this operation is already supported by D due to its RTTI system: if (entity.class == ClassThinkingEntity) entity.Think(); Personally, I like the "is" operator more, but even now D already has support for typechecking.
Nov 24 2001
Pavel Minayev wrote:IMHO, typechecking and typecasting should be _separate_ operations, not mixed. Because typecasting is usually performed on the generic pointer actually pointing to the child class when you know for sure that it does, and typechecking is used when you don't know what object your pointer references. These are two distinct things, let's not mix them.It's possible that I've been poisoned by years of working with functions that return a pointer or NULL on failure, but that's a familiar way for me to frame the idiom "if object supports X() then do X() on object," so we may just be up against personal style issues here.BTW I've just thought that this operation is already supported by D due to its RTTI system: if (entity.class == ClassThinkingEntity) entity.Think(); Personally, I like the "is" operator more, but even now D already has support for typechecking.But we need to know if the entity is a ThinkingEntity or any class derived from that. The class library I'm working with at my job has two separate operations (macros, actually) -- IsA(), which checks exact class membership, and IsKindOf(), which checks for membership in any derived class. Those would be the minimum primitives necessary in conjunction with a throwing cast to support the idiom. -RB
Nov 24 2001
"Russell Borogove" <kaleja estarcion.com> wrote in message news:3C0003D0.9070305 estarcion.com...It's possible that I've been poisoned by years of working with functions that return a pointer or NULL on failure, but that's a familiar way for me to frame the idiom "if object supports X() then do X() on object," so we may just be up against personal style issues here.It's a common style that I use as well, I just ain't satisfied with the syntax.But we need to know if the entity is a ThinkingEntity or any class derived from that.Oh yes, I missed that. However, I'm pretty sure that classes of classes will have some way to determine the parent, for example: if (entity.class.extends(ClassThinkingEntity)) ... Or sumthing like that. Probably Walter will tell us if this works or not as he comes by this thread =)The class library I'm working with at my job has two separate operations (macros, actually) -- IsA(), which checks exact class membership, and IsKindOf(), which checks for membership in any derived class. Those would be the minimum primitives necessary in conjunction with a throwing cast to support the idiom.In most cases, you actually use IsKindOf() or its equvalent. So I believe the exact typechecking could be left in its current form, and base class check should of course be introduced, hopefully in form of "is" operator.
Nov 24 2001
"Pavel Minayev" <evilone omen.ru> wrote in message news:9tptu2$22je$1 digitaldaemon.com..."Russell Borogove" <kaleja estarcion.com> wrote in message news:3C0003D0.9070305 estarcion.com... if (entity.class.extends(ClassThinkingEntity)) ... Or sumthing like that. Probably Walter will tell us if this works or not as he comes by this thread =)No, I had missed that. It's wierd how from time to time I discover interesting things in my own design <g>.
Nov 25 2001
This sounds like fine syntax to me. I still think that once you've determined that an object is a subclass of some base class, you should be able to do the typecast without checking the same thing again. if (entity.class.extends(ClassThinkingEntity)) (static_cast(ClassThinkingEntity) entity).Think(); or (dynamic_cast(ClassThinkingEntity) entity).Think(); // dynamic_cast must throw an exception if it can't do it. But I'd hate to pay the RTTI lookup overhead twice. Sean "Walter" <walter digitalmars.com> wrote in message news:9trei7$euv$1 digitaldaemon.com..."Pavel Minayev" <evilone omen.ru> wrote in message news:9tptu2$22je$1 digitaldaemon.com..."Russell Borogove" <kaleja estarcion.com> wrote in message news:3C0003D0.9070305 estarcion.com... if (entity.class.extends(ClassThinkingEntity)) ... Or sumthing like that. Probably Walter will tell us if this works or not as he comes by this thread =)No, I had missed that. It's wierd how from time to time I discover interesting things in my own design <g>.
Nov 29 2001
IMHO, typechecking and typecasting should be _separate_ operations, not mixed. Because typecasting is usually performed on the generic pointer actually pointing to the child class when you know for sure that it does, and typechecking is used when you don't know what object your pointer references. These are two distinct things, let's not mix them.I agree with this. Dynamic typecasting can be almost zero overhead if the object is already known to be of such type or a descendant.Nope, that won't catch the case where entity is actually a class derived from ClassThinkingEntity. Maybe an 'is' operator here would be nice. Only takes class types as arguments (an object being implicitly convertible to its class type) Seanis-safe-to-cast? operation _must_ (as you noted) be provided by the language in a way that doesn't internally generate an exception, for performance reasons.BTW I've just thought that this operation is already supported by D due to its RTTI system: if (entity.class == ClassThinkingEntity) entity.Think(); Personally, I like the "is" operator more, but even now D already has support for typechecking.
Nov 29 2001
This post just gave me a thought. It probably isn't appropriate for D but I'll spit it out anyway. Each type is going to have a property that tells you the type right? (Humor me. Say yes.) Likewise we could also put such a property on the class identifier itself. The property could be the RTTI info. I don't really care as long as it is a definite type that the compiler can recognize. So you have: Class1; // some class defined somewhere Class1 Obj1; // an instance of Class1 Class2; // another class Class2 Obj2; // you know the drill With the property I described above (I'll call it type) and some type comparison operators we could have: // true iff Obj1 & Obj2 are instances // of the same class Obj1.type == Obj2.type; // true iff Obj1 is a descendent of Obj2 Obj1.type > Obj2.type; // true iff Obj1 is a parent of Obj2 Obj1.type < Obj2.type; Since classes have the property you could also say: // true iff Obj is an instance of Class Obj.type == Class.type; You could also have all of the >=, <=, !=, <> type comparison too. This could be done in the compiler but I imagine the detractors of operator overloading might also be offended by this. It's clear (to me at least) concise, and does require new keywords or syntax. Thought? Dan "Sean L. Palmer" wrote:IMHO, typechecking and typecasting should be _separate_ operations, not mixed. Because typecasting is usually performed on the generic pointer actually pointing to the child class when you know for sure that it does, and typechecking is used when you don't know what object your pointer references. These are two distinct things, let's not mix them.I agree with this. Dynamic typecasting can be almost zero overhead if the object is already known to be of such type or a descendant.Nope, that won't catch the case where entity is actually a class derived from ClassThinkingEntity. Maybe an 'is' operator here would be nice. Only takes class types as arguments (an object being implicitly convertible to its class type) Seanis-safe-to-cast? operation _must_ (as you noted) be provided by the language in a way that doesn't internally generate an exception, for performance reasons.BTW I've just thought that this operation is already supported by D due to its RTTI system: if (entity.class == ClassThinkingEntity) entity.Think(); Personally, I like the "is" operator more, but even now D already has support for typechecking.
Nov 29 2001
a wrote:So you have: Class1; // some class defined somewhere Class1 Obj1; // an instance of Class1 Class2; // another class Class2 Obj2; // you know the drill With the property I described above (I'll call it type) and some type comparison operators we could have: // true iff Obj1 & Obj2 are instances // of the same class Obj1.type == Obj2.type; // true iff Obj1 is a descendent of Obj2 Obj1.type > Obj2.type; // true iff Obj1 is a parent of Obj2 Obj1.type < Obj2.type; Since classes have the property you could also say: // true iff Obj is an instance of Class Obj.type == Class.type; You could also have all of the >=, <=, !=, <> type comparison too. This could be done in the compiler but I imagine the detractors of operator overloading might also be offended by this. It's clear (to me at least) concise, and does require new keywords or syntax.I like it, but I will be perpetually confused because I'll think of parents as "greater than" children, or see the > as a directional indicator of the direction of descendance instead of the direction of inheritance. Also, it's unclear what the right answers are when obj1 and obj2 are completely unrelated classes -- probably all relationals should return false? -RB
Nov 29 2001
Russell Borogove wrote:a wrote:I saw it as meaning the child class was everything the parent was and more. A superset of sorts. However, swapping the operators probably wouldn't hurt. It would just have to have a good meaning that capture the inheritance relation and how the parent is 'greater'. (Age doesn't count.)So you have: Class1; // some class defined somewhere Class1 Obj1; // an instance of Class1 Class2; // another class Class2 Obj2; // you know the drill With the property I described above (I'll call it type) and some type comparison operators we could have: // true iff Obj1 & Obj2 are instances // of the same class Obj1.type == Obj2.type; // true iff Obj1 is a descendent of Obj2 Obj1.type > Obj2.type; // true iff Obj1 is a parent of Obj2 Obj1.type < Obj2.type; Since classes have the property you could also say: // true iff Obj is an instance of Class Obj.type == Class.type; You could also have all of the >=, <=, !=, <> type comparison too. This could be done in the compiler but I imagine the detractors of operator overloading might also be offended by this. It's clear (to me at least) concise, and does require new keywords or syntax.I like it, but I will be perpetually confused because I'll think of parents as "greater than" children, or see the > as a directional indicator of the direction of descendance instead of the direction of inheritance.Also, it's unclear what the right answers are when obj1 and obj2 are completely unrelated classes -- probably all relationals should return false?I guess I was thinking of that as being treated like the NaN cases with floats. They aren't equal and neither one is greater than the other. Isn't there a difference between != and <> for floats? Dan
Nov 29 2001
a wrote:I saw it as meaning the child class was everything the parent was and more. A superset of sorts. However, swapping the operators probably wouldn't hurt. It would just have to have a good meaning that capture the inheritance relation and how the parent is 'greater'. (Age doesn't count.)If you think of a class as a set of objects, then the parent is the larger, since it encompasses a larger set and each child class encompasses a subset of the parent set. That's how I've seen OOP theory taught. However, from the view of a programmer, a class is a definition of a set of functionality, and so the child is a larger set. I don't see any way to ensure clarity...other than just make a definition. That's too bad, since I think that these operators are a very Good Idea. Maybe it's worth the confusion...How about throw an exception if they're not comparable? -- The Villagers are Online! http://villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]Also, it's unclear what the right answers are when obj1 and obj2 are completely unrelated classes -- probably all relationals should return false?I guess I was thinking of that as being treated like the NaN cases with floats. They aren't equal and neither one is greater than the other. Isn't there a difference between != and <> for floats?
Nov 29 2001
Russ Lewis wrote:If you think of a class as a set of objects, then the parent is the larger, since it encompasses a larger set and each child class encompasses a subset of the parent set. That's how I've seen OOP theory taught. However, from the view of a programmer, a class is a definition of a set of functionality, and so the child is a larger set. I don't see any way to ensure clarity...other than just make a definition. That's too bad, since I think that these operators are a very Good Idea. Maybe it's worth the confusion...It would have to be an arbitrary rule. Just pick a semantic model. I can live with that.If the test to see if they are not at all related isn't any more complicated than test for specific relation ships (i.e.. parent of, child of, same) then I'd hate to burden the operation with an exception throw. Are we sure that there will never be a case where someone would reasonably want to test if two objects are not related?How about throw an exception if they're not comparable?Also, it's unclear what the right answers are when obj1 and obj2 are completely unrelated classes -- probably all relationals should return false?I guess I was thinking of that as being treated like the NaN cases with floats. They aren't equal and neither one is greater than the other. Isn't there a difference between != and <> for floats?
Nov 29 2001
a wrote:If the test to see if they are not at all related isn't any more complicated than test for specific relation ships (i.e.. parent of, child of, same) then I'd hate to burden the operation with an exception throw. Are we sure that there will never be a case where someone would reasonably want to test if two objects are not related?It's thinking about this that caused me to ponder the greatestCommonClass idea described in my subsequent post. The test to see if two objects are related could be: if( greatestCommonClass(ptr1,ptr2) != Object) -- The Villagers are Online! http://villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Nov 30 2001
Russ Lewis wrote:a wrote:A nifty idea, but it seems more appropriate in a dynamically typed language like perl or python. That still doesn't tell you that ptr1 is not ptr2's parent or visa versa. I was thinking that ptr1 <> ptr2; might mean true if neither of them is the descendant of the other. Frankly, I don't care if their closest common ancestor is Object or something closer. The greatest common class really doesn't provide that. You could implement <> with it, but you could also just use the <= & >= operators just as well. I'm trying to figure out how some one might reasonable use the function you describe, but I know the operators I've suggested would not be enough to implement it in any optimal fashion. Will/should D allow a programmer to use rtti to determine what type of object to allocate at runtime? If so, it feels like it could seriously compromise the abilities of compile time type checking severely. It could just be the cost of play with the operation. I suspect it could be very useful with regard to generic programming depending on how that is implemented. DanIf the test to see if they are not at all related isn't any more complicated than test for specific relation ships (i.e.. parent of, child of, same) then I'd hate to burden the operation with an exception throw. Are we sure that there will never be a case where someone would reasonably want to test if two objects are not related?It's thinking about this that caused me to ponder the greatestCommonClass idea described in my subsequent post. The test to see if two objects are related could be: if( greatestCommonClass(ptr1,ptr2) != Object)
Nov 30 2001
a wrote:Russ Lewis wrote:Sure it does! switch( greatestCommonClass(ptr1,ptr2) ) { case ptr1.class: // ptr1 is a parent of ptr2 case ptr2.class: // ptr2 is a parent of ptr1 case Object: // no commonality default: // they share a common base class };a wrote:A nifty idea, but it seems more appropriate in a dynamically typed language like perl or python. That still doesn't tell you that ptr1 is not ptr2's parent or visa versa.If the test to see if they are not at all related isn't any more complicated than test for specific relation ships (i.e.. parent of, child of, same) then I'd hate to burden the operation with an exception throw. Are we sure that there will never be a case where someone would reasonably want to test if two objects are not related?It's thinking about this that caused me to ponder the greatestCommonClass idea described in my subsequent post. The test to see if two objects are related could be: if( greatestCommonClass(ptr1,ptr2) != Object)I was thinking that ptr1 <> ptr2; might mean true if neither of them is the descendant of the other. Frankly, I don't care if their closest common ancestor is Object or something closer. The greatest common class really doesn't provide that. You could implement <> with it, but you could also just use the <= & >= operators just as well. I'm trying to figure out how some one might reasonable use the function you describe, but I know the operators I've suggested would not be enough to implement it in any optimal fashion. Will/should D allow a programmer to use rtti to determine what type of object to allocate at runtime? If so, it feels like it could seriously compromise the abilities of compile time type checking severely. It could just be the cost of play with the operation. I suspect it could be very useful with regard to generic programming depending on how that is implemented.I don't know the details of RTTI (I don't know *a lot* of the detail of compilers, but wouldn't the vtable pointer be a good RTTI identifier? Two objects of the same class would have identical vtable pointers. If you wanted, at runtime, the class name, then the vtable could include a pointer to a class name field. Even if the class doesn't need a vtable, you could include a vtable pointer and use it to gain access to the class name and do RTTI. As for the usefulness of greatestCommonClass (I'd love to call it gcc...if the acronym wasn't taken...what about 'gcp' for 'greatestCommonParent'?), I offered a very simple snippet from a generic container class in the original post. Would it be useful for me to flesh this example out? -- The Villagers are Online! http://villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Nov 30 2001
Russ Lewis wrote:a wrote:I hadn't thought of that. I don't know if switch was intended to work with anything other than integral types and maybe strings. It might be nice if it did, but depending on how switch is done, there might be other nasty side effects. Also, I thought the case values had to be constants know at compile time.Russ Lewis wrote:Sure it does! switch( greatestCommonClass(ptr1,ptr2) ) { case ptr1.class: // ptr1 is a parent of ptr2 case ptr2.class: // ptr2 is a parent of ptr1 case Object: // no commonality default: // they share a common base class };a wrote:A nifty idea, but it seems more appropriate in a dynamically typed language like perl or python. That still doesn't tell you that ptr1 is not ptr2's parent or visa versa.If the test to see if they are not at all related isn't any more complicated than test for specific relation ships (i.e.. parent of, child of, same) then I'd hate to burden the operation with an exception throw. Are we sure that there will never be a case where someone would reasonably want to test if two objects are not related?It's thinking about this that caused me to ponder the greatestCommonClass idea described in my subsequent post. The test to see if two objects are related could be: if( greatestCommonClass(ptr1,ptr2) != Object)I'm not concerned with how rtti will be implemented. I was thinking that the best use I could find for such a function would be to get type information at runtime in order to allocate a new object of this dynamically determined type. base* ptr = greatestCommonClass(ptr2,ptr3).new(swizzle(ptr2,ptr3)); Ya, I know the syntax is broken, but hopeful the idea was clear. In any case. I find the above dangerous. It's not as bad as creating a type at runtime in perl, but it feel like it is in the same arena. Of course, dangerous does not mean useless. I just like to understand when I have enough rope to hang myself. I guess greatestCommonClass would also be useful for determining if two classes have a common ancestor other that Object. That's about the only uses I see for it. You could it to see if two classes have a common ancestor that is a descendent of some known base like so: if(greatestCommonClass(p1, p2) >= WigetBase.class) meaningfulThings(); but you would get the same results with: if(p1.class >= WigetBase.class && p2.class >= WidetBase.class) meaningfulThings(); I'm not saying there aren't more uses. I'm just too dense to see them. DanI was thinking that ptr1 <> ptr2; might mean true if neither of them is the descendant of the other. Frankly, I don't care if their closest common ancestor is Object or something closer. The greatest common class really doesn't provide that. You could implement <> with it, but you could also just use the <= & >= operators just as well. I'm trying to figure out how some one might reasonable use the function you describe, but I know the operators I've suggested would not be enough to implement it in any optimal fashion. Will/should D allow a programmer to use rtti to determine what type of object to allocate at runtime? If so, it feels like it could seriously compromise the abilities of compile time type checking severely. It could just be the cost of play with the operation. I suspect it could be very useful with regard to generic programming depending on how that is implemented.I don't know the details of RTTI (I don't know *a lot* of the detail of compilers, but wouldn't the vtable pointer be a good RTTI identifier? Two objects of the same class would have identical vtable pointers. If you wanted, at runtime, the class name, then the vtable could include a pointer to a class name field. Even if the class doesn't need a vtable, you could include a vtable pointer and use it to gain access to the class name and do RTTI. As for the usefulness of greatestCommonClass (I'd love to call it gcc...if the acronym wasn't taken...what about 'gcp' for 'greatestCommonParent'?), I offered a very simple snippet from a generic container class in the original post. Would it be useful for me to flesh this example out?
Nov 30 2001
How about this class hierarchy: interface Comparable; class Apples : Comparable; class ApplesChild1 : Apples; class ApplesChild2 : Apples; class Oranges : Comparable; class OrangesChild1 : Oranges; class OrangesChild2 : Oranges; The idea here is that both Apples and Oranges implement the functions of interface Comparable. Obviously, you can't compare apples and oranges. :) So here's a snippet from a container class: int Compare(Object *ptr1, Object *ptr2) { Class common = gcp(ptr1,ptr2); // greatestCommonParent if(common = Object) throw Exception("Cannot compare objects: no common parent classes"); if( !common.implements(Comparable) ) throw Exception("Cannot compare objects: common parent class does not implement interface Comparable"); return ptr1->Compare(ptr2); } Does this code make sense to anybody but me? -- The Villagers are Online! http://villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Dec 01 2001
Russ Lewis wrote:How about this class hierarchy: interface Comparable; class Apples : Comparable; class ApplesChild1 : Apples; class ApplesChild2 : Apples; class Oranges : Comparable; class OrangesChild1 : Oranges; class OrangesChild2 : Oranges; The idea here is that both Apples and Oranges implement the functions of interface Comparable. Obviously, you can't compare apples and oranges. :) So here's a snippet from a container class: int Compare(Object *ptr1, Object *ptr2) { Class common = gcp(ptr1,ptr2); // greatestCommonParent if(common = Object) throw Exception("Cannot compare objects: no common parent classes"); if( !common.implements(Comparable) ) throw Exception("Cannot compare objects: common parent class does not implement interface Comparable"); return ptr1->Compare(ptr2); } Does this code make sense to anybody but me?I see how it works, but it is not very general purpose. If Apple and Orange had some other common base (say fruit) this suddenly breaks. This container simply uses the first ancestor after Object to divide types into equivalence classes. A general container should not make this type of assumption. A domain specific probably ought to deal more with the base classes it was designed for. I guess you could have a common base other than object (again Fruit) and make it a design decision that direct children of that class are not comparable. I would also put the requirement to implement compare in that class. I guess I see how it can be used. I don't like it, but it will take a while for me to decide if it's just because it's new to me. You do know that such a design will require the eventual addition of multiple inheritance once the biological engineers make a fruit that can be compared to it's own kind as well as apples and oranges. :-) Also your error message in the first if is wrong. All classes in D have a common parent class. I see you are trying to simulate a C++ style object model in this sense but it may clash with D code that does not differentiate between Objects that only have a parent of Object. Dan
Dec 01 2001
a wrote:I see how it works, but it is not very general purpose. If Apple and Orange had some other common base (say fruit) this suddenly breaks.But if the programmer has declared (by the class structure) that Fruit are Comparable, then why not use that to compare them?This container simply uses the first ancestor after Object to divide types into equivalence classes. A general container should not make this type of assumption. A domain specific probably ought to deal more with the base classes it was designed for.I'm not sure why this is a problem. Examples, please, so I can understand better?I guess you could have a common base other than object (again Fruit) and make it a design decision that direct children of that class are not comparable. I would also put the requirement to implement compare in that class. I guess I see how it can be used. I don't like it, but it will take a while for me to decide if it's just because it's new to me. You do know that such a design will require the eventual addition of multiple inheritance once the biological engineers make a fruit that can be compared to it's own kind as well as apples and oranges. :-)???? If fruit are comparable, then why not just declare Fruit as implementing interface Comparable? I'm lost again.Also your error message in the first if is wrong. All classes in D have a common parent class. I see you are trying to simulate a C++ style object model in this sense but it may clash with D code that does not differentiate between Objects that only have a parent of Object.True, it was kind of rough. Acutally, the message should be "Cannot compare objects: no common parent class other than Object" -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Dec 03 2001
a wrote:I hadn't thought of that. I don't know if switch was intended to work with anything other than integral types and maybe strings. It might be nice if it did, but depending on how switch is done, there might be other nasty side effects. Also, I thought the case values had to be constants know at compile time.heh. Well, it can be an if...else if otherwise. Would be cool if switch would work on this, though... -- The Villagers are Online! http://villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Dec 01 2001
Walter says D's switch statement allows strings. I don't see why it has to be limited to only constants, since a switch can always be rewritten as a series of if .. else if ... else clauses (with a break for a case being simulated with a goto) and if's are not limited to only constants. Sean "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3C08E67F.664DE454 deming-os.org...a wrote:would work on this,I hadn't thought of that. I don't know if switch was intended to work with anything other than integral types and maybe strings. It might be nice if it did, but depending on how switch is done, there might be other nasty side effects. Also, I thought the case values had to be constants know at compile time.heh. Well, it can be an if...else if otherwise. Would be cool if switchthough...
Dec 02 2001
"Sean L. Palmer" wrote:Walter says D's switch statement allows strings. I don't see why it has to be limited to only constants, since a switch can always be rewritten as a series of if .. else if ... else clauses (with a break for a case being simulated with a goto) and if's are not limited to only constants. Sean "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:3C08E67F.664DE454 deming-os.org...I believe if was suppose to be the high level equivalent of a conditional branch. Switch was supposed to be the equivalent of a jump table. The is a performance difference. C made it pretty easy to look at the code and know what the compiler was going to do to it. Dana wrote:would work on this,I hadn't thought of that. I don't know if switch was intended to work with anything other than integral types and maybe strings. It might be nice if it did, but depending on how switch is done, there might be other nasty side effects. Also, I thought the case values had to be constants know at compile time.heh. Well, it can be an if...else if otherwise. Would be cool if switchthough...
Dec 02 2001
There's nothing stopping a D compiler from turning a suitable switch into a jump table. In the string case the compiler could build a hidden static constant associative array to a jump address, or it could turn it into a series of if-else statements. For integers or enums it should be able to optimize as much as C can. I can't think of a reason anyone would want to switch on the value of a float unless one could specify ranges for each case. I have no idea if switches on class instances would be legal or not, as it seems like we won't be able to override class operator ==. What is the defined behavior for comparing two object instances? Compare the actual pointers, and if they're the same return true. Otherwise compare their vtable pointers, and if they're the same, compare the actual data member by member. I suppose memberwise assignment of an object to another isn't possible, since it seems it would just assign the reference pointer? What about structs? Sean "a" <a b.c> wrote in message news:3C0B150D.E8A5ADAC b.c...I believe if was suppose to be the high level equivalent of a conditional branch. Switch was supposed to be the equivalent of a jump table. The is a performance difference. C made it pretty easy to look at the code and know what the compiler was going to do to it. Dan
Dec 03 2001
"Sean L. Palmer" <spalmer iname.com> wrote in message news:9ufi76$2k1b$1 digitaldaemon.com...What is the defined behavior for comparing two object instances? Compare the actual pointers, and if they're the same return true. Otherwisecomparetheir vtable pointers, and if they're the same, compare the actual data member by member.I believe pointers are compared. Otherwise, there's no way to find out if two references point to the same object.I suppose memberwise assignment of an object to another isn't possible, since it seems it would just assign the reference pointer? What about structs?Since structs are not references, it seems just logical for them to be copied on assignment, like in C/C++.
Dec 03 2001
"Sean L. Palmer" <spalmer iname.com> wrote in message news:9ufi76$2k1b$1 digitaldaemon.com...What is the defined behavior for comparing two object instances? Compare the actual pointers, and if they're the same return true. Otherwisecomparetheir vtable pointers, and if they're the same, compare the actual data member by member.Compare the pointers. There is a root overridable method called cmp(), however. cmp() will get used for sorting arrays, for building associative arrays out of objects, etc.I suppose memberwise assignment of an object to another isn't possible, since it seems it would just assign the reference pointer?Correct.What about structs?It'll always do a bit copy - based on the notion that structs are simple aggregations. I've always been uncomfortable with the C++ notion that arbitrary functions can be executed when copying structs.
Dec 05 2001
Walter wrote:"Sean L. Palmer" <spalmer iname.com> wrote in message news:9ufi76$2k1b$1 digitaldaemon.com...Does this mean the language should provide a deep-copy or clone operation?I suppose memberwise assignment of an object to another isn't possible, since it seems it would just assign the reference pointer?Correct.Will that break structs that include class members? -RWhat about structs?It'll always do a bit copy - based on the notion that structs are simple aggregations.
Dec 05 2001
"Russell Borogove" <kaleja estarcion.com> wrote in message news:3C0E62DD.803 estarcion.com...Does this mean the language should provide a deep-copy or clone operation?I've also thought of it... maybe a built-in assign() method or a new operator (":=" ?) or something like that?Why? It'll simply copy the pointer, so you get two structs referencing one object - not a problem.It'll always do a bit copy - based on the notion that structs are simple aggregations.Will that break structs that include class members?
Dec 05 2001
Pavel Minayev wrote:"Russell Borogove" <kaleja estarcion.com> wrote in message news:3C0E62DD.803 estarcion.com...As long as the referenced object gets its refcount increased, I suppose so.[1] I guess I'm still thinking in terms of the bastardized C/C++ hybrid code that I deal with daily, where references and pointers are mixed at whim, and you have to play "guess the semantic" everywhere. (Especially when the compiler randomly decides that reference members in structs somehow make struct initializers not work. Grrrrrr.) -RB [1] Walter, does updating ref counts qualify as "arbitrary functions [...] executed when copying structs?"Does this mean the language should provide a deep-copy or clone operation?I've also thought of it... maybe a built-in assign() method or a new operator (":=" ?) or something like that?Why? It'll simply copy the pointer, so you get two structs referencing one object - not a problem.It'll always do a bit copy - based on the notion that structs are simple aggregations.Will that break structs that include class members?
Dec 05 2001
"Russell Borogove" <kaleja estarcion.com> wrote in message news:3C0E7447.E2DA8E9F estarcion.com...[1] Walter, does updating ref counts qualify as "arbitrary functions [...] executed when copying structs?"Ref counts? I've always thought there are none in D, and different techniques are used...
Dec 05 2001
Walter, the more I hear you talk, the more I think D may not be for me. People that afraid of code being executed that isn't specified right there in the source file are people that want big bloated source files, and that isn't for me. I want the compiler to do stuff automatically for me, if it is so instructed or designed. It's not like people can't figure out what's going on by stepping through the code in the debugger. It seems to me that all the nicest and most powerful features of C++ have been dropped just to end up with a language that cleans up just a few of C/C++'s worst things (header files, memory leaks) without really adding much besides native string support and associative and dynamic arrays. Guess what... you can already do all that stuff in C++, using templates and operator overloading, 2 of the things you seems to abhor. Walter, I think you and I just have a basic philosophical difference. D sounded nice at first but the more I listen to you the more I realize it's Sean "Walter" <walter digitalmars.com> wrote in message news:9ukrph$k78$1 digitaldaemon.com..."Sean L. Palmer" <spalmer iname.com> wrote in message news:9ufi76$2k1b$1 digitaldaemon.com...CompareWhat is the defined behavior for comparing two object instances?functionsthe actual pointers, and if they're the same return true. Otherwisecomparetheir vtable pointers, and if they're the same, compare the actual data member by member.Compare the pointers. There is a root overridable method called cmp(), however. cmp() will get used for sorting arrays, for building associative arrays out of objects, etc.I suppose memberwise assignment of an object to another isn't possible, since it seems it would just assign the reference pointer?Correct.What about structs?It'll always do a bit copy - based on the notion that structs are simple aggregations. I've always been uncomfortable with the C++ notion that arbitrarycan be executed when copying structs.
Dec 06 2001
It's entirely possible we have different philosophies on what makes a great language. And that's fine, the give and take here is valuable. I have read your posts with great interest. One crucial feature of D you didn't mention, and which unfortuately isn't obvious, is the design by contract and unit testing features. I've tried to do them in my C++ code, but the results aren't pretty or satisfactory. When I have used them, I discovered that the code was much more bug-free, reliable, and development was faster. -Walter "Sean L. Palmer" <spalmer iname.com> wrote in message news:9unc1g$ed$1 digitaldaemon.com...Walter, the more I hear you talk, the more I think D may not be for me. People that afraid of code being executed that isn't specified right there in the source file are people that want big bloated source files, and that isn't for me. I want the compiler to do stuff automatically for me, if it is so instructed or designed. It's not like people can't figure outwhat'sgoing on by stepping through the code in the debugger. It seems to me that all the nicest and most powerful features of C++ have been dropped just to end up with a language that cleans up just a few of C/C++'s worst things (header files, memory leaks) without really addingmuchbesides native string support and associative and dynamic arrays. Guess what... you can already do all that stuff in C++, using templates and operator overloading, 2 of the things you seems to abhor. Walter, I think you and I just have a basic philosophical difference. D sounded nice at first but the more I listen to you the more I realize it's Sean "Walter" <walter digitalmars.com> wrote in message news:9ukrph$k78$1 digitaldaemon.com...data"Sean L. Palmer" <spalmer iname.com> wrote in message news:9ufi76$2k1b$1 digitaldaemon.com...CompareWhat is the defined behavior for comparing two object instances?the actual pointers, and if they're the same return true. Otherwisecomparetheir vtable pointers, and if they're the same, compare the actualassociativemember by member.Compare the pointers. There is a root overridable method called cmp(), however. cmp() will get used for sorting arrays, for buildingpossible,arrays out of objects, etc.I suppose memberwise assignment of an object to another isn'tfunctionssince it seems it would just assign the reference pointer?Correct.What about structs?It'll always do a bit copy - based on the notion that structs are simple aggregations. I've always been uncomfortable with the C++ notion that arbitrarycan be executed when copying structs.
Dec 11 2001
Will/should D allow a programmer to use rtti to determine what type of object to allocate at runtime? If so, it feels like it could seriously compromise the abilities of compile time type checking severely. It could just be the cost of play with the operation. I suspect it could be very useful with regard to generic programming depending on how that is implemented.The ability to store an object's type to a file and then once you reload that type use some kind of virtual constructor scheme to use the loaded type to construct a new object. Probably would want to pass the file as a constructor parameter. If you can support this, it will make storing out object hierarchies much easier. I suppose we could make our own Streamable class which provides this functionality so long as we can get a storable value from the RTTI system from an object to represent its type, and make 'new' able to understand such values. It'd probably end up returning an Object reference since the compiler couldn't know what exact type it would be. One could always then inquire the object's type if we needed to work with it, or we could just typecast it to a known base class type. (similar to malloc) Sean
Dec 02 2001
Speaking of virtual constructors (which are probably the most important point in this scheme), Walter said that it could be a "good idea". Hopefully this means that we'll see them in D.
Dec 02 2001
Another idea...it might be useful to include some sort of "greatest common class" function. Object* ptr1,ptr2; Class foo = greatestCommonClass(ptr1,ptr2); It could be useful for generics: Object* ptr1,ptr2; Class base = greatestCommonClass(ptr1,ptr2); if( !base.isChildOf(Comparable) ) throw InvalidClassException("pointer cannot be compared"); if( (base*)ptr1.isLessThan((base*)ptr2) ) etc... -- The Villagers are Online! http://villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Nov 29 2001