www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Implicit Interface Deduction

reply Faux Amis <faux amis.com> writes:
interface IA {}
interface IB {}
interface IC {}
interface IAB : IA, IB {}
interface IBC : IB, IC {}

class C : IA, IB, IC {}
// Defining C as : IAB, IBC
// is not really scalable ;)

void main()
{
  IAB c = new C(); // This doesn't work.
}
// Any suggestions?
Dec 13 2015
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 12/13/2015 02:09 PM, Faux Amis wrote:
 interface IA {}
 interface IB {}
 interface IC {}
 interface IAB : IA, IB {}
 interface IBC : IB, IC {}

 class C : IA, IB, IC {}
 // Defining C as : IAB, IBC
 // is not really scalable ;)
It is not automatic at least because of implementation details: The compiler should not generate a vtbl for every possible interface. Is it acceptable to add IAB and IBC to C? If so, this works: import std.stdio; class C : IA, IB, IC, IAB, IBC { void a() { writeln(__FUNCTION__); } void b() { writeln(__FUNCTION__); } void c() { writeln(__FUNCTION__); } } Ali
Dec 13 2015
parent Faux Amis <faux amis.com> writes:
On Mon 14/12/2015 00:27, Ali Çehreli wrote:
 On 12/13/2015 02:09 PM, Faux Amis wrote:
 interface IA {}
 interface IB {}
 interface IC {}
 interface IAB : IA, IB {}
 interface IBC : IB, IC {}

 class C : IA, IB, IC {}
 // Defining C as : IAB, IBC
 // is not really scalable ;)
It is not automatic at least because of implementation details: The compiler should not generate a vtbl for every possible interface. Is it acceptable to add IAB and IBC to C? If so, this works: import std.stdio; class C : IA, IB, IC, IAB, IBC { void a() { writeln(__FUNCTION__); } void b() { writeln(__FUNCTION__); } void c() { writeln(__FUNCTION__); } } Ali
So, you would just add the combined interfaces to the definition. Maybe with some nice separation this would be acceptable. class C : IA, IB, IC, IAB, IBC // implicit { // body } Enforcement would be difficult. Forgetting IB, for instance, will still compile.
Dec 16 2015
prev sibling next sibling parent reply Chris Wright <dhasenan gmail.com> writes:
On Sun, 13 Dec 2015 23:09:47 +0100, Faux Amis wrote:

 interface IA {}
 interface IB {}
 interface IC {}
 interface IAB : IA, IB {} interface IBC : IB, IC {}
 
 class C : IA, IB, IC {}
 // Defining C as : IAB, IBC // is not really scalable ;)
 
 void main()
 {
   IAB c = new C(); // This doesn't work.
 }
 // Any suggestions?
If you really can't modify the declaration to suit, there are two options. The first is to use casts. If a function would require something that's both IA and IB, it takes an IA and casts to IB. It can use contracts to ensure that things are of the right type. Ugly, but it works. The second is to use templates to generate the interface you need and appropriate wrapper classes. Then you need to manually wrap variables in those generated wrapper classes wherever you need to pass them. You'll end up with an API like: alias IABC = Union!(IA, IB, IC); void foo(IABC.Interface iabc) {} auto c = new C; foo(IABC.wrap(c)); If you really want to go this way, std.typecons might help. Or I hacked up something horrific here: http://dpaste.dzfl.pl/0464f723580f
Dec 13 2015
parent Faux Amis <faux amis.com> writes:
On Mon 14/12/2015 02:45, Chris Wright wrote:
 On Sun, 13 Dec 2015 23:09:47 +0100, Faux Amis wrote:

 interface IA {}
 interface IB {}
 interface IC {}
 interface IAB : IA, IB {} interface IBC : IB, IC {}

 class C : IA, IB, IC {}
 // Defining C as : IAB, IBC // is not really scalable ;)

 void main()
 {
    IAB c = new C(); // This doesn't work.
 }
 // Any suggestions?
If you really can't modify the declaration to suit, there are two options. The first is to use casts. If a function would require something that's both IA and IB, it takes an IA and casts to IB. It can use contracts to ensure that things are of the right type. Ugly, but it works. The second is to use templates to generate the interface you need and appropriate wrapper classes. Then you need to manually wrap variables in those generated wrapper classes wherever you need to pass them. You'll end up with an API like: alias IABC = Union!(IA, IB, IC); void foo(IABC.Interface iabc) {} auto c = new C; foo(IABC.wrap(c)); If you really want to go this way, std.typecons might help. Or I hacked up something horrific here: http://dpaste.dzfl.pl/0464f723580f
The thing is, I would like to define my class by its basic components. It makes it very clear what type of functionality it exposes. I do not see how the Union template is different from interface IABC : IA, IB, IC Maybe I don't get :(
Dec 16 2015
prev sibling parent Meta <jared771 gmail.com> writes:
On Sunday, 13 December 2015 at 22:09:47 UTC, Faux Amis wrote:
 interface IA {}
 interface IB {}
 interface IC {}
 interface IAB : IA, IB {}
 interface IBC : IB, IC {}

 class C : IA, IB, IC {}
 // Defining C as : IAB, IBC
 // is not really scalable ;)

 void main()
 {
  IAB c = new C(); // This doesn't work.
 }
 // Any suggestions?
I believe you can use std.typecons.wrap for this. import std.typecons: wrap; import std.stdio; interface IA { void quack(); } interface IB { int divBy2(int n); } interface IAB: IA, IB { } class Test: IA, IB { override void quack() { writeln("quack!"); } override int divBy2(int n) { return n / 2; } } void main() { auto t = new Test(); IAB tAsIAB = t.wrap!IAB; tAsIAB.quack(); writeln(tAsIAB.divBy2(4)); assert(!is(Test : IAB)); assert(is(tAsIAB: IAB)); }
Dec 16 2015