Thread overview
LazyInterface (simplified Boost.Interfaces)
Sep 21, 2010
kenji hara
Sep 21, 2010
bearophile
Sep 22, 2010
kenji hara
Sep 23, 2010
kenji hara
Sep 23, 2010
kenji hara
Sep 23, 2010
kenji hara
September 21, 2010
Hi.

I heard Boost.Interfaces recently. Then, it implemented by D. http://github.com/9rnsr/scrap/blob/master/interfaces/interfaces.d

How about you?
September 21, 2010
kenji hara:

> I heard Boost.Interfaces recently. Then, it implemented by D. http://github.com/9rnsr/scrap/blob/master/interfaces/interfaces.d How about you?

// static auto opDispatch(string Name, Args...)(Args args)
// {
// enum stc = 's';
// mixin(dispatch);
// }
}


But static opDispatch works:

struct Foo {
    static void opDispatch(string name, Args...)(Args args) {
        static assert(name == "hello");
    }
}
void main() {
    Foo.hello(10, 20);
}


So if you have found a bug you may add a minimized case in Bugzilla.

Bye,
bearophile
September 22, 2010
On 9/21/10 14:36 CDT, kenji hara wrote:
> Hi.
>
> I heard Boost.Interfaces recently. Then, it implemented by D.
> http://github.com/9rnsr/scrap/blob/master/interfaces/interfaces.d
>
> How about you?

Hi Kenji,


Looking very interesting. One thing I'd change would be the interface definition. Ideally the client code would look like this:

static class A
{
  int draw(){ return 10; }
}

static class B : A
{
  int draw(){ return 20; }
}

interface Drawable
{
  int draw();
};

unittest
{
  Drawable d = adaptTo!Drawable(new A);
  assert(d.draw() == 10);
  d = adaptTo!Drawable(new B);
  assert(d.draw() == 20);
}

adaptTo would rely on introspection and code generation to define an implementation of Drawable that forwards calls to an object.


Andrei
September 22, 2010
Thanks for your advise, Andrei.

I will try to implement adaptTo!T .

Kenji Hara

2010/9/22 Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>:
> On 9/21/10 14:36 CDT, kenji hara wrote:
>>
>> Hi.
>>
>> I heard Boost.Interfaces recently. Then, it implemented by D. http://github.com/9rnsr/scrap/blob/master/interfaces/interfaces.d
>>
>> How about you?
>
> Hi Kenji,
>
>
> Looking very interesting. One thing I'd change would be the interface definition. Ideally the client code would look like this:
>
> static class A
> {
>  int draw(){ return 10; }
> }
>
> static class B : A
> {
>  int draw(){ return 20; }
> }
>
> interface Drawable
> {
>  int draw();
> };
>
> unittest
> {
>  Drawable d = adaptTo!Drawable(new A);
>  assert(d.draw() == 10);
>  d = adaptTo!Drawable(new B);
>  assert(d.draw() == 20);
> }
>
> adaptTo would rely on introspection and code generation to define an implementation of Drawable that forwards calls to an object.
>
>
> Andrei
>
September 23, 2010
I implemented adaptTo .

http://github.com/9rnsr/scrap/blob/master/interfaces/interfaces.d

Kenji Hara

2010/9/22 kenji hara <k.hara.pg@gmail.com>:
> Thanks for your advise, Andrei.
>
> I will try to implement adaptTo!T .
>
> Kenji Hara
>
> 2010/9/22 Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org>:
>> On 9/21/10 14:36 CDT, kenji hara wrote:
>>>
>>> Hi.
>>>
>>> I heard Boost.Interfaces recently. Then, it implemented by D. http://github.com/9rnsr/scrap/blob/master/interfaces/interfaces.d
>>>
>>> How about you?
>>
>> Hi Kenji,
>>
>>
>> Looking very interesting. One thing I'd change would be the interface definition. Ideally the client code would look like this:
>>
>> static class A
>> {
>>  int draw(){ return 10; }
>> }
>>
>> static class B : A
>> {
>>  int draw(){ return 20; }
>> }
>>
>> interface Drawable
>> {
>>  int draw();
>> };
>>
>> unittest
>> {
>>  Drawable d = adaptTo!Drawable(new A);
>>  assert(d.draw() == 10);
>>  d = adaptTo!Drawable(new B);
>>  assert(d.draw() == 20);
>> }
>>
>> adaptTo would rely on introspection and code generation to define an implementation of Drawable that forwards calls to an object.
>>
>>
>> Andrei
>>
>
September 23, 2010
On 9/23/10 8:09 CDT, kenji hara wrote:
> I implemented adaptTo .
>
> http://github.com/9rnsr/scrap/blob/master/interfaces/interfaces.d
>
> Kenji Hara

This is great work, Kenji! I'm very glad about this because it uses introspection to implement an important feature. Such post-hoc interface binding is a core feature in quite a few languages.

If you agree, I am committed to advocate adopting this abstraction for Phobos in module std.typecons, with credit.

All - a bit of bikeshedding - what is a better name for adaptTo? I know there is a consecrated name for such late matching of an interface, but I can't remember it.

A few nits about the implementation:

* In line 73 it looks like you don't support covariance of return types. Could you fix that? Example (add it to the unittests, too):

class C
{
  long draw(){ return 10; }
}
interface Drawable
{
  int draw();
}

The override should be legit.

