Uniform Inheritance Transformation

Craig Craig at Tonsils.com
Mon Mar 25 17:13:45 UTC 2019


In functional programming languages there is generally a way to 
extending objects completely through inheritance.

Suppose for example that one has a class hierarchy like

  Person
     |
     v
  Profile
     |
   Image


which is like

class Person;
class Profile : Person { Image[] images; }
class Image;

This is all standard oop.

Suppose one builds a business model using this, we will represent 
it simply as

Person[] objects;

and one can think of it just as a set of people who have 
profiles(info) with some images

Now, suppose we would like to extend our business model to 
include a graphical viewer around it. We do not want to touch the 
business model, it all works. We just want to add functionality 
"on top" of the model with the least amount of plumbing. We 
definitely do not want to have to add a lot of code to hook up 
the visual side by having to mimic the business model, it's 
basically all there.

We want a visual model that sort sort of parallels the business 
model:


  VisualPerson
       |
       v
  VisualProfile
       |
  Visual Image


These new types include visual information that is only relevant 
to the visual side and have nothing to do with the business side, 
such as the xy coordinates for the image to be displayed, a draw 
routine that will "draw" the person on the screen, etc.


The key here is that the visual hierarchy MUST parallel the 
business model and be a drop in replacement for the business 
model where ever it is used(which leverages the oop side of 
things).

So if some external app uses our Person, we can instead just drop 
in VisualPerson and with little work get a visualization of that 
person in the external app.

This requires the hierarchy to be:

class VisualPerson : Person { Person p; mixin(Wrap!Person("p")); }
class VisualProfile : VisualPerson { Profile p; VisualImage[] 
images; mixin(Wrap!Profile("p")); }
class VisualImage : Image { Image i; mixin(Wrap!Image("i")); }

Note the extensions and transformations.

Any where a Person is used, a VisualPerson can be used. 
Visualization simply "extends" non-visualization, but it only 
adds new structure, it does not remove structure.

Through the power of oop, if Person is used somewhere, we can 
simply alter the code or use an abstract factory to turn it in to 
a visualization:

Graphics g = new Graphics();
Person p = new Person("Ken")
Person p = new VisualPerson(Person("Ken"), g);

And whatever app that was written with Person in mind will now 
have visual capabilities(at least in theory, a little work will 
generally be required to hook up the graphical system).

In a functional language this is very easy to handle by using 
functors and fmap which translate between the two structures the 
various components when ever they are used(recursively, so if a 
VisualPerson is the object, fmap will use the fmap of derived 
objects to map their structure so everything gets mapped. There 
is a one to one correspondence between Visual and Non-Visual, 
Every Non-Visual structural element has a corresponding Visual 
"wrapper"(that may not add anything new))).

We can achieve similar behavior using mixin(Wrap!X("x")); and the 
composition pattern but it is rather ugly.

Ideally there would be a simple way to extend a structure that 
just provides the necessary linkage:

Hypothetically:

class VisualPersonEx : Person
{

     void  DisplayPerson();
}

class VisualProfileEx : Profile
{

}

class VisualImageEx : Image
{

}



VisualPerson = Extend!(Person,VisualPersonEx, VisualProfileEx, 
VisualImageEx);

And Extend takes care of hooking up and transmogrifying what is 
required to make everything work.



In D, I'm unsure how to find a nice way to go about handling 
this. I do not want to create duplicate the business structure 
myself since it is quite large. I simply want to provide the 
additional structure around it exactly where it is needed.


One can see that it requires one to use composition and forwarding

What I am trying to do is functionally extend a model to an 
extended model and only add whatever additional functionality 
that is required without as minimum plumbing as I possibly can to 
extend the model. Since D does not have the concept of 
models(large scale multi-faceted compound objects) it is not so 
easy. In functional languages one can specify such models more 
naturally and do away with a lot of the plumbing, in D, I don't 
know? Maybe there is something out there or an easier way than 
what I have mentioned?

The main thing here to recognize is that when extending models, 
there is a uniform and deterministic process. Every type in the 
hierachy will extend to a new type that can be plugged 
in(composition) and every new type that uses an "old" type will 
actually use the new type instead.[E.g., VisualProfile uses 
Person, but since it's a new type it actually uses VisualPerson 
which exists. Essentially `uses` is uniformly extended to create 
wrapper of a model just as we can wrap an object]

Ideally D would have something like
NewModel = WrapModel!Model;

And then one just adds the new functionality to NewModel somehow.

And then we could do

NewNewModel = WrapModel!NewModel

which further extends the model.

Each time it encapsulates the old model.

This is analogous to having inheritance of models. Eventually, of 
course, we would want n-dimensional model mapping so that 
collections("classes") of models could be extended just as we can 
extend a class now using inheritance.

Is anything like this feasible in D?  [Remember, it's not just 
about doing it, it's about doing it optimally = little plumbing 
as possible]








More information about the Digitalmars-d mailing list