www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Restriction on interface function types

reply "Steve Teale" <steve.teale britseyeview.com> writes:
interface I
{
    auto myType();
}

class A: I
{
    auto myType() { return cast(A) null; }
}

void main()
{
    I x = getSomeI();
    typeof(x.myType()) y;
}
Mar 12 2014
next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 12 March 2014 at 10:57:10 UTC, Steve Teale wrote:
 interface I
 {
    auto myType();
 }

 class A: I
 {
    auto myType() { return cast(A) null; }
 }

 void main()
 {
    I x = getSomeI();
    typeof(x.myType()) y;
 }

Seems like you want covariance? I don't see how else having an interface that returns "auto" could work. That said, I'd expect this to work: //---- interface I { I myType(); } class A: I { //auto myType() { return cast(A) null; } //Nope A myType() { return cast(A) null; } //OK } //---- But app
Mar 12 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 12 Mar 2014 06:57:08 -0400, Steve Teale  
<steve.teale britseyeview.com> wrote:

 interface I
 {
     auto myType();
 }

 class A: I
 {
     auto myType() { return cast(A) null; }
 }

 void main()
 {
     I x = getSomeI();
     typeof(x.myType()) y;
 }

What you want simply isn't possible. An interface binds at runtime, and you need to declare types at compile-time. You can't use an interface method to define the type of y. -Steve
Mar 12 2014
prev sibling next sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
On Wednesday, 12 March 2014 at 11:13:00 UTC, monarch_dodra wrote:
 That said, I'd expect this to work:

 //----
 interface I
 {
    I myType();
 }

 class A: I
 {
    //auto myType() { return cast(A) null; } //Nope
    A myType() { return cast(A) null; } //OK
 }
 //----

 Yup, covariance desired, but

import std.stdio; interface I { I myType(); } class A: I { A myType() { return cast(A) null; } void foo() { writeln("foo"); } } void main() { I a = new A(); writeln(typeof(a.myType()).stringof); } returns I Seems like a bug to me. Steve
Mar 12 2014
prev sibling next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Wednesday, 12 March 2014 at 13:05:07 UTC, Steve Teale wrote:
    I a = new A();

 Seems like a bug to me.

You are working through the interface, so the type will be what was written in the interface. If you made that "A a = new A();", then you could see type A on the override. But the interface has no way of knowing which child class is there at compile time so it has to work through base types only.
Mar 12 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 12 Mar 2014 09:05:05 -0400, Steve Teale  
<steve.teale britseyeview.com> wrote:

 On Wednesday, 12 March 2014 at 11:13:00 UTC, monarch_dodra wrote:
 That said, I'd expect this to work:

 //----
 interface I
 {
    I myType();
 }

 class A: I
 {
    //auto myType() { return cast(A) null; } //Nope
    A myType() { return cast(A) null; } //OK
 }
 //----

 Yup, covariance desired, but

import std.stdio; interface I { I myType(); } class A: I { A myType() { return cast(A) null; } void foo() { writeln("foo"); } } void main() { I a = new A(); writeln(typeof(a.myType()).stringof); } returns I Seems like a bug to me.

No, not a bug. What you want is actually not possible. To demonstrate further: void bad(I i) { typeof(i.myType()) x; } class A : I { A myType() { return cast(A)null;} } class B : I { B myType() {return cast(B) null;} } void main() { I[] arr = [new A, new B]; foreach(i; arr) {bad(i);} } How is the compiler to build it's one copy of bad? Should x be typed as A or B? Or something not even seen in this module that could derive from I? -Steve
Mar 12 2014
prev sibling next sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
On Wednesday, 12 March 2014 at 11:56:43 UTC, Steven Schveighoffer 
wrote:
 On Wed, 12 Mar 2014 06:57:08 -0400, Steve Teale 
 <steve.teale britseyeview.com> wrote:


 What you want simply isn't possible. An interface binds at 
 runtime, and you need to declare types at compile-time. You 
 can't use an interface method to define the type of y.

 -Steve