* Throughout: everything that is a value should start with a lowercase letter; everything that is not a value (e.g. type, type tuple) should start with an uppercase letter. In particular your "result" convention should use "Result" for type results and "result" for value results.

* Code shouldn't use uppercase "i" as a symbol name - it's confusable with "1".

Congratulations! This is great work indeed.


Thanks,

Andrei
September 23, 2010
Thanks very much!

> If you agree, I am committed to advocate adopting this abstraction for Phobos in module std.typecons, with credit.
Of couse, I agree.


> All - a bit of bikeshedding - what is a better name for adaptTo? I know there is a consecrated name for such late matching of an interface, but I can't remember it.
from here(http://www.coderage.com/interfaces/), I found two keywords.
- Non-intrusive dynamic polymorphism
- Aspect Oriented Programming
How about you?


I understood the covariance problem. I think that I should also support it. By the way, there is a question about this sample code.
> class C
> {
>  long draw(){ return 10; }
> }
> interface Drawable
> {
>  int draw();
> }
In my opinion, C can derive from Drawable ideally.
so, it will be satisfied with this code.

static assert(isCovariantWith!(typeof(C.draw), typeof(Drawable.draw)));

Correctness of it is like this, isn't it?
class C
{
 int draw(){ return 10; }
}
interface Drawable
{
 long draw();
}


> The override should be legit.
I will fix them.


Kenji Hara
September 23, 2010
I supported covariance of return types.
Please check it.

2010/9/24 kenji hara <k.hara.pg@gmail.com>:
> Thanks very much!
>
>> If you agree, I am committed to advocate adopting this abstraction for Phobos in module std.typecons, with credit.
> Of couse, I agree.
>
>
>> All - a bit of bikeshedding - what is a better name for adaptTo? I know there is a consecrated name for such late matching of an interface, but I can't remember it.
> from here(http://www.coderage.com/interfaces/), I found two keywords.
> - Non-intrusive dynamic polymorphism
> - Aspect Oriented Programming
> How about you?
>
>
> I understood the covariance problem. I think that I should also support it. By the way, there is a question about this sample code.
>> class C
>> {
>>  long draw(){ return 10; }
>> }
>> interface Drawable
>> {
>>  int draw();
>> }
> In my opinion, C can derive from Drawable ideally.
> so, it will be satisfied with this code.
>
> static assert(isCovariantWith!(typeof(C.draw), typeof(Drawable.draw)));
>
> Correctness of it is like this, isn't it?
> class C
> {
>  int draw(){ return 10; }
> }
> interface Drawable
> {
>  long draw();
> }
>
>
>> The override should be legit.
> I will fix them.
>
>
> Kenji Hara
>
September 24, 2010
On 9/23/10 14:13 CDT, kenji hara wrote:
> I supported covariance of return types.
> Please check it.

Excellent! And sorry, indeed I got it backwards: if the interface returns e.g. long, the implementation is allowed to return int. Generally if the interface returns T, the implementation is allowed to return any U implicitly convertible to T.

> 2010/9/24 kenji hara<k.hara.pg@gmail.com>:
>> Thanks very much!
>>
>>> If you agree, I am committed to advocate adopting this abstraction for Phobos in module std.typecons, with credit.
>> Of couse, I agree.

Perfect, thanks! Stay tuned.

>>> All - a bit of bikeshedding - what is a better name for adaptTo? I know there is a consecrated name for such late matching of an interface, but I can't remember it.
>> from here(http://www.coderage.com/interfaces/), I found two keywords.
>> - Non-intrusive dynamic polymorphism
>> - Aspect Oriented Programming
>> How about you?

Well the first term is, I think, invented by the author of the Interfaces Boost library, and the second is unrelated. I discussed your implementation with Walter and he recognized it as an instance of structural conformance. Indeed, check this paper that does the same for Java: http://tinyurl.com/2ct69t7.

I think adaptTo should be therefore called structuralCast.

Also, Kenji, I very much recommend you read this paper: http://tinyurl.com/2e3vmmx. It contains further idea on how you can extend structuralCast to multiple interfaces. I actually have some old code that might help there.

Here are a few more suggestions for future work:

* The object returned by structuralCast should offer the ability to access the original object, be it via an explicit function or an implicit mechanism such as alias this.

* structuralCast should work with a struct as input. The object returned stores a copy of the struct inside and implements the interface in terms of calls to the struct's member functions.

* structuralCast should work with a pointer to a struct as input and work as above, except it doesn't make a copy - it stores the pointer and forwards method calls to it. (This is unsafe.)

* structuralCast should work to cast a struct to another. The requirements for accepting a structural cast from S to T are as follows:

a) T must be a prefix of S, i.e. all fields in T appear in the same order and with the same names at the beginning of S. For example:

struct Point2D {
  int x, y;
}

struct Point3D {
  int x, y, z;
}

struct Point2DColor {
  int x, y;
  Color color;
}

struct Point3DColor {
  int x, y, z;
  Color color;
}

In the example above, Point2D is a prefix of all others, and Point3D is a prefix of Point3DColor.

b) All fields that are common to S and T must be public in both. structuralCast should not give access to private data and provide opportunity for breaking invariants.

If these conditions are satisfied, then given a reference or a pointer to S, structuralCast gives you back (safely) a reference or a pointer to T. The implementation is a simple cast of pointers, but the point is that the function is @trusted, i.e. it provides a safe restricted interface over the unsafe cast.


Andrei