Type inference when returning this

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Type inference when returning this

Simon Krajewski
Hello list,

in this example:

     class Parent {
         public function new() { }

         public function doSomething() {
             trace("Doing something.");
             return this;
         }
     }

     class Child extends Parent {
         public function new() { super(); }

         public function doSomethingElse() {
             trace("Doing something else.");
             return this;
         }
     }

the following fails:

         var c:Child = new Child();
         c.doSomething().doSomethingElse();

because:

         Parent has no field doSomethingElse

Is there any way of convincing the compiler that the call should be
valid while retaining type safety? This would be really good for
creating fluent interfaces.

Thanks in advance
Simon

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Schnell Henrik
Try this: 

var c:Child = new Child();
cast(c.doSomething(), Child).doSomethingElse();

So in my opinion the Parent class doSomething() method returns a Parent type by default even when called on a Child. 
So you need to explicitly cast it to a Child type first.

I may be wrong, I'm not a Haxe expert, but this is how I think in general OOP.

Henko

2010/12/8 Simon Krajewski <[hidden email]>
Hello list,

in this example:

   class Parent {
       public function new() { }

       public function doSomething() {
           trace("Doing something.");
           return this;
       }
   }

   class Child extends Parent {
       public function new() { super(); }

       public function doSomethingElse() {
           trace("Doing something else.");
           return this;
       }
   }

the following fails:

       var c:Child = new Child();
       c.doSomething().doSomethingElse();

because:

       Parent has no field doSomethingElse

Is there any way of convincing the compiler that the call should be valid while retaining type safety? This would be really good for creating fluent interfaces.

Thanks in advance
Simon

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Simon Krajewski
Hi,

thanks for your suggestion. Using cast is actually what I'm doing now, but is seems quite verbose and sort of ruins the fluency of a fluent interface. But I guess this is the best I can do for now.

Regards
Simon

On 09.12.2010 02:40, Schnell Henrik wrote:
Try this: 

var c:Child = new Child();
cast(c.doSomething(), Child).doSomethingElse();

So in my opinion the Parent class doSomething() method returns a Parent type by default even when called on a Child. 
So you need to explicitly cast it to a Child type first.

I may be wrong, I'm not a Haxe expert, but this is how I think in general OOP.

Henko

2010/12/8 Simon Krajewski <[hidden email]>
Hello list,

in this example:

   class Parent {
       public function new() { }

       public function doSomething() {
           trace("Doing something.");
           return this;
       }
   }

   class Child extends Parent {
       public function new() { super(); }

       public function doSomethingElse() {
           trace("Doing something else.");
           return this;
       }
   }

the following fails:

       var c:Child = new Child();
       c.doSomething().doSomethingElse();

because:

       Parent has no field doSomethingElse

Is there any way of convincing the compiler that the call should be valid while retaining type safety? This would be really good for creating fluent interfaces.

Thanks in advance
Simon

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Tony Polinelli
You can put the cast inside the baseclass - to avoid the type inference locking its return and the "type" - but this means that it isnt strictly typed when you use *just* the baseclass. and The first override to no cast - will infer the type

class Main
{
   
    static function main()
    {
        var t = new MyType2();
        t.getThis().more();
    }
   
}
class BaseType
{
    public function new() { }
   
    public function getThis()
    {
        return cast this;
    }
}

class MyType extends BaseType
{
    override public function getThis()
    {
        return this;
    }
   
    public function more()
    {
        trace("more");
    }
}


On Thu, Dec 9, 2010 at 2:07 PM, Simon Krajewski <[hidden email]> wrote:
Hi,

thanks for your suggestion. Using cast is actually what I'm doing now, but is seems quite verbose and sort of ruins the fluency of a fluent interface. But I guess this is the best I can do for now.

Regards
Simon


On 09.12.2010 02:40, Schnell Henrik wrote:
Try this: 

var c:Child = new Child();
cast(c.doSomething(), Child).doSomethingElse();

So in my opinion the Parent class doSomething() method returns a Parent type by default even when called on a Child. 
So you need to explicitly cast it to a Child type first.

I may be wrong, I'm not a Haxe expert, but this is how I think in general OOP.

