diff --git a/doc/technical/library/DiffFramework.txt b/doc/technical/library/DiffFramework.txt index 2208a636b..5afce5c78 100644 --- a/doc/technical/library/DiffFramework.txt +++ b/doc/technical/library/DiffFramework.txt @@ -75,7 +75,7 @@ diff detection schemes, especially those geared at text diff detection, engage i of producing an ``optimal'' diff, which effectively means to build specifically tuned pattern or decision tables, from which the final diff can then be pulled or interpreted. We acknowledge that in our case building a lookup table index with additional annotations can be -as bad as O(n^2^) and worse; we might well be able to do better, but likely for the price of +as bad as O(n^2^) and worse; we _might_ be able to do better, but likely for the price of turning the algorithm into some kind of mental challenge.] In case this turns out as a performance problem, we might consider integrating the index maintenance into the data structure to be diffed, which shifts the additional impact of @@ -199,14 +199,14 @@ link:{ldoc}/design/architecture/ExternalTreeDescription.html[»External Tree Des _symbolic representation_ of hierarchically structured elements, without actually implementing them. The purpose of this ``external'' description is to largely remove the need for a central data model to work against. A _symbolic diff message_ allows to propagate data and structure changes, -without even using the same data representation at both ends. +without even using the same data representation at both sides of the collaboration. Generic Node Record ~~~~~~~~~~~~~~~~~~~ For this to work, we need some very generic meta representation. This can be a textual representation (e.g. JSON) -- but within the application it seems more appropriate to use an abstracted and unspecific typed data representation, akin to ``JSON with typed language data''. It can be considered _symbolic,_ -insofar it isn't the data, it refers to it. For this approach to work, we need the following parts: +insofar it isn't the data, it refers to it. To make such an approach work, we need the following parts: - a _generic node_, which has an _identity_ and some payload data. This `GenNode` is treated as elementary value. - a _record_ made from a collection of generic nodes, to take on the abstracted role of an object. Such a @@ -286,3 +286,43 @@ verb `emu(ID)`:: and the parent scope with all existing diff state is _popped from an internal stack._ + +representation of objects +~~~~~~~~~~~~~~~~~~~~~~~~~ +While we are talking about _structured data,_ in fact what are about to handle are *objects*, understood in the standard +flavour of object orientation, where an object is the instance of a type and offers a contract. Incidentally, this is +not the original, ``pure'' meaning of object orientation, but the one that became prolific in brining our daily practice +closer to the inherent structuring of modern human organisation. And in dealing with this kind of object, we sometimes +get into conflict with the essentially open and permissive nature of structured data. So we need to establish a +mapping rule, which translates into additional conventions about how to spell out matters in the diff language. + +We choose to leave this largely on the level of stylistic rules, thus stressing the language nature of the diff. +Even when this bears the danger to produce an exception very late, when it comes to applying the diff to a target +data structure. The intention behind this whole diff approach is to transform tight coupling with strict rules +into a loose collaboration based on a common understanding. So generally we'll assume the diff is just right, +and if not, we'll get what we deserve.footnote:[This gives rise to a tricky discussion about loss of strictness +and the costs incurred by that happening. We should not treat this topic in isolation, but rather consider that +loose coupling was chosen to avoid far more serious problems caused by tight coupling, and especially the poisoning +and dire consequences of a global fixed common data model, when used in a large, not homogeneous system. +But when a system indeed is not homogeneous, we better try to make each part open-closed, open for change +but closed against extension. This is especially true in the case of the UI.] + + +object representation protocol +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +A diff is created to tell some partner about our data, and the »protocol to describe an object« is as follows + +- the ID is the object's identity and is once given, right at start, and never changed +- we spell out any metadata (esp. a type information) first, followed by all attributes, + and then followed by contents of the object's scope (children). +- attributes are to be given in a way not in contradiction to the more stringent semantics + of an object field or property + + * never attempt to re-order or delete such attributes, since their presence is fixed in the class definition + * when a field is mandatory _by its nature,_ it shall be required in construction, and the corresponding data + is to be given with the `ins` verb causing the constructor call + * on the other hand, the data for an optional field, when present, shall be spelled out by `ins` verb + after construction, with the first _population diff._ + * we do not support attribute map semantics (or extended ``object properties'' of any kind). + + If necessary, treat them as nested entity with map semantics + diff --git a/src/gui/ctrl/bus-term.hpp b/src/gui/ctrl/bus-term.hpp index f3e729ac3..c7be67881 100644 --- a/src/gui/ctrl/bus-term.hpp +++ b/src/gui/ctrl/bus-term.hpp @@ -99,13 +99,14 @@ namespace ctrl{ { protected: using EntryID = lib::idi::BareEntryID; - using ID = EntryID const&; using Tangible = gui::model::Tangible; EntryID endpointID_; BusTerm& theBus_; public: + using ID = EntryID const&; + virtual ~BusTerm(); ///< this is an interface virtual void act (GenNode const& command); diff --git a/src/gui/model/tangible.hpp b/src/gui/model/tangible.hpp index 1f9a6a4c8..e4a358029 100644 --- a/src/gui/model/tangible.hpp +++ b/src/gui/model/tangible.hpp @@ -162,11 +162,12 @@ namespace model { , public lib::diff::DiffMutable , boost::noncopyable { + public: + using ID = ctrl::BusTerm::ID; protected: using GenNode = lib::diff::GenNode; using Cmd = interact::InvocationTrail; using Rec = lib::diff::Rec; - using ID = lib::idi::BareEntryID const&; ctrl::BusTerm uiBus_; diff --git a/src/gui/timeline/timeline-controller.cpp b/src/gui/timeline/timeline-controller.cpp index f49f8b574..14343a898 100644 --- a/src/gui/timeline/timeline-controller.cpp +++ b/src/gui/timeline/timeline-controller.cpp @@ -75,9 +75,9 @@ namespace timeline { - TimelineController::TimelineController (ID identity, ctrl::BusTerm& nexus) + TimelineController::TimelineController (ID identity, ID trackID, ctrl::BusTerm& nexus) : Controller{identity, nexus} - , fork_{} /////////////////////////////////////////////////////////////////////////////////////TODO note that the TrackPresenter will be built later, when the diff assigns the property!!! + , fork_{new TrackPresenter{trackID, nexus}} { UNIMPLEMENTED ("how to make the controller operative..."); } diff --git a/src/gui/timeline/timeline-controller.hpp b/src/gui/timeline/timeline-controller.hpp index 46967f28f..1c7fce4be 100644 --- a/src/gui/timeline/timeline-controller.hpp +++ b/src/gui/timeline/timeline-controller.hpp @@ -87,7 +87,7 @@ namespace timeline { * @param identity used to refer to a corresponding timeline element in the Session * @param nexus some established connection to the UI-Bus, used for registration. */ - TimelineController (ID identity, ctrl::BusTerm& nexus); + TimelineController (ID identity, ID trackID, ctrl::BusTerm& nexus); ~TimelineController(); diff --git a/src/gui/timeline/timeline-widget.cpp b/src/gui/timeline/timeline-widget.cpp index 2b0b3ac3d..ea1486556 100644 --- a/src/gui/timeline/timeline-widget.cpp +++ b/src/gui/timeline/timeline-widget.cpp @@ -65,9 +65,9 @@ namespace timeline { - TimelineWidget::TimelineWidget (TimelineID identity, ctrl::BusTerm& nexus) + TimelineWidget::TimelineWidget (BusTerm::ID identity, BusTerm::ID trackID, BusTerm& nexus) : Gtk::Paned{Gtk::ORIENTATION_VERTICAL} - , control_{new TimelineController{identity, nexus}} + , control_{new TimelineController{identity, trackID, nexus}} , layout_{new LayoutManager} { UNIMPLEMENTED ("build the timeline UI"); diff --git a/src/gui/timeline/timeline-widget.hpp b/src/gui/timeline/timeline-widget.hpp index 54811b3f0..a006c40e5 100644 --- a/src/gui/timeline/timeline-widget.hpp +++ b/src/gui/timeline/timeline-widget.hpp @@ -62,7 +62,6 @@ #include "lib/time/timevalue.hpp" #include "lib/diff/diff-mutable.hpp" -#include "lib/idi/entry-id.hpp" //#include //#include @@ -77,7 +76,7 @@ namespace asset{ namespace gui { namespace timeline { - using TimelineID = lib::idi::EntryID; + using ctrl::BusTerm; /** * Core timeline display (custom widget). @@ -95,6 +94,7 @@ namespace timeline { public: /** build a new timeline display and attach it to the UI-Bus. * @param identity used to refer to a corresponding element in the Session + * @param trackID the mandatory root track used in the associated Sequence * @param nexus some established connection to the UI-Bus, will be used * to register the embedded TimelineController as communication * partner to respond under the given ID. @@ -111,7 +111,7 @@ namespace timeline { * automatically from the UI-Bus. After that, any further messages * towards this element will be dropped silently. */ - TimelineWidget (TimelineID identity, ctrl::BusTerm& nexus); + TimelineWidget (BusTerm::ID identity, BusTerm::ID trackID, BusTerm& nexus); ~TimelineWidget(); diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 1a9c099c2..ac2dc73f3 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -1992,7 +1992,7 @@ It would thus be desirable to have a fixed-sized allocation, able to hold the pl !!!Storage Explicit placements are value objects and stored at the respective usage site, most notably the [[Segmentation]]. They are //not// attached to the placement index in the session, nor do they bear any referential or indexing semantics. The only dynamic side effect of an explicit placement is to keep the reference count of the corresponding MObject up and thus keep it alive and accessible. -
+
//to symbolically represent hierarchically structured elements, without actually implementing them.//
 The purpose of this »external« description is to remove the need of a central data model to work against. We consider such a foundation data model as a good starting point, yet harmful for the evolution of any larger structure to be built. According to the subsidiarity principle, we prefer to turn the working data representation into a local concern. Which leaves us with the issue of collaboration. Any collaboration requires, as an underlying, some kind of common understanding. Yet any formalised, mechanical collaboration requires to represent that common point of attachment -- at least as a symbolic representation. The ExternalTreeDescription is shaped to fulfil this need: //in theory,// the whole field could be represented, symbolically, as a network of hierarchically structured elements. Yet, //in practice,// all we need is to conceive the presence of such a representation, as a backdrop to work against. And we do so -- we work against that symbolic representation, by describing ''changes'' made to the structure and its elements. Thus, the description of changes, the ''diff language'', refers to and partially embodies such symbolically represented elements and relations.
 &rarr; TreeDiffFundamentals
@@ -2028,7 +2028,7 @@ With the exception of the record, which, like any {{{std::vector}}} implicitly u
 A //monad// is an entity which supports the following operations
 *construction:{{{a:A -> M<A>(a)}}}
 *flatMap:{{{(M<A>, f:A->M<B>) -> M<B>}}}
-Operationally, a modad can be constructed to wrap-up and embody a given element. And to flat-map a monad generating function means to apply it to all elements within the given source monad, and then to //join// the produced monads "flat" into a new, uniform monad of the new type.
+Operationally, a modad can be constructed to wrap-up and embody a given element. And to flat-map a monad generating function means to apply it to all "content elements" within the given source monad, and then to //join// the produced monads "flat" into a new, uniform monad of the new type.
 Now, the interesting question is: //what does "join" mean?// --
 *will it drill down?
 *will it lift the contents of generated monads into the parent level, or attach them as new subtrees?
@@ -3688,9 +3688,9 @@ As an immediate consequence of not being able to reduce processing to elementary
 * the PlayProcess serves to join both views, providing a single PlayController front-end, while [[dispatching|FrameDispatcher]] to single channel processing.
 
-
+
//message on the UI-Bus to cause changes on the targeted UI-Element.//
-The UI-Bus offers a dedicated API to direct ~MutationMessages towards {{{Tangible}}} elements, as designated by the given ID. Actually, such messages serve as //capsule to transport a [[diff-sequence|TreeDiffModel]]// -- since a diff sequence as such is always concrete and tied to a specific context, we can not represent it directly as an abstract type on interface level. The receiver of a diff sequence must offer the ability to be reshaped through diff messages, which is expressed through the interface {{{DiffMutable}}}. In our case here, {{{Tangible}}} offers this interface and thus the ability to construct a concrete TreeMutator, which in turn is bound to the internals of the actual UI-Element in question. Together this allows for a generic implementation of MutationMessage handling, where the designated UI-Element is reshaped by applying an embedded concrete diff message with the help of a {{{DiffApplicator<DiffMutable>}}}, based on the TreeMutator exposed.
+The UI-Bus offers a dedicated API to direct ~MutationMessages towards {{{Tangible}}} elements, as designated by the given ID. Actually, such messages serve as //capsule to transport a [[diff-sequence|TreeDiffModel]]// -- since a diff sequence as such is always concrete and tied to a specific context, we can not represent it directly as an abstract type at interface level. The receiver of a diff sequence must offer the ability to be reshaped through diff messages, which is expressed through the interface {{{DiffMutable}}}. In our case here, {{{Tangible}}} offers this interface and thus the ability to construct a concrete TreeMutator, which in turn is bound to the internals of the actual UI-Element in question. Together this allows for a generic implementation of MutationMessage handling, where the designated UI-Element is reshaped by applying an embedded concrete diff message with the help of a {{{DiffApplicator<DiffMutable>}}}, based on the TreeMutator exposed.
Various aspects of the individual [[render node|ProcNode]] are subject to configuration and may influence the output quality or the behaviour of the render process.
@@ -8435,7 +8435,7 @@ As said, this turns out to be a tricky challenge: implementing the application o
 ** how to open a nested scope for recursive mutation
  
-
+
for the purpose of handling updates in the GUI timeline display efficiently, we need to determine and represent //structural differences//
 This leads to what could be considered the very opposite of data-centric programming. Instead of embody »the truth« into a central data model with predefined layout, we base our achitecture on a set of actors and their collaboration. In the mentioned example this would be the high-level view in the Session, the Builder, the UI-Bus and the presentation elements within the timeline view. Underlying to each such collaboration is a shared conception of data. There is no need to //actually represent that data// -- it can be conceived to exist in a more descriptive, declarative [[external tree description (ETD)|ExternalTreeDescription]]. In fact, what we //do represent// is a ''diff'' against such an external rendering.
 
@@ -8482,14 +8482,14 @@ Thus, for our specific usage scenario, the foremost relevant question is //how t
 __Implementation note__:The representation chosen here uses terms of constant size for the individual diff steps; in most cases, the argument is redundant and can be used for verification when applying the diff -- with the exception of the {{{ins}}} term, where it actually encodes additional information. Especially the {{{find}}}-representation is a compromise, since we encode as "search for the term a~~5~~ and insert it at curent position". The more obvious rendering -- "push term a~~4~~ back by +1 steps" -- requires an additional integer argument not neccesary for any of the other diff verbs, defeating a fixed size value implementation.
 
 !!!extension to tree changes
-Diff description and diff handling can be applied to tree-like data structures as well. Some usages of textual comparison (e.g. diffing of programming language texts) are effectively working on tree structures -- yet they do not build on the structure of the diffed data explicitly. But if we represent the data structures symbolically, the change form text diffing to data structure diffing is marginal. The only relevant change is to handle embedded recursive diff descriptions of the child nodes. As it stands, each node or "object" can be represented as a list of properties plus the attachment of child nodes. This list can be treated with the methods developed for a stream of text tokes.
+Diff description and diff handling can be applied to tree-like data structures as well. Some usages of textual comparison (e.g. diffing of programming language texts) are effectively working on tree structures -- yet they do not build on the structure of the diffed data explicitly. But if we represent the data structures symbolically, the change form text diffing to data structure diffing is marginal. The only relevant change is to handle embedded recursive diff descriptions of the child nodes. As it stands, each node or "object" can be represented as a list of properties plus the attachment of child nodes. This list can be treated with the methods developed for a stream of text tokens.
 
 Basically the transition from text diffing to changes on data structures is achieved by exchanging the //type of the tokens.// Instead of words, or lines of text, we now use //data elements.// To do so, we introduce a symbolic ExternalTreeDescription of tree-like core data structures. The elementary token element used in this tree diff, the GenNode, embodies either simple plain data elements (numbers, strings, booleans, id-hashes, time values) -- or it describes a //recursive data element,// given as {{{Record<GenNode>}}}. Such a recursive data element describes object-like entities as a sequence of metadata, named attributes and ordered child-nodes -- it is handled in two phases: the first step is to treat the presence and ordering of child data elements, insertions and deletes. The second phase opens for each structurally changed child data element a recursive bracketing construct, as indicated  by explicit (and slightly redundant) //bracketing tokens://
 *{{{mut}}}(node-ID)  : recurse into the designated node, which must be present already as result of the preceding changes. The following diff tokens describe //mutations// of the child
 *{{{emu}}}(node-ID)  : close the current node context and return one step up; the node-ID is given for verification, but can be used to restore the working position at parent level
 *{{{set}}}(node)  : shortcut notation for simple value elements; assign the new payload value to the designated element, retaining identity
 In addition, in a future extension, we might consider to introduce up/down folding primitives
-*{{{fold}}}(node-ID) : pick the following elements and fold them down into a new child with given node-ID. The downfolding continues until the next {{{emu}}} token
+*{{{fold}}}(node-ID) : pick the following elements and fold them down into a new child with given node-ID. The down folding continues until the next {{{emu}}} token
 *{{{lift}}}(node-ID) : remove the next child node, which must be node-ID, and insert its children at current position
 
 Since the bracketing construct for mutation of child structures bears the ID of the parent, a certain degree of leeway is introduced. In theory, we could always open such a bracketing construct right after the {{{pick}}} token accepting the parent -- yet, while minimal, such a strictly depth-first representation would be hard to read -- so we allow to group the recursive treatement of children //post-fix,// after the messages for the current node. In a similar vein, we introduce another token to describe a //short-cut://
@@ -8498,14 +8498,28 @@ To complement this language construct, we define some special, magical (meta) el
 *{{{_CHILD_}}} : marks an //unnamed// ID. The implementation exploits this specific marker to distinguish between nodes which are (named) attributes of an object, and real children.
 *{{{_ATTRIBS_}}} : can be used to jump {{{after(_ATTRIBS_)}}} when mutating the contents of an object. So the following diff verbs will immediately start working on the children
 *{{{_END_}}} : likewise can be used to jump {{{after(_END_)}}} to start appending new elements without caring for the existing current content.
-All these additional language constructs aren't strictly necessary, but widen the usability of the langauge, also to cover the description of incomplete or fuzzy diffs.
+All these additional language constructs aren't strictly necessary, but widen the usability of the language, also to cover the description of incomplete or fuzzy diffs.
+
+!!!representation of objects
+While we are talking about //structured data,// in fact what are about to handle are objects, understood in the standard flavour of object orientation, where an object is the instance of a type and offers a contract. Incidentally, this is not the original, "pure" meaning of object orientation, but the one that became prolific in brining our daily practice closer to the inherent structuring of modern human organisation. And in dealing with this kind of object, we sometimes get into conflict with the essentially open and permissive nature of structured data. So we need to establish a mapping rule, which translates into additional conventions about how to spell out matters in the diff language.
+
+We choose to leave this largely on the level of stylistic rules, thus stressing the language nature of the diff. Even when this bears the danger to produce an exception very late, when it comes to applying the diff to a target data structure. The intention behind this whole diff approach is to transform tight coupling with strict rules into a loose collaboration based on a common understanding. So generally we'll assume the diff is just right, and if not, we'll get what we deserve.
+
+The ''protocol to describe an object'' is as follows
+* the ID is the objects identity and is once given, never changed
+* we spell out any metadata (esp. a type information) first, followed by all attributes, and then followed by contents of the object's scope (children)
+* attributes are to be given in a way not in contradiction to the more stringent semantics of an object field or property
+** never attempt to re-order or delete such attributes, since their presence is fixed in the class definition
+** when a field is mandatory //by its nature,// it shall be required in construction, and the corresponding data is to be given with the {{{ins}}} verb causing the constructor call
+** on the other hand, the data for an optional field, when present, shall be spelled out by {{{ins}}} verb after construction, with the first //population diff.//
+** we do not support attribute map semantics (or extended "object properties" of any kind). If necessary, treat them as nested entity with map semantics
 
 !!!deriving conventional representations
 On receiving a stream of tokens of this "diff language", it is possible to generate the well known and more conventional diff representations,
 i.e. a ''unified diff'' or the ''predicate notation'' used above to describe the list diffing algorithm, just by accumulating changes.
 
-
+
The TreeMutator is an intermediary to translate a generic structure pattern into heterogeneous local invocation sequences.
 within the [[diff framework|TreeDiffModel]], this is a crucial joint, since here the abstract, generic, ~DOM-like ExternalTreeDescription meeds opaque, local and undisclosed data structures.
 
@@ -8513,7 +8527,7 @@ within the [[diff framework|TreeDiffModel]], this is a crucial joint, since here
 
 !Motivation
 on a very large scale within the Lumiera application, disjoint subsystems are collaborating based on the notion of a //shared conceptual structure.//
-This means, we do not share a data model -- rather we exchange ''diff messages'' with respect to this assumed, common, conceptual structure. In practice, this kind of very loose coupling is realised with the help of a ~DOM-like notation based on a small selection of primitive base types, plus an ~object-like //record// made from such base elements. Based on these elements represented as [[generic nodes|GenNode]], we can build up a symbolic representation of shared structures, which we term the ExternalTreeDescription. In fact, this is not mean and not used as actual implementation data structure -- rather it is used to derive and validate the diff messages handled within our [[diff framework|TreeDiffModel]].
+This means, we do not share a data model -- rather we exchange ''diff messages'' with respect to this assumed, common, conceptual structure. In practice, this kind of very loose coupling is realised with the help of a ~DOM-like notation based on a small selection of primitive base types, plus an object-like //record// made from such base elements. Based on these elements represented as [[generic nodes|GenNode]], we can build up a symbolic representation of shared structures, which we term the ExternalTreeDescription. In fact, this is not meant and not used as actual implementation data structure -- rather it is used to derive and validate the diff messages handled within our [[diff framework|TreeDiffModel]].
 
 //But --// if this symbolic representation is not meant for implementation -- how are we then able to relate it in any useful way to actual implementation data structures? The answer is two fold. For one, and most importantly, we do not collaborate on a shared data model, which means that the implementation data structures are always an implementation detail confined within some subsystem or even part of an subsystem. And this implementation layer can then -- secondly -- expose an adapter or intermediary, which offers a "generic side" for the diff framework to attach to. This adapter is the TreeMutator.
 
@@ -8649,13 +8663,13 @@ attached to a clip, or the mixture of clips, effects and labels found within a [
 ;GenNode binding
 :in the end, it turnes out that the //implementation// underlying our ExternalTreeDescription itself fits nicely into the above mentioned standard bindings --
 :all we have to do is to layer two collection bindings on top of each other, with a suitable //selector// to separate //attributes// from //children.//
-:obviously, this unified implementation comes at the price of one additional indirection (namely through the ~TreeMutator VTable), while the requirements on temporary storage size are almost identical (two iterators and two back references instead of one). Moreover, all the explicitly coded complexities regarding the attribute / children distinction is gone, relying on the logic of layered decorators solely. So the effort to shape the TreeMutator API payed off in the end, to improve and rectify the whole design...
+:obviously, this unified implementation comes at the price of one additional indirection (namely through the ~TreeMutator ~VTable), while the requirements on temporary storage size are almost identical (two iterators and two back references instead of one). Moreover, all the explicitly coded complexities regarding the attribute / children distinction is gone, relying on the logic of layered decorators solely. So the effort to shape the TreeMutator API payed off in the end, to improve and rectify the whole design...
 
 
 You should note that this entire design is recursive: only after understanding the part, where, for handling a sub-structure, a nested mutator is fabricated and placed into a given buffer, it becomes clear to what effect we're creating a customised mutator: we always need some (relative) parent scope, which happens to know more about the actual data to be treated with a TreeMutator. This scope assists with creating a suitable binding. Obviously, from within that binding, it is known what the sub-structures and children of that local data are all about and what semantics to give to the fundamental operations.
 
-
+
The TreeMutator is an intermediary to translate a generic structure pattern into heterogeneous local invocation sequences.
 
 !Motivation
@@ -8708,7 +8722,7 @@ This construction pattern can be extended to offer several optional extension ho
 * how to deal with collections of children
 * how to integrate typed children
 
-&rarr; largely, these problems are settled {{red{as of 3/2013}}}
+&rarr; largely, these problems are settled {{red{as of 3/2016}}}
 ;objects
 :...are represented within the fixed structures of the [[ETD|ExternalTreeDescription]], that is as combination of [[generic node elements|GenNode]]
 ;binding
@@ -8798,6 +8812,11 @@ To create a ''binding'' for any object field, we need
 * either a ''setter'' (lambda) or a ''mutator builder'' (lambda)
 We have a distinct typing for each individual attribute, but this typing remains implicit: the lambda has to know what value to extract from the GenNode payload within the accepted diff message and how to apply this value. Especially for ''time entities'', which are modelled as immutable values, the lambda might want to build a [[time mutator|TimeMutation]]. And especially in the UI, timing specifications are expected to be translated into a //presentation grid.//
 
+!!!policy to deal with non optional object fields
+It turns out we're frequently forced to make a problematic decision here: in practice we often have the choice to treat a field as optional or mandatory. The diff protocol demands to send all mandatory fields immediately, with the {{{INS}}}  verb causing object creation, but, generally speaking, both cases can be supported. Now, what makes this decision tough is the fact it seems way more cheap to cheat our way around this decision: we may implement the fields as being optional, but actually treat them as being mandatory. And we just hope the diff will always provide the necessary values with further {{{INS}}} verbs right within the first population diff. Judging by widely accepted principles of pragmatism, this way to deal with the problem is even the most sensible way. Incidentally, this also relates to the pervasive use of property setters and getters in typical object based programming.
+Unfortunately, there is a price to pay on the long run. This fudge tends to spread in neighbouring code, and, over time, what is //practically irrelevant// tends to happen non the less, causing fixes and complexities to creep into the code. A good guideline thus is not to base this decision on practicality, but to base it on the nature of those matters to be represented in objects: is something //by its own nature is mandatory,// then represent it as mandatory. If something is optional, maybe try to decompose to get rid of it altogether.
+
+
 !!!types, attributes and layering
 During the analysis it turned out that support for a mixed set of //typed child elements// is an important goal. However, we may impose the restriction that these typed sub collections will be kept segregated and not be mixed up within the child scope. Effectively, this was already the fundamental trait for the //symbolic object representation// chosen here. Thus, "attributes" become just one further kind of typed children; even "metadata" might be treated along these lines in future (currently as of 2016 we have only a type field in {{{diff::Record}}}, which is treated explicitly).
 This observation leads directly to an implementation based on layered decorators. Each kind of target elements will be treated by another decorator exclusively, and control is passed through a chain of such decorators. This means, each decorator (or "onion-layer") gets into charge based on a //selector predicate,// which works on the given diff verb solely (no introspection and no "peeking" into the implementation data). We should note though, that this implies some fine points of the diff language semantics are subject to this architectural decision -- especially the precise behaviour of the {{{AFTER}}}-verb depends on the //concrete layer structure// used at the target of the diff. Yet this seems acceptable, since it is the very nature of diff application to be dependent on internals of the target location -- just by definition we assume this inner structure of the target to be semantically congruent with the diff's source structure.
@@ -8818,7 +8837,7 @@ To receive and apply a diff, client code has to build a {{{DiffApplicator<Tre
 
 The {{{DiffApplicator}}} itself can be made non-copyable; preferably it should be small and cheap to construct. At least we should strive at keeping the number of indirections and heap allocations low. Together with the requirement to separate from the actual TreeMutator implementation, which is built late, just before invocation, we arrive at a ~PImpl structure, with the TreeMutator as ~PImpl and a scope manager hidden within the implementation part; the latter will be responsible for creating a suitable stack, and to use the //mutator building closure// in order to incorporate the concrete TreeMutator into the stack frames.
 
-Pulling all those building blocks together, this architecture finally allows us to offer a (tree) diff-applicator for //»basically anything«:// The ctor respective the init method of {{{DiffAplicator<Something>}}} relies on the metaprogramming or ADL technique embedded within the {{{TreeDiffTraits<Something>}}} to //somehow// get at a {{{DiffMutable&}}} -- the latter offering the crucial method to build a TreeMutator implementation internally wired in a proper way to {{{Something}}}'s internals. This in turn enables us to build a suitalbe {{{ScopeManager}}} implementation with a stack size sufficient to hold this TreeMutator implementation. After this type specific setup, the rest of the diff application works entirely generic and can thus be delegated to the non-templated baseclass TreeDiffMutatorBinding...
+Pulling all those building blocks together, this architecture finally allows us to offer a (tree) diff-applicator for //»basically anything«:// The ctor respective the init method of {{{DiffAplicator<Something>}}} relies on the metaprogramming or ADL technique embedded within the {{{TreeDiffTraits<Something>}}} to //somehow// get at a {{{DiffMutable&}}} -- the latter offering the crucial method to build a TreeMutator implementation internally wired in a proper way to {{{Something}}}'s internals. This in turn enables us to build a suitalbe {{{ScopeManager}}} implementation with a stack size sufficient to hold this TreeMutator implementation. After this type specific setup, the rest of the diff application works entirely generic and can thus be delegated to the non-templated baseclass {{{TreeDiffMutatorBinding}}}...
 
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 9bb0c94dd..c3368e275 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -655,11 +655,191 @@ + + + + + + + + + +

+ Thema "Darstellung von Objekt-Feldern im Diff" +

+

+ da hab ich mir ausgiebig Gedanken darüber gemacht (in dieser Mindmap) +

+
    +
  • + entweder ein Feld ist wirklich optional belegbar, dann kann es mit dem Diff kommen +
  • +
  • + wenn dagegen ein Feld zwingend befüllt sein soll, muß man das über den Konstruktor erzwingen
    in diesem Fall müssen alle Daten bereits mit dem vorangehenden INS kommen,
    welches den Konstruktor-Aufruf auslöst

    +
  • +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +

+ die betreffenden Felder sind echt optional. +

+

+ Der Ctor belegt sie mit einem sinnvollen Leerwert +

+

+ Das Objekt muß so geschrieben werden, daß es mit den Leerwerten umgehen kann, +

+

+ was typischerweise heitß, daß es verschiedene Betriebsmodi bekommt. +

+

+ +

+

+ Das Diff kann dann später die konkreten Werte für die Attribute nachliefern; +

+

+ typischerweise wird es das in einem Populationsdiff sofort als Nächstes machen. +

+ + +
+ +
+ + + + + + + +

+ zwei mögliche +

+

+ Konsequenzen +

+ + +
+ + + + + + + + + + +

+ funktioniert fast immer +

+ + +
+ + + + + +

+ "was kann denn schon passieren??" +

+ + +
+ +
+
+ + + + + + + +

+ Betriebsart "partiell initialisiert" +

+ + +
+
+ + + + + + + +

+ ..hier das Widget, das ebenfalls +

+
    +
  • + nur partiell aufgebaut existieren können muß +
  • +
  • + später sich dynamisch erweitern können muß +
  • +
  • + in der Behandlung der UI-Signale ebenfalls checks einbauen muß +
  • +
+ + +
+
+ + + + + + +

+ einen Fall, der praktisch nie auftritt +

+ + +
+ +
+
+
+
+
+