Thread overview
Implicit Interface Deduction
Dec 13, 2015
Faux Amis
Dec 13, 2015
Ali Çehreli
Dec 16, 2015
Faux Amis
Dec 14, 2015
Chris Wright
Dec 16, 2015
Faux Amis
Dec 16, 2015
Meta
December 13, 2015
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?
December 13, 2015
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

December 14, 2015
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
December 16, 2015
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.
December 16, 2015
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 :(
December 16, 2015
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));
}