Henko

2010/12/8 Simon Krajewski <[hidden email]>
Hello list,

in this example:

   class Parent {
       public function new() { }

       public function doSomething() {
           trace("Doing something.");
           return this;
       }
   }

   class Child extends Parent {
       public function new() { super(); }

       public function doSomethingElse() {
           trace("Doing something else.");
           return this;
       }
   }

the following fails:

       var c:Child = new Child();
       c.doSomething().doSomethingElse();

because:

       Parent has no field doSomethingElse

Is there any way of convincing the compiler that the call should be valid while retaining type safety? This would be really good for creating fluent interfaces.

Thanks in advance
Simon

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org



--
Tony Polinelli
http://touchmypixel.com

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Justin Donaldson-3
In reply to this post by Simon Krajewski
The way that type inference is set up now, the type of a method is inferred as soon as the return object type is known.  In your example, the inferred return type from "this" in doSomething() refers to a Parent class, and Parent needs to be fully typed before Child can extend it.

In order to do what you want, it would be necessary for the compiler to manage the types for functions that return an inferred "this" type differently for each class that extends the base class.  I can imagine this might add a neat trick for handling self references, but it could potentially cause problems in other cases (if someone expected the inferred type to always be "Parent").  Out of curiosity, what kinds of things were you wanting to do with this technique?

-Justin

On Wed, Dec 8, 2010 at 7:07 PM, Simon Krajewski <[hidden email]> wrote:
Hi,

thanks for your suggestion. Using cast is actually what I'm doing now, but is seems quite verbose and sort of ruins the fluency of a fluent interface. But I guess this is the best I can do for now.

Regards
Simon


On 09.12.2010 02:40, Schnell Henrik wrote:
Try this: 

var c:Child = new Child();
cast(c.doSomething(), Child).doSomethingElse();

So in my opinion the Parent class doSomething() method returns a Parent type by default even when called on a Child. 
So you need to explicitly cast it to a Child type first.

I may be wrong, I'm not a Haxe expert, but this is how I think in general OOP.

Henko

2010/12/8 Simon Krajewski <[hidden email]>
Hello list,

in this example:

   class Parent {
       public function new() { }

       public function doSomething() {
           trace("Doing something.");
           return this;
       }
   }

   class Child extends Parent {
       public function new() { super(); }

       public function doSomethingElse() {
           trace("Doing something else.");
           return this;
       }
   }

the following fails:

       var c:Child = new Child();
       c.doSomething().doSomethingElse();

because:

       Parent has no field doSomethingElse

Is there any way of convincing the compiler that the call should be valid while retaining type safety? This would be really good for creating fluent interfaces.

Thanks in advance
Simon

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org



--
blog: http://www.scwn.net
aim: iujjd
twitter: jjdonald


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Vag Vagoff
In reply to this post by Simon Krajewski
interface IThis<T> {
        function This() : T;
}

class Parent<This> implements IThis<This> {
        public function new() { }
        public function This() : This return throw "abstract"

        public function doSomething() : This {
          trace("Doing something.");
                return This();
        }
}

class Child extends Parent<Child> {
        public function new() super()
        override public function This() return this

        public function doSomethingElse() : Child {
                trace("Doing something else.");
                return This();
        }
}


class Test {
        static function main() {
                var c:Child = new Child();
                c.doSomething().doSomethingElse();
                trace("hello");
        }
}

On 08.12.2010 22:39, Simon Krajewski wrote:

> Hello list,
>
> in this example:
>
> class Parent {
> public function new() { }
>
> public function doSomething() {
> trace("Doing something.");
> return this;
> }
> }
>
> class Child extends Parent {
> public function new() { super(); }
>
> public function doSomethingElse() {
> trace("Doing something else.");
> return this;
> }
> }
>
> the following fails:
>
> var c:Child = new Child();
> c.doSomething().doSomethingElse();
>
> because:
>
> Parent has no field doSomethingElse
>
> Is there any way of convincing the compiler that the call should be valid while retaining type safety? This would be really good for creating fluent interfaces.
>
> Thanks in advance
> Simon
>


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Vag Vagoff
In reply to this post by Simon Krajewski
// Second variant -- using inheritance