Steve OK, it was a bad illustrative example, but (cast(typeof(a.myType()) whatever).foo(); could be useful, when foo() is not in the interface. It was the failure of auto in an interface that I was remarking on - should at least be documented. Also the covariant return values as suggested by md don't work either. Steve
Mar 12 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 12 Mar 2014 09:13:08 -0400, Steve Teale  
<steve.teale britseyeview.com> wrote:

 On Wednesday, 12 March 2014 at 11:56:43 UTC, Steven Schveighoffer wrote:
 On Wed, 12 Mar 2014 06:57:08 -0400, Steve Teale  
 <steve.teale britseyeview.com> wrote:


 What you want simply isn't possible. An interface binds at runtime, and  
 you need to declare types at compile-time. You can't use an interface  
 method to define the type of y.

 -Steve

Steve OK, it was a bad illustrative example, but (cast(typeof(a.myType()) whatever).foo(); could be useful, when foo() is not in the interface. It was the failure of auto in an interface that I was remarking on - should at least be documented. Also the covariant return values as suggested by md don't work either.

Auto doesn't work if you don't define what it returns. Auto is not a type in itself, it means "infer the type". If there's nothing to infer with, it's an error. -Steve
Mar 12 2014
prev sibling next sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
On Wednesday, 12 March 2014 at 13:12:20 UTC, Steven Schveighoffer 
wrote:
 On Wed, 12 Mar 2014 09:05:05 -0400, Steve Teale 
 <steve.teale britseyeview.com> wrote:

 How is the compiler to build it's one copy of bad? Should x be 
 typed as A or B? Or something not even seen in this module that 
 could derive from I?

 -Steve

Let's take bad() away, and instead: class A : I { A myType() { return cast(A)null;} final void foo(); } class B : I { B myType() {return cast(B) null;} final void bar(); } void main() { I[] arr = [new A, new B]; foreach(i; arr) { (cast(typeof(i.myType()) i).foo() } } myType() is a virtual function, so calling it through the interface type should get the correct version right?, and then the cast should cause a call to A or B.
Mar 12 2014
prev sibling next sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
On Wednesday, 12 March 2014 at 13:34:33 UTC, Steve Teale wrote:
 class A : I
 {
    A myType() { return cast(A)null;}
    final void foo();
 }

 class B : I
 {
    B myType() {return cast(B) null;}
    final void bar();
 }

 void main()
 {
    I[] arr = [new A, new B];
    foreach(i; arr) { (cast(typeof(i.myType()) i).foo() }
 }

 myType() is a virtual function, so calling it through the 
 interface type should get the correct version right?, and then 
 the cast should cause a call to A or B.

Aargh - not final void foo() and final void bar(), just void foo() in each case - a virtual function not mentioned by the interface.
Mar 12 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 12 Mar 2014 09:34:32 -0400, Steve Teale  
<steve.teale britseyeview.com> wrote:

 On Wednesday, 12 March 2014 at 13:12:20 UTC, Steven Schveighoffer wrote:
 On Wed, 12 Mar 2014 09:05:05 -0400, Steve Teale  
 <steve.teale britseyeview.com> wrote:

 How is the compiler to build it's one copy of bad? Should x be typed as  
 A or B? Or something not even seen in this module that could derive  
 from I?

 -Steve

Let's take bad() away, and instead: class A : I { A myType() { return cast(A)null;} final void foo(); } class B : I { B myType() {return cast(B) null;} final void bar(); } void main() { I[] arr = [new A, new B]; foreach(i; arr) { (cast(typeof(i.myType()) i).foo() } } myType() is a virtual function, so calling it through the interface type should get the correct version right?, and then the cast should cause a call to A or B.

The type cannot be determined at runtime, it's a static language. foreach(i; arr) { typeof(i.myType()) x = cast(i.myType()) i; x.foo();} What is typeof(x)? It needs to be decided at compile time. -Steve
Mar 12 2014
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 12 March 2014 at 13:34:33 UTC, Steve Teale wrote:
 On Wednesday, 12 March 2014 at 13:12:20 UTC, Steven 
 Schveighoffer wrote:
 On Wed, 12 Mar 2014 09:05:05 -0400, Steve Teale 
 <steve.teale britseyeview.com> wrote:

 How is the compiler to build it's one copy of bad? Should x be 
 typed as A or B? Or something not even seen in this module 
 that could derive from I?

 -Steve

Let's take bad() away, and instead: class A : I { A myType() { return cast(A)null;} final void foo(); } class B : I { B myType() {return cast(B) null;} final void bar(); } void main() { I[] arr = [new A, new B]; foreach(i; arr) { (cast(typeof(i.myType()) i).foo() } } myType() is a virtual function, so calling it through the interface type should get the correct version right?, and then the cast should cause a call to A or B.

It will *call* the correct version, but the signature used will still statically be the interface's signature. It can make a difference when you *statically* know you are in a derived type: I i = new A(); A a = new A(); I ii = i.myType(); A aa = a.myType(); Here, the call to "myType", in both cases, will "runtime" resolve to A.myType(). *However*, the static type used to return the value, will not be the same.
Mar 12 2014
prev sibling next sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
On Wednesday, 12 March 2014 at 13:45:30 UTC, Steven Schveighoffer 
wrote:

 What is typeof(x)? It needs to be decided at compile time.

 -Steve

OK, squirm, squirm - I misunderstood the examples for typeof. Will you take a look at my last post on d.learn please. What I describe there is the motivation for my squirming. Can you suggest a compile-time way of telling ControlSet what class it is targeting at the point where an instance of it is declared? Sorry Steve
Mar 12 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 12 Mar 2014 09:51:32 -0400, monarch_dodra <monarchdodra gmail.com>  
wrote:

 On Wednesday, 12 March 2014 at 13:34:33 UTC, Steve Teale wrote:

 void main()
 {
    I[] arr = [new A, new B];
    foreach(i; arr) { (cast(typeof(i.myType()) i).foo() }
 }

 myType() is a virtual function, so calling it through the interface  
 type should get the correct version right?, and then the cast should  
 cause a call to A or B.

It will *call* the correct version, but the signature used will still statically be the interface's signature.

There is no foo in the interface definition. The code is invalid, as is the idea you can declare variables based on a runtime type definition. -Steve
Mar 12 2014
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 12 Mar 2014 09:54:00 -0400, Steve Teale  
<steve.teale britseyeview.com> wrote:

 On Wednesday, 12 March 2014 at 13:45:30 UTC, Steven Schveighoffer wrote:

 What is typeof(x)? It needs to be decided at compile time.

 -Steve

OK, squirm, squirm - I misunderstood the examples for typeof. Will you take a look at my last post on d.learn please. What I describe there is the motivation for my squirming. Can you suggest a compile-time way of telling ControlSet what class it is targeting at the point where an instance of it is declared?

I saw that, but I think what you encountered was a bug in the compiler or differently-generated vtables. I think you should focus on trying to identify and fix the bug rather than trying to exploit a workaround. One thing to try is re-compiling all your code. Any changes in vtables will mess up the linkage. If the compiler thinks your function to call is in index 2 in one compilation, but it's in index 3 in another, bad things will happen :) -Steve
Mar 12 2014
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 12 March 2014 at 13:55:35 UTC, Steven Schveighoffer 
wrote:
 On Wed, 12 Mar 2014 09:51:32 -0400, monarch_dodra 
 <monarchdodra gmail.com> wrote:

 On Wednesday, 12 March 2014 at 13:34:33 UTC, Steve Teale wrote:

 void main()
 {
   I[] arr = [new A, new B];
   foreach(i; arr) { (cast(typeof(i.myType()) i).foo() }
 }

 myType() is a virtual function, so calling it through the 
 interface type should get the correct version right?, and 
 then the cast should cause a call to A or B.

It will *call* the correct version, but the signature used will still statically be the interface's signature.

There is no foo in the interface definition.

I meant call relative to "myType()". I can see how that was not clear actually. Sorry.
 The code is invalid, as is the idea you can declare variables 
 based on a runtime type definition.

Yup.
Mar 12 2014
prev sibling next sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
On Wednesday, 12 March 2014 at 14:28:02 UTC, Steven Schveighoffer 
wrote:
 I saw that, but I think what you encountered was a bug in the

focus on trying to identify and fix the bug rather than trying to exploit a workaround. One thing to try is re-compiling all your code. Any changes in vtables will mess up the linkage. If the compiler thinks your function to call is in index 2 in one compilation, but it's in index 3 in another, bad things will happen :)

Recompilation has been frequent, and the makefile for the plugin refers to the sources for the app, and is otherwise just a single source file, so I don't think it is that. My primary suspicion is that I am linking both the plugin and the app using the static gtkd-2 library. I believe the next step is to link both against a shared library version of gtkd-2. So far, I've had no success in building that. If the library code has static module constructors/destructors, or some such alternative down at the GTK+3 OOP C level, that uses a distinct text or data segment or something, then I can understand that I might well be hosed. It's also noteworthy that I can't use an interface as a 'base class' for the plugin, even though the system should work with quite a limited set of methods. That works to the extent that methods that don't access data work OK, but if they do, the edifice comes tumbling down. I'll have to brush up my command-line GDB skills to get much further - something I'm not looking forward to. Last time I did it was pre Iain Bucklaw when I was trying to sort out crashes in GDC. The ability to dynamically load D shared libraries into a D program is something that's been way up my wish list since about 2006. Seems like there's some way to go yet. Even further for Windows, where we probably need a new linker! At present, the app seems to be working pretty well with a plugin, as I have special cased the calls to host.onCSNotify() etc to apply the cast when the target is my main base class. Other uses will generally be entirely local to a plugin. So it might just stay like that for a while until I break it again. Thanks Steve
Mar 12 2014
prev sibling next sibling parent Iain Buclaw <ibuclaw gdcproject.org> writes:
On 12 March 2014 18:17, Steve Teale <steve.teale britseyeview.com> wrote:
 On Wednesday, 12 March 2014 at 14:28:02 UTC, Steven Schveighoffer wrote:
 I saw that, but I think what you encountered was a bug in the

trying to identify and fix the bug rather than trying to exploit a workaround. One thing to try is re-compiling all your code. Any changes in vtables will mess up the linkage. If the compiler thinks your function to call is in index 2 in one compilation, but it's in index 3 in another, bad things will happen :)

Recompilation has been frequent, and the makefile for the plugin refers to the sources for the app, and is otherwise just a single source file, so I don't think it is that. My primary suspicion is that I am linking both the plugin and the app using the static gtkd-2 library. I believe the next step is to link both against a shared library version of gtkd-2. So far, I've had no success in building that. If the library code has static module constructors/destructors, or some such alternative down at the GTK+3 OOP C level, that uses a distinct text or data segment or something, then I can understand that I might well be hosed. It's also noteworthy that I can't use an interface as a 'base class' for the plugin, even though the system should work with quite a limited set of methods. That works to the extent that methods that don't access data work OK, but if they do, the edifice comes tumbling down. I'll have to brush up my command-line GDB skills to get much further - something I'm not looking forward to. Last time I did it was pre Iain Bucklaw when I was trying to sort out crashes in GDC.

My GDB work is yet to be fully released into the wild, but it's looking as a good solid base from where I'm testing.
Mar 12 2014
prev sibling next sibling parent "Frustrated" <Frustrated nowhere.com> writes:
On Wednesday, 12 March 2014 at 10:57:10 UTC, Steve Teale wrote:
 interface I
 {
    auto myType();
 }

 class A: I
 {
    auto myType() { return cast(A) null; }
 }

 void main()
 {
    I x = getSomeI();
    typeof(x.myType()) y;
 }

Check out: http://forum.dlang.org/thread/ljqbcbitfptxqjauppte forum.dlang.org / http://dpaste.dzfl.pl/6c90ca418996 It does what you want. As mentioned, you can't quite do this at compile time because the types must be known(or else just use object or a void *). You can, though do this at runtime: interface I { I myType(); // can return anything that derives from I } class A : I { final A _myType() { return cast(A) null; } //mixin(AbstractToInterface!(A, I, A)); // (won't work as is because only return type of myType will be different. Need to use different names) // The mixin would create the following function if slightly modified I myType() { return _myType; } } void main() { I x = getSomeI(); typeof(x._myType()) y1; typeof(x.myType()) y2; typeof(cast(Object)x.myType()) y; } y1 = y2 = I, y = A. (cast(Object) has to do with the weird way D handles interface types) Note, that this code works in that if a new class B is created, it can return it's type: class B : I { final B _myType() { return cast(B) null; } I myType() { return _myType; } } If getSomeI() returns B then y = B. Of course it's way easier just to do typeof(cast(Object)x) y; unless you want to potentially return different objects.
Mar 12 2014
prev sibling next sibling parent "Chris Williams" <yoreanon-chrisw yahoo.co.jp> writes:
On Wednesday, 12 March 2014 at 11:56:43 UTC, Steven Schveighoffer 
wrote:
 What you want simply isn't possible. An interface binds at 
 runtime, and you need to declare types at compile-time. You 
 can't use an interface method to define the type of y.

Here's the method that is used in Phobos: http://forum.dlang.org/thread/yagdbyegdkibhaqlbyid forum.dlang.org#post-zkdhdiszjklaepgkbxpj:40forum.dlang.org
Mar 12 2014
prev sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
On Wednesday, 12 March 2014 at 19:05:40 UTC, Iain Buclaw wrote:

 My GDB work is yet to be fully released into the wild, but it's
 looking as a good solid base from where I'm testing.

You're a hero Iain. Steve
Mar 12 2014