digitalmars.D - Assignment and down-casting
- Yigal Chripun (45/45) Mar 07 2009 I just read this article by Dennis Richie posted on the NG [1], and I
- Tim M (3/48) Mar 07 2009 Thats bcos it's not a down cast. It's an up cast.
- Tim M (43/43) Mar 07 2009 What I was trying to say is that func needs to be called with an "A" but...
- Yigal Chripun (15/58) Mar 08 2009 I think you missed my point.
I just read this article by Dennis Richie posted on the NG [1], and I wanted to discuss a way to solve the const return issue. here's some (general) code: class A {} class B : A {} A func (A a) { .. do stuff .. return a; } void main() { B b = new B; A a1 = func(b); B a2 = cast(B) func(b); // will not compile with explicit cast } the explicit downcast could be removed if the compiler inserted the down-cast implicitly - assigning null or throwing if the down-cast fails. this can be applied to constancy since const is super type of both immutable and mutable. I don't know how a const pointer/reference is implemented in D so assume that pointers to const objects have a certain bit set. (constancy runtime type) // create a const object - bit is set const T* cptr = cast(const T*) new Struct; // create mutable object - bit unset T* ptr = new Struct; // bit is unset on assingment the bit is preserved and cannot be unset: T* a = ptr; // bit unset T* b = cptr; // fails - bit cannot be unset const T* c = cptr; // bit is set const T* d = ptr; // bit remains unset the second case fails by either assinging null to be or by throwing an exception. invariant can use a different bit. let's say we have: const T foo(const T a, U b); // foo returns a const T cptr = ...; //const object T ptr = ...; // mutable object T res = foo (cptr, something); // fails T res = foo (ptr, something); // *works* const T res = foo (cptr, something); // bit set for res const T res = foo (ptr, something); // bit unset for res just as before, the first foo fails by evaluating to null or by exception and the second foo works since the bit was never set so there's no problem "downcasting" to a regular, mutable, pointer/ref. What do you think? [1] http://www.lysator.liu.se/c/dmr-on-noalias.html
Mar 07 2009
On Sun, 08 Mar 2009 06:59:04 +1300, Yigal Chripun <yigal100 gmail.com> wrote:I just read this article by Dennis Richie posted on the NG [1], and I wanted to discuss a way to solve the const return issue. here's some (general) code: class A {} class B : A {} A func (A a) { .. do stuff .. return a; } void main() { B b = new B; A a1 = func(b); B a2 = cast(B) func(b); // will not compile with explicit cast } the explicit downcast could be removed if the compiler inserted the down-cast implicitly - assigning null or throwing if the down-cast fails. this can be applied to constancy since const is super type of both immutable and mutable. I don't know how a const pointer/reference is implemented in D so assume that pointers to const objects have a certain bit set. (constancy runtime type) // create a const object - bit is set const T* cptr = cast(const T*) new Struct; // create mutable object - bit unset T* ptr = new Struct; // bit is unset on assingment the bit is preserved and cannot be unset: T* a = ptr; // bit unset T* b = cptr; // fails - bit cannot be unset const T* c = cptr; // bit is set const T* d = ptr; // bit remains unset the second case fails by either assinging null to be or by throwing an exception. invariant can use a different bit. let's say we have: const T foo(const T a, U b); // foo returns aThats bcos it's not a down cast. It's an up cast.const T cptr = ...; //const object T ptr = ...; // mutable object T res = foo (cptr, something); // fails T res = foo (ptr, something); // *works* const T res = foo (cptr, something); // bit set for res const T res = foo (ptr, something); // bit unset for res just as before, the first foo fails by evaluating to null or by exception and the second foo works since the bit was never set so there's no problem "downcasting" to a regular, mutable, pointer/ref. What do you think? [1] http://www.lysator.liu.se/c/dmr-on-noalias.html
Mar 07 2009
What I was trying to say is that func needs to be called with an "A" but calling it with a "B" works because a "B" is a kind of "A". The function looses an information that it is a "B" returns it as an "A" which should be cast back to a "B" explicitly. This is corrct behavior as not all "A"s can be of kind "B". One way to get the kind of behaviour you are looking for is to have the caller infer the type from the function and also have the function templated to work with any type that inherits from A. I have shown this in the following example with the extra step of not explicitly instantiating the template as that can also be inferred: module temp; import std.stdio; class A { void foo() { writefln("A.foo()"); } } class B : A { override void foo() { writefln("B.foo()"); } void bar() { writefln("B.bar()"); } } T func(T : A)(T a) { //.. do stuff .. return a; } void main() { auto thing = func(new B()); //same as auto thing = func!(B)(new B()); thing.foo(); thing.bar(); } I'm not completly sure of how const/invariant work with object references so I won't attempt to answer that.
Mar 07 2009
Tim M wrote:What I was trying to say is that func needs to be called with an "A" but calling it with a "B" works because a "B" is a kind of "A". The function looses an information that it is a "B" returns it as an "A" which should be cast back to a "B" explicitly. This is corrct behavior as not all "A"s can be of kind "B". One way to get the kind of behaviour you are looking for is to have the caller infer the type from the function and also have the function templated to work with any type that inherits from A. I have shown this in the following example with the extra step of not explicitly instantiating the template as that can also be inferred: module temp; import std.stdio; class A { void foo() { writefln("A.foo()"); } } class B : A { override void foo() { writefln("B.foo()"); } void bar() { writefln("B.bar()"); } } T func(T : A)(T a) { //.. do stuff .. return a; } void main() { auto thing = func(new B()); //same as auto thing = func!(B)(new B()); thing.foo(); thing.bar(); } I'm not completly sure of how const/invariant work with object references so I won't attempt to answer that.I think you missed my point. I used an example with classes as a generalization. remember that in D we have: const(T) /\ / \ / \ T invariant(T) basically I want to do: ref const(T) max(T)(ref const(T) a, ref const(T) b){ return (a>b)?a:b; } int a = 4; int b = 5; int res = max(a, b); //works due to "downcasting" from const(int) to int this can be limited to constancy only if it doesn't make sense for classes.
Mar 08 2009