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