Idea: Lazy upcasting

Reiner Pope some at address.com
Tue Mar 27 15:12:13 PDT 2007


Reiner Pope wrote:
> Marcin Kuszczak wrote:
>> Hello!
>>
>> Recently I have tried to achieve chaining a few calls to setters. I mean
>> something like below:
>>
>> //-------------------------------------------
>>
>> abstract class Storage {
>>      Storage param1(int p1) {
>>          this.p1 = p1;
>>          return this;
>>      }
>> private:
>>      int p1;
>> }
>>
>> class SpecificStorage : Storage {
>> public:
>>      SpecificStorage param2(bool p2) {
>>         this.p2=p2;
>>         return this;
>>      }
>> private:
>>      bool p2;
>> }
>>
>> void main() {
>> //                             ...ok...      ...ok...        ...ups!
>> SpecificStorage1 s1 = (new SpecificStorage).param2(true).param1(5);
>> }
>>
>> //-------------------------------------------
> 
> How about:
> 
> interface Storage
> {
>     Storage param1(int);
> }
> 
> abstract class StorageImpl(T) : Storage {
>     static assert(is(typeof(this) == T));
> 
>     T param1(int p1)
>     {
>         this.p1 = p1;
>         return cast(T)this;
>     }
>     private int p1;
> }
> 
> class SpecificStorage : StorageImpl!(SpecificStorage) {
>     SpecificStorage param2(bool p2) {
>         this.p2 = p2;
>         return this;
>     }
>     private bool p2;
> }
> 
> That should already work.
> 
> Cheers,
> 
> Reiner

PS. The reason I needed to add the extra interface was that D's type 
system doesn't think StorageImpl!(Derived) is-a StorageImpl!(Base)

It makes sense, because there are times when such a conversion is dangerous:
    List!(Square) a;
    List!(Shape) b = a;
    b.add(new Triangle); /// Ooops

But Java and Nemerle support this kind of casting in a safe way (I 
think). What you need to do is specify something in the template 
parameters at the top, which says, "You can cast down from this" or "you 
can cast up from this".  The general rule is that the "you can cast down 
from this" types may only be used as return values, and the "you can 
cast up from this" types may only be used as parameters:

interface Reader(T) // you can cast down from this
{
     T read();
}
// Reader!(Derived) is-a Reader!(Base)

interface Writer(T) // you can cast up from this
{
     void write(T);
}
// Writer!(Base) is-a Writer!(Derived)

D runs into problems because of the fact that templates can do more than 
simple type substitution; things like static if. I don't know what the 
solution to this is, but it seems like something here has been kept in 
mind for a while, given that the Future page on digitalmars says 
'template inheritance.'

Cheers,

Reiner



More information about the Digitalmars-d mailing list