Programming to Interfaces simplification

Steven Schveighoffer schveiguy at yahoo.com
Mon Feb 24 14:07:46 PST 2014


On Mon, 24 Feb 2014 16:24:00 -0500, Frustrated <c1514843 at drdrb.com> wrote:

> On Monday, 24 February 2014 at 18:59:32 UTC, Steven Schveighoffer
> wrote:
>> On Mon, 24 Feb 2014 11:36:50 -0500, Frustrated <c1514843 at drdrb.com>  
>> wrote:
>>
>>> http://dpaste.dzfl.pl/c25655e2dfe9
>>>
>>> The code above simplifies using interfaces as the programming
>>> object. It allows one to program the derived classes as if they
>>> were not part of an abstraction by mapping the abstracted virtual
>>> methods to concrete methods.
>>>
>>> e.g.,
>>>
>>> class WindowsGui : iGui
>>> {
>>> 	WindowsButton _button;
>>> 	@property WindowsButton button(WindowsButton b) { return
>>> (_button = b); }
>>> 	
>>> 	mixin(Fixup!(WindowsGui, iButton, WindowsButton));
>>> }
>>>
>>> instead of
>>>
>>> class WindowsGui : iGui
>>> {
>>> 	WindowsButton _button;
>>>          @property iButton button(iButton b)
>>>          {
>>>              assert(cast(WindowsButton)b !is null, `Invalid object
>>> type dependency mismatch! Type: `~b.classinfo.name~` Type
>>> Expected: WindowsButton`);
>>>              auto bb = cast(WindowsButton)b;
>>>              // do work with bb.
>>>          }
>>> }
>>
>> Nice work!
>>
>>> One problem with the template is that b.classinfo.name returns
>>> the interface instead of the actual class.
>>
>> Hm... classinfo (now typeid) should get the most derived type from an  
>> instance. This may be a factor of it being an interface instance vs. a  
>> class instance. A simple test:
>>
>> Stevens-MacBook-Pro:~ steves$ cat testinterface.d
>> import std.stdio;
>>
>> interface I
>> {
>> }
>>
>> class C : I
>> {
>> }
>>
>> void main()
>> {
>>     I i = new C;
>>     writeln(typeid(i).name);
>>     writeln(typeid(cast(Object)i).name);
>> }
>> Stevens-MacBook-Pro:~ steves$ ./testinterface
>> testinterface.I
>> testinterface.C
>>
>> Looks like that is the case. Note that classinfo is not part of the  
>> language any more, and will likely be deprecated. typeid is the correct  
>> mechanism to get the TypeInfo of a derived class.
>>
>> I'm thinking this is incorrect, typeid should get the derived class  
>> type IMO. It shouldn't be that difficult or costly for the compiler to  
>> do.
>>
>
> Thanks. Now the correct type is known. One could, for example, look for  
> wrappers/adapters/etc to get a linuxbutton into a windowsbutton(if so  
> desired, throw a well informed error, etc.
>
> Hopefully though, now you see the point. It is a runtime contract
> that you make since you can't specify it at compile time(since D
> doesn't supports it).

Always have seen the point, it is why I suggested this solution.

> Unfortunately the main downside is the vtable is twice as big. Final or  
> static methods could be used for this. If the compiler could manage such  
> a system it could do the job better. (There would be no extra functions  
> needed and the calls would be faster)

First, the vtable is not per-instance, so it doesn't detract too much from  
the solution.
Second, the concrete function does not need to be virtual, make it final,  
and it won't add to the vtable.

> The issue is this: I want to program to interfaces(requiring the  
> class(WindowsGui) to use base interfaces(iButton) to satisfy the  
> interface.
>
> The problem is this compile time contract is to generic and makes coding  
> the classes more verbose. The mixin reduces the verbosity and provides a  
> runtime contract(we enforce it using asserts in this case).
>
> The benefit of the mixin is that coding WindowsGui is simpler and more  
> direct and it's dependency on WindowsButton(not iButton) is known at  
> compile time(But enforced at runtime by assert). Would you not agree?  
> Everything else is essentially identical.

I have written such libraries before (I had an OS abstraction library in  
C++), it's not always pretty.

-Steve


More information about the Digitalmars-d-learn mailing list