www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Runtime dependency checking


The code above demonstrates run-time contracts using interface 
based programming.

It provides two co-benfits: Simplified class implementation(you 
do not have to use interfaces for types which then requires 
casting that type for orthogonal behavior) and run-time contracts.

e.g., The WindowsGui class is implemented using WindowsButton and 
not iButton. This allows one to avoid having to cast the iButton 
to a WindowsButton when one wants to use the featuers of a 

A contract is created that every iButton used in WindowsGui must 
be a WindowsButton or an error is thrown. This creates a run-time 
contract or dependency between WindowsGui and WindowsButton. 
Normally in such interface based programming the contract is not 
automatic and any iButton(for example, a linux button) could be 
used for the WindowsGui. Normally this is not desired behavior as 
it limits what WindowsGui can do.

Basically when we "lift" a class to an interface and any objects 
used in that class to interfaces we create contract that is in 
general too generic(but easier to specify in the language). This 
creates generally creates a problem for the implementations of 
the interface by forcing them to be more generic than one wants. 
To solve this requires casting and type checking to get the more 
specific type. The mixin attempts to automate this. It would be 
nice if the language was extended to allow covariance on argument 
types, e.g.,

interface iGui
      property T button(T : iButton)(T button); // Syntax says 
that any T can be used as long as it is derived from 
iButton(instead of just an iButton)

class WindowsGui : iGui
      property WindowsButton button(WindowsButton  button) { }
     // implements the iGui.button property since it satisfies the 
contract and also allows us to use the type we actually want to 
use. (no explicit casts or checks)

Now, WindowsGui.button might be used with an iButton, so an 
implicit check is required to make sure that iButton is of 
WindowsButton type.

The compiler could handle this quite easily. The mixin emulates 
such a feature. The mixin is not robust though.

I seriously doubt that we'll ever get the semantics to handle 
this though.

In any case, I think there is real benefit here and it makes it 
easier to do modular programming in D with proper dependency 
checking(WindowsGui is dependent on WindowsButton, not iButton or 
LinuxButton and this dependency is retained even when we use the 
iGui and iButton interface).

Now, in the meantime I'll work on tidying up the mixin code but I 
was thinking about adding versioning. I could have a version 
property in all the types only if the versions have the same 
major version are they compatible. So a WindowsGui 3.42 is not 
compatible with a WindowsButton 2.89. Not sure if this a good way 
or if it will cause headaches later on. (I could keep a file of 
all the version compatibilities but that seems excessive)

Any ideas?

---- output ----
Trying WindowsButton with WindowsGui!
Do(): WindowsButton
WindowsButton.foo(): I'm an extra WindowsButton feature!
...WindowsButton works in WindowsGui!
Trying WindowsBorder with WindowsGui!
Do(): WindowsBorder
WindowsBorder.foo(): I'm an extra WindowsBorder feature!
...WindowsBorder works in WindowsGui!

Trying LinuxBorder with WindowsGui!
Invalid object type dependency mismatch! Type: f872.LinuxBorder 
Type Expected: WindowsBorder

Trying LinuxButton with WindowsGui!
Invalid object type dependency mismatch! Type: f872.LinuxButton 
Type Expected: WindowsButton

Trying WindowsButton with LinuxGui!
Invalid object type dependency mismatch! Type: f872.WindowsButton 
Type Expected: LinuxButton

Trying LinuxButton with LinuxGui!
Do(): LinuxButton
...LinuxButton works in LinuxGui!
Trying WindowsBorder with LinuxGui!
Invalid object type dependency mismatch! Type: f872.WindowsBorder 
Type Expected: LinuxBorder

Trying LinuxBorder with LinuxGui!
Do(): LinuxBorder
...LinuxBorder works in LinuxGui!
Feb 25 2014