class GetThis<This> {
     public function getThis() : This return throw "abstract"
}

class Parent<This> extends GetThis<This> {
        public function new() { }

        public function doSomething() : This {
          trace("Doing something.");
                return getThis();
        }
}

class Child extends Parent<Child> {
        public function new() super()
        override public function getThis() return this

        public function doSomethingElse() : Child {
                trace("Doing something else.");
                return getThis();
        }
}


class Test {
        static function main() {
                var c:Child = new Child();
                c.doSomething().doSomethingElse();
        }
}

On 08.12.2010 22:39, Simon Krajewski wrote:

> Hello list,
>
> in this example:
>
> class Parent {
> public function new() { }
>
> public function doSomething() {
> trace("Doing something.");
> return this;
> }
> }
>
> class Child extends Parent {
> public function new() { super(); }
>
> public function doSomethingElse() {
> trace("Doing something else.");
> return this;
> }
> }
>
> the following fails:
>
> var c:Child = new Child();
> c.doSomething().doSomethingElse();
>
> because:
>
> Parent has no field doSomethingElse
>
> Is there any way of convincing the compiler that the call should be valid while retaining type safety? This would be really good for creating fluent interfaces.
>
> Thanks in advance
> Simon
>


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Vag Vagoff
In reply to this post by Simon Krajewski
// third variant -- slightly cleaner -- maybe Child wants to be inherited also

class GetThis<This> {
     public function getThis() : This return throw "abstract"
}

class Parent<This> extends GetThis<This> {
        public function new() { }

        public function doSomething() : This {
          trace("Doing something.");
                return getThis();
        }
}

class Child<This> extends Parent<This> {
        public function new() super()

        public function doSomethingElse() : This {
                trace("Doing something else.");
                return getThis();
        }
}

class Final extends Child<Final> {
        override public function getThis() return this
}

class Test {
        static function main() {
                var c:Final = new Final();
                c.doSomething().doSomethingElse();
        }
}

On 08.12.2010 22:39, Simon Krajewski wrote:

> Hello list,
>
> in this example:
>
> class Parent {
> public function new() { }
>
> public function doSomething() {
> trace("Doing something.");
> return this;
> }
> }
>
> class Child extends Parent {
> public function new() { super(); }
>
> public function doSomethingElse() {
> trace("Doing something else.");
> return this;
> }
> }
>
> the following fails:
>
> var c:Child = new Child();
> c.doSomething().doSomethingElse();
>
> because:
>
> Parent has no field doSomethingElse
>
> Is there any way of convincing the compiler that the call should be valid while retaining type safety? This would be really good for creating fluent interfaces.
>
> Thanks in advance
> Simon
>


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Simon Krajewski
Hi,

that's a great solution, works like a charm. Thanks!

Regards
Simon

On 09.12.2010 10:03, Vag Vagoff wrote:

> // third variant -- slightly cleaner -- maybe Child wants to be
> inherited also
>
> class GetThis<This> {
>     public function getThis() : This return throw "abstract"
> }
>
> class Parent<This> extends GetThis<This> {
>     public function new() { }
>
>     public function doSomething() : This {
>             trace("Doing something.");
>         return getThis();
>     }
> }
>
> class Child<This> extends Parent<This> {
>     public function new() super()
>
>     public function doSomethingElse() : This {
>         trace("Doing something else.");
>         return getThis();
>     }
> }
>
> class Final extends Child<Final> {
>     override public function getThis() return this
> }
>
> class Test {
>     static function main() {
>             var c:Final = new Final();
>             c.doSomething().doSomethingElse();
>     }
> }
>
> On 08.12.2010 22:39, Simon Krajewski wrote:
>> Hello list,
>>
>> in this example:
>>
>> class Parent {
>> public function new() { }
>>
>> public function doSomething() {
>> trace("Doing something.");
>> return this;
>> }
>> }
>>
>> class Child extends Parent {
>> public function new() { super(); }
>>
>> public function doSomethingElse() {
>> trace("Doing something else.");
>> return this;
>> }
>> }
>>
>> the following fails:
>>
>> var c:Child = new Child();
>> c.doSomething().doSomethingElse();
>>
>> because:
>>
>> Parent has no field doSomethingElse
>>
>> Is there any way of convincing the compiler that the call should be
>> valid while retaining type safety? This would be really good for
>> creating fluent interfaces.
>>
>> Thanks in advance
>> Simon
>>
>
>

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Simon Krajewski
In reply to this post by Justin Donaldson-3
Hi Justin,

it is part of a small remoting/marshalling framework. With RemoteObject as base class, its method toClient(client) sets an internal variable that causes the next method call to be routed to the set client instead of being executed on the server, and returns itself:

    serverChannel.toClient(client).message(serverUser, "Welcome, client.");

I think this usage is very convenient. My User class has

    public function channelApi(channel:Channel) {
        return callback(channel.toClient, client);
    }

which allows a very simple (and fully typed) message method in Channel:

    for (user in users)
        user.channelApi(this)().message(user, text);

Regards
Simon


On 09.12.2010 06:25, Justin Donaldson wrote:
The way that type inference is set up now, the type of a method is inferred as soon as the return object type is known.  In your example, the inferred return type from "this" in doSomething() refers to a Parent class, and Parent needs to be fully typed before Child can extend it.

In order to do what you want, it would be necessary for the compiler to manage the types for functions that return an inferred "this" type differently for each class that extends the base class.  I can imagine this might add a neat trick for handling self references, but it could potentially cause problems in other cases (if someone expected the inferred type to always be "Parent").  Out of curiosity, what kinds of things were you wanting to do with this technique?

-Justin

On Wed, Dec 8, 2010 at 7:07 PM, Simon Krajewski <[hidden email]> wrote:
Hi,

thanks for your suggestion. Using cast is actually what I'm doing now, but is seems quite verbose and sort of ruins the fluency of a fluent interface. But I guess this is the best I can do for now.

Regards
Simon


On 09.12.2010 02:40, Schnell Henrik wrote:
Try this: 

var c:Child = new Child();
cast(c.doSomething(), Child).doSomethingElse();

So in my opinion the Parent class doSomething() method returns a Parent type by default even when called on a Child. 
So you need to explicitly cast it to a Child type first.

I may be wrong, I'm not a Haxe expert, but this is how I think in general OOP.

Henko

2010/12/8 Simon Krajewski <[hidden email]>
Hello list,

in this example:

   class Parent {
       public function new() { }

       public function doSomething() {
           trace("Doing something.");
           return this;
       }
   }

   class Child extends Parent {
       public function new() { super(); }

       public function doSomethingElse() {
           trace("Doing something else.");
           return this;
       }
   }

the following fails:

       var c:Child = new Child();
       c.doSomething().doSomethingElse();

because:

       Parent has no field doSomethingElse

Is there any way of convincing the compiler that the call should be valid while retaining type safety? This would be really good for creating fluent interfaces.

Thanks in advance
Simon

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org



--
blog: http://www.scwn.net
aim: iujjd
twitter: jjdonald


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: Type inference when returning this

Armén
In reply to this post by Vag Vagoff
On Thu, Dec 9, 2010 at 11:03, Vag Vagoff <[hidden email]> wrote:

> // third variant -- slightly cleaner -- maybe Child wants to be inherited
> also
>
> class GetThis<This> {
>    public function getThis() : This return throw "abstract"
> }
>
> class Parent<This> extends GetThis<This> {
>        public function new() { }
>
>        public function doSomething() : This {
>                trace("Doing something.");
>                return getThis();
>        }
> }
>
> class Child<This> extends Parent<This> {
>        public function new() super()
>
>        public function doSomethingElse() : This {
>                trace("Doing something else.");
>                return getThis();
>        }
> }
>
> class Final extends Child<Final> {
>        override public function getThis() return this
> }
>
> class Test {
>        static function main() {
>                var c:Final = new Final();
>                c.doSomething().doSomethingElse();
>        }
> }
>

Someone should write a short book:
"Abusive Language in Computer Programs" :-)

--
haXe - an open source web programming language
http://haxe.org