http://dpaste.dzfl.pl/80c6225ed090

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 WindowsButton.

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!

Reply via email to