back from LAC2015: re-read and simplify the code draft
This commit is contained in:
parent
2e1df16bdc
commit
51cdc85e58
2 changed files with 14 additions and 13 deletions
|
|
@ -24,11 +24,11 @@
|
|||
/** @file tree-mutator.hpp
|
||||
** Customisable intermediary to abstract generic tree mutation operations.
|
||||
** This is the foundation for generic treatment of tree altering operations,
|
||||
** and especially to handling of changes (diff) to hierarchical data structures.
|
||||
** and especially the handling of changes (diff) to hierarchical data structures.
|
||||
** The goal is to represent a standard set of conceptual operations working on
|
||||
** arbitrary data structures, without the need for these data structures to
|
||||
** comply to any interface or base type. Rather, we allow each instance to
|
||||
** define binding closures, which allows to tap into any internal data
|
||||
** define binding closures, which allows to tap into arbitrary internal data
|
||||
** representation, without any need of disclosure. The only assumption is
|
||||
** that the data to be treated is \em hierarchical and \em object-like,
|
||||
** i.e. it has (named) attributes and it may have a collection of children.
|
||||
|
|
@ -148,7 +148,8 @@ namespace diff{
|
|||
virtual void
|
||||
setAttribute (ID id, Attribute newValue)
|
||||
{
|
||||
PAR::setAttribute(id, newValue); ////////////////////TODO only as a check to verify the class chaining. Of course we do *not* want to call the inherited implementeation
|
||||
// Decorator-style chained invocation of inherited implementation
|
||||
PAR::setAttribute(id, newValue);
|
||||
|
||||
string dummy("blubb");
|
||||
change_(dummy);
|
||||
|
|
@ -164,7 +165,7 @@ namespace diff{
|
|||
struct Builder
|
||||
: PAR
|
||||
{
|
||||
using Chain = ChangeOperation<PAR>;
|
||||
using Change = ChangeOperation<PAR>;
|
||||
|
||||
Builder(PAR par)
|
||||
: PAR(par)
|
||||
|
|
@ -173,10 +174,10 @@ namespace diff{
|
|||
|
||||
/* ==== binding API ==== */
|
||||
|
||||
Builder<Chain>
|
||||
Builder<Change>
|
||||
change (Literal attributeID, function<void(string)> closure)
|
||||
{
|
||||
return Builder<Chain> (Chain (closure, *this));
|
||||
return Change (closure, *this);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -185,7 +186,7 @@ namespace diff{
|
|||
Builder<TreeMutator>
|
||||
TreeMutator::build ()
|
||||
{
|
||||
return Builder<TreeMutator>(TreeMutator());
|
||||
return TreeMutator();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7935,7 +7935,7 @@ On receiving the terms of this "diff language", it is possible to gene
|
|||
i.e. a ''unified diff'' or the ''predicate notation'' used above to describe the list diffing algorithm, just by accumulating changes.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="TreeMutator" creator="Ichthyostega" modifier="Ichthyostega" created="201503292115" modified="201504031750" tags="Model Concepts GuiPattern design draft" changecount="32">
|
||||
<div title="TreeMutator" creator="Ichthyostega" modifier="Ichthyostega" created="201503292115" modified="201504131311" tags="Model Concepts GuiPattern design draft" changecount="39">
|
||||
<pre>The TreeMutator is an intermediary to translate a generic structure pattern into heterogeneous local invocation sequences.
|
||||
|
||||
!Motivation
|
||||
|
|
@ -7978,17 +7978,17 @@ There is one fundamental problem, we'll never be able to overcome: the //opennes
|
|||
}}}
|
||||
So this looks similar, but indeed now we create //operation bindings// up front, at creation time of the client (widget). Thus, the initiative originates from the implementing code, which //offers// a method as building block to implement the mutation of a conceptual tree-like structure. Actually, these "methods" are given as //closures//, implicitly tied into the implementation context. And since this configuration invocation carries implicit type information, we may generate the necessary adapters and visitor implementation at compile time.
|
||||
|
||||
This construction pattern can be extended to offer several optional extension hooks for the clients to supply. Extended even by offering more generic hooks to deal with recursive changes to whole sub-trees or collections of children of a specific type. Facing towards the diff application, the generated TreeMutator will expose a standardised interface to support implementing all the diff verbs necessary to describe structural and data changes. Operations, attributes and properties not outfitted by the client with actual bindings will be supplemented as ~NOP-implementation, silently ignoring any changes targeted towards the corresponding structures. This is the remaining loophole: if a client "forgets" to install a binding for some part of the structure, any changes to this part will go by unnoticed.
|
||||
This construction pattern can be extended to offer several optional extension hooks for the clients to supply. Extended even by offering more generic hooks to deal with recursive changes to whole sub-trees or collections of children of a specific type. Facing towards the diff application, the generated TreeMutator will expose a standardised interface to support implementing all the diff verbs necessary to describe structural and data changes. Operations, attributes and properties not outfitted by the client with actual bindings will be supplemented as ~NOP-implementation, silently ignoring any changes targeted towards the corresponding structures. This is the remaining loophole: if a client "forgets" to install a binding for some part of the structure, any changes directed towards this part will pass by unnoticed.
|
||||
|
||||
!!!practical problems {{red{to be solved 3/2015}}}
|
||||
* still not sure how to design the generic data elements to represent "Objects" / "records"
|
||||
* still not sure how to design the generic data elements representing "Objects" / "records"
|
||||
* how to generate a suitable //attribute visitor// ^^&rarr; looks like this can be achieved with a quite classical visitor impl, just the reflect-back are functors, instead of vcalls^^
|
||||
* how to integate the recursive invocation properly
|
||||
* how to deal with collections of children
|
||||
* how to integrate typed children
|
||||
|
||||
!!!working with children
|
||||
Handling tree structured object data imposes some additional constraints, in comparision to generic changes done to a flat list. One notable difference is that there are pre-existing //attributes,// which can not be added and deleted, are known by-name, not by positional order. Another point worth noting is the fact that child objects may be segregated into several collections by type. Since our goal is to provide an intermediary with the ability to map to arbitrary structures, we need to define the primitive operations necessary to implement the structural operations represented in the form of a diff
|
||||
Handling tree structured object data imposes some additional constraints, in comparision to generic changes done to a flat list. One notable difference is that there are pre-existing //attributes,// which can not be added and deleted, are known by-name, not by positional order. Another point worth noting is the fact that child objects may be segregated into several collections by type. Since our goal is to provide an intermediary with the ability to map to arbitrary structures, we need to define the primitive operations necessary for implementing the structural operations represented in the form of a diff
|
||||
* add a child
|
||||
* remove a child
|
||||
* step to the next child
|
||||
|
|
@ -8014,9 +8014,9 @@ The contract is as follows:
|
|||
* the mutation handler has to return a reference to a suitable TreeMutator object, which is implicitly bound to the denoted track. It can be expected to be used for feeding mutations to this child right away.
|
||||
|
||||
!!!Architecture
|
||||
The distinguising trait or Lumiera's diff handling framework is to treat a //diff language// as a scope, where some verbs or predications gain a specific meaning. While a concrete {{{DiffApplicator}}} binds to a specific agent or target environment, the meaning of the remains implicit. This approach bears on the observation, that dealing with structural differences actually addresses //several layers of language.// An odered collection is one of them, some kind of object notion another one, and the exact meaning of structure yet another one.
|
||||
The distinguising trait or Lumiera's diff handling framework is to treat a //diff language// as a scope, where some verbs or predications gain a specific meaning. While a concrete {{{DiffApplicator}}} binds to a specific agent or target environment, the meaning of the binding remains implicit. This approach bears on the observation, that dealing with structural differences actually addresses //several layers of language.// An odered collection is one of them, some kind of object notion another one, and the exact meaning of structure yet another one.
|
||||
|
||||
In accordance with this understanding, the TreeMutator is shaped to form the attachment point of such a language construct onto a given structural context, which, through this very construct, remains opaque and decoupled. In the simple exemplary case of list diffing, the {{{DiffApplicator}}} requries the specialisation of some {{{DiffApplicationStrategy}}} to the concrete data container in use, most likely a STL {{{vector}}}. In a similar vein, a {{{DiffApplicator}}} for structural transformations requires the {{{DiffApplication}}}'s specialisation to a TreeMutator. Which -- consequently -- needs to expose an API well suited to implement what a structural diff language might want to express. Yet, in addition, the TreeMutator also needs a binding API to be linked into the actual structures subject to manipulation.
|
||||
In accordance with this understanding, the TreeMutator is shaped to form the attachment point of such a language construct onto a given structural context, which, through this very construct, remains opaque and decoupled. In the simple exemplary case of list diffing, the {{{DiffApplicator}}} requries the specialisation of some {{{DiffApplicationStrategy}}} to the concrete data container in use, most likely a STL {{{vector}}}. In a similar vein, a {{{DiffApplicator}}} for structural transformations requires the {{{DiffApplicationStrategy}}}'s specialisation to a TreeMutator. Which -- consequently -- needs to expose an API well suited to implement what a structural diff language might want to express. Yet, in addition, the TreeMutator also needs a binding API to be linked into the actual structures subject to manipulation.
|
||||
|
||||
At this point, practical performance considerations settle the remaining decisions: Language application is a ''double dispatch'' at least, so we won't be able to get below two indirections ever. We could strive at getting close to this theoretical minimum though. Unfortunately, one of the indirections is taken by the verbs of the language, while the other one is consumed by decoupling the language from the Applicator or Interpreter, i.e. abstracting the diff representation from the meaning of the described changes when considered within a specific target context -- which is the very core of using a diff representation.
|
||||
So we get to choose between
|
||||
|
|
|
|||
Loading…
Reference in a new issue