AUA: Henne oder Ei?

denn:

  • Nexus verwendet CoreService als "upstream", um alle sonstigen Nachriten dorthin zuzustellen
  • CoreService hat Nexus als Upstream, um mit dem restlichen System kommunizieren zu können

gemeint ist: im ctor

Es speichert nur die Referenz

Ganz anders Model::Tangible: dieses registriert sich bei der Konstruktion

oder anders herum,

aber so herum macht es mehr Sinn

UI: GuiNotification

...weil es dadurch passieren könnte,

daß die Konstruktion des GuiRunners schon scheitert, bevor der Rumpf des ctors aufgerufen wird.

In einem solchen Fall wird leider auch der Rumpf des dtors nicht aufgerufen, wodurch das

Term-Signal nicht ausgesendet würde.

...weil unser Thread-Framework

tatsächlich erzwingt, daß der neue Thrad zu laufen beginnt, bevor die

startende Funktion zurückkehrt.

Proc: SessionCommand

setzt aktivierten Dispatcher zwingend voraus

es genügt definitiv nicht, nur die Dispatcher-Komponente(Schnittstelle) erreichen zu können.

Jede Operation, die über dieses externe Interface bereitsteht, benötigt zur Implementierung

eine aktiv laufende Dispatcher-Queue.

Daher macht es Sinn, den Interface-Lebenszyklus ganz starr an den Disspatcher zu binden

...und zwar wirklich sehr implizit,

nämlich über die Identität (IDs) der Command-Parameter.

Das heißt, ein eingehendes Command paßt nur zu einer bestimmten Session-Instanz,

was zwar jederzeit (via statisches/internes Session-API) verifizierbar ist, jedoch nicht offensichtlich

das folgt einfach aus den logischen Eigenschaften der beteiligten Komponenten,

welche eben autonom sind.

Das heißt im Klartext, alle Clients müssen darauf vorbereitet sein, daß diese Schnittstelle

jederzeit wegbrechen kann, was dann heißt, daß irgend ein Aufruf eine Exception wirft

wer besitzt die

Implementierung

meint: zwei gekoppelte Statusvariable

muß alle Operationen durchschleifen

oder muß PImpl als Interface exponieren

meint: zwei gekoppelte Statusvariable

Shutdown tricky

das Lock sorgt hier für konsistenten Zustand und Sichtbarkeit (memory barrier)

Lock ist hier das Dispatcher-Lock

...wenn jemand zugreift

grundlegende Design-Enscheidung

  • wir haben Komponenten mit Dependency-Injection
  • da beide Komponenten nur nach ihren eigenen Hinsichten funktionieren,
    wird das System insgesamt einfacher

sets für eine feste session::Timeline

es gibt eine EmptyTimeline

Frage ist, wie viel des Verhaltens programmieren wir selber explizit aus,

und welchen Teil des Verhaltens überlassen wir GTK

Das war zwar schon meine Bauchgefühl,

habe aber sicherheitshalber diese Analyse nochmal gemacht.

Details im  TiddlyWiki....

braucht feste Speicher-Addresse

..d.h. der Controller muß wieder auf das Widget zugreifen

und sei es auch bloß über ein Interface!

aber: Binding im Diff-System durchaus möglich

...denn:

das Diff-System verlangt nicht, daß Kinder in der Collection auch Tangible sind.

Es verlangt nur

  • daß wir wissen, wie wir Kinder machen
  • daß wir für ein gegebenes Kind ein DiffMutable beschaffen können

grundsätzliches

Problem

speziell die Umordnungen ergeben sich

...und der Dekorator würde die beobachteten Operationen

an diese Notifikations-Schnittstelle senden.

Implementiert würde sie vom jeweiligen Widget

korrekt wäre, die Diff-Verben mitzulesen.

Das geht aber nicht, weil wir intern (aktiv) iterieren.

Wollten wir das doch, müßten wir das gesamte Diff-Applikator-Design wegwerfen.

Da aber eigentlich eine 1:1-Zuordnung zwischen Diff-Verben und Operations-Primitiven besteht,

könnte man trotzdem (mit etwas Hängen und Würgen) noch hinkommen.

Der Dekorator würde also auf dem TreeMutator sitzen...

Weil wir die "skip"-Operation für zwei Zwecke verwenden,

und man im Skip nicht weiß, ob man das Element überhaupt noch anfassen darf,

denn es könnte ja auch ein von "find" zurückgelassener Müll sein.

Daher gibt es die matchSrc-Operation. Effektiv wird die aber nur bei einem Delete aufgerufen...

  • man sitzt mit dem Detektor unter dem API
  • dadurch entstehen "ungeschriebene Regeln", wie das API auzurufen ist
  • alternativ könnten wir die Operationen komplett 1:1 definieren, also eine explizite delete-Operation einführen
  • dafür würde dann die matchSrc wegfallen, was praktisch alle sinnvollen Unit-Tests stark beschränkt.

nach der Mutation erfolgt Display-Neubewertung

interagiert mit den Presentern

d.h. eine LUID

wir lassen es offen, welche Art von ID das ist.

Irgend eine BareEntryID genügt

...abstraktes Interface

latürnich

...den muß jeder individuell implementieren,

um die Bindung herzustellen

theoretisch könnte man eine Timeline ohne Sequenz

oder eine Sequenz ohne root-Fork zulassen

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

und zwar interessanterweise über Kreuz gegliedert

  • die Ctor-Lösung (hat aber etwas mehr Umsetzungsaufwand)
  • die "wird schon klappen"-Lösung

wenn alle Objekte wirklich auf partiell initialisierten Zustand vorbereitet sind,

und auch über ihre APIs dem Nutzer diese Unterscheidnung mit aufzwingen

...welche darin besteht,

daß man überall, in der Fläche, sich um Zustandsabhöngigkeit kümmern muß,

und deshalb dazu neigt, das Problem jeweils wegzutricksen.

Es besteht also die große Gefahr, zu "sündigen" und

heimlich in den "wird schon nix passieren" Fall zu geraten.

das heißt, nur diese Lösung gründet in der Natur der behandelten Sachverhalte.

Wenn etwas seinem Wesen nach nicht optional ist, dann wird es auch nicht optional behandelt.

Es ist keine weitere Argumentation notwendig.

...nach allen gängigen Prinzipien der instrumentellen Vernunft.

KISS

YAGNI

"fokussiere Dich"

hier hab ich endlich mal die Gelegenheit, sauber zu arbeiten

hey, es ist mein Leben

...hab ich mich je anders entschieden?

wenn ich mich überhaupt entscheiden konnte...

...nochmal zusammengefaßt

  • immer wenn ein Feld seinem Wesen nach zwingend gesetzt sein muß (und aus keinem anderen Grund)
  • dann wird dies per Konstruktor so erzwungen
  • daher muß dann im Diff bereits im INS-Verb die notwendige Information transportiert werden
  • das heißt, bei der Diff-Erzeugung muß man aufpassen und an dieser Stelle bereits einen Record mit den Daten liefern

wie in Kopf und Rumpf injizieren

...sie verwenden dann ein LabelWidget zur Darstellung

Ein Clip hat verschiedene Erscheinungsformen im UI

Verwende das als Leitgedanke, um das Layout zu entwickeln

UI-Bus gilt nur für globale Belange

es geht nur um Rollen

das lokale Element muß nur als View fungieren

kann sich selbst

transformieren

...nur enabled wenn

mehr als ein top-level Fenster offen

A Gtk::UIManager constructs a user interface (menus and toolbars) from one or more UI definitions,

which reference actions from one or more action groups.

realisiert Vererbung zu fuß

...anstatt eine auf den konkreten Typ getemplatete Subklasse zu verwenden,

wird eine "CreatePanelProc" in einen PanelDescriptor eingewickelt.

Letzten Endes wird dieser dann per Match auf die Typ-ID ausgewählt.

AUA!

wie komme ich da drauf?

Ich wollte untersuchen, ob Gtk::manage( ptr ) korrekt die übergebenen Objekte aufräumt.

Wie sich nun zeigt, passiert das Aufräumen im dtor desjenigen Widget, dem das zu managende Objekt als Kind gegeben wurde.

Im vorliegenden Fall wäre das der dtor des umschließenden ScrolledWindow. Der aber wird offensichtlich nicht aufgerufen,

auch nicht im Application-Shutdown!

....erzeugt wird das hier:

dock_.add_item(timelinePanel->getDockItem(),Gdl::DOCK_BOTTOM);

Helper to build the menu and for registering and handling of user action events

es sieht so aus, als wäre es "das" WorkspaceWindow

aber es kann davon mehrere geben

innere

Struktur

heißt: Element registriert sich am UI-Bus

heißt: Element deregistriert sich am UI-Bus

...ist immer ein tangible

presentation

state

vom tangible initiiert

dafür genügt der normale Reset

mark "clearMsg"

mark "clearErr"

mark "reset"

Nachricht an irgend ein Wurzel-Element

generisch

sinnvoll?

was haben alle UI-Elemente wirklich gemeinsam?

die Frage ist, wie generisch ist eigentlich ein Command-Aufruf selber?

Macht es daher Sinn, ein generisches API allgemein sichtbar zu machen,

oder handelt es sich nur um ein Implementierungsdetail der UI-Bus-Anbindung?

...wird sinnvoll im Rahmen von InteractionControl

ich wollte explizit kein generisch-introspektives UI,

weil das die Tendenz hat, sich zu einem Framework auszuwachsen.

Für die UI-Programmierung muß man Spaghetticode akzeptieren.

gemeint, eine ENUM von verschiedenen Graden der Aufgeklappt-heit

Dann mußte das allerdigns jeweils für alle Elemente sinnvoll sein

und der muß vom konkreten Widget implementiert werden

dann wird eine state mark ausgesendet

need to bubble up

support ist optional

nach Broadcast von "reset"

sollte logischerweise der PresentationStateManager leer sein

ist er aber nicht notwendig,

denn er kann Zustand von nicht mehr existierenden Elementen aufgezeichnet haben.

Nur Elemente, die im Moment angeschlossen sind, bekommen die "reset"-Nachricht mit;

sofern sie tatsächlich abweichenden Zustand haben, sollten sie sich resetten

und eine state mark "reset" zurückschicken...

....so harmlos hat alles angefangen

Denn das heißt, ich muß konkret ausarbeiten,

wie man einen Diff gegen eine opaque Implementierungs-Datenstruktur aufspielt.

Und ich muß das in einem Test zumindest emulieren können!

muß DiffApplicationStrategy

noch einmal implementieren

das mag überraschen --

ist aber im Sinne des Erfinders

  • DiffApplicationStrategy war von Anfang an als technisches Binding konzipiert
  • es ist besser, die gleiche Semantik der Sprache X-mal herunterzucoden
  • cleverer Code-re-Use zahlt sich i.d.R. nicht aus

dies setzt volle Implementierung

des Tree-Mutators voraus

der schwierigste Teil, das Mutieren von Attributen,

ist jedoch schon prototypisch implementiert

Mutator verwendet einen Binder

Diff kennt keine Zuweisung

Nein

aber was dann wenn out-of-order

eindeutig überlegen

  • faktorisiert sauber
  • Zustand delegiert auf die jeweilige Kinder-Sammlung
  • diese wird damit auch zum generischen Element

schlechter....

  • sammelt viel technische Komplexität auf top-level
  • wir müssen eine meta-Repräsentation aufbauen
  • wir müssen Adapter zentral generieren, anstatt uns vom Installieren von Closures treiben zu lassen

Primitive

(impl-ops)

of questionable use

with multiple layers

since skipSrc performs both the `del` and the `skip` verb, it can not perform the match itself...

...because it is also used to discard garbage after a findSrc operation.

Thus we need to avoid touching the actual data in the src sequence, because this might lead to SEGFAULT.

For this reason, the implementation of the `del` verb has to invoke matchSrc explicitly beforehand,

and this is the very reason `matchSrc` exists. Moreover, `matchSrc` must be written such

as to ensure to invoke the Selector before performing a local match. And skipSrc has to

proceed in precisely the same way. Thus, if the selector denies responsibility, we'll delegate

to the next lower layer in both cases, and the result and behaviour depends on this next lower layer solely

then move into target

since, on interface level, we're pretending that this mutator is a single collection like thing,

while in fact the implementation might bind to several opaque target structures.

Thus, internally we'll have a selector to determine which onion layer is responsible for

handling an element as designated by the argument. It is then the responsibility

of this specific onion layer to accept forward until meeting this element.

warning: messed-up state in case of failure

this is (probably) the only operation which entirely messes up the mutator state

when the designated target does not exist. The assumption is that a diff application front-end

will check the bool return value and throw an exception in that case

move into target

throw when

insufficent space

...in Fällen, in denen der konkrete onion-layer

überhaupt nicht im Stande ist, das zu beurteilen.

Wichtigster solcher Fall ist die Bindung auf Objekt-Felder

invoke mutateChild

NOTE: mutator need to be written in such a way

to be just discarded when done with the alterations.

That is, the mutator must not incorporate the target data, rather it is expected

to construct the new target data efficiently in place.

Mutator enthält die Bindung auf die konkreten Daten

stellt sich u.U erst während der Verarbeitung heraus:

bei "offenen Datenstrukturen" entscheided jeder Typ selber,

welchen Mutator er erzeugt

aber: Aufrufprinzip

Verb muß den

Diff bekommen

und delegiert iterativ

an die Verben

...denn in dem Moment, wo wir den top-level TreeMutator erzeugen,

können wir rekursiv abfragen, wie groß alle möglichen Kind-Mutatoren werden können

nur Zuweisung einiger Referenzen

....denn der liegt (mind) einmal vor,

eingebettet in ein Selektor-Prädikat,

welches bestimmt, ob dieses Attribut angesprochen wird

was man konventionellerweise auch macht.

Ich verstehe nun, warum. Es ist der vernünftigste Weg.

Leider scheidet das aber für uns hier genau aus,

denn das gesamte Projekt entstand, aufgrund der inhärenten Limitierungen

der "vernünftigen" (=pragmatischen) Lösung.

dieser Ansatz löst tatsächlich das Problem,

aber zu dem Preis, daß er die Strukturen von innen her zersetzt.

Auf lange Sicht wird das System wuchern wie ein Krebsgeschwühr,

und man kann das nur mit Disziplin eindämmen, was realistisch gesprochen meint,

daß es vergeblich ist. Einen Kampf gegen das Menschliche, Allzumenschliche kann man nicht gewinnen.

das ist die schlankeste Lösung, die ästhetisch befriedigt.

Sie hat aber das Problem, daß dadurch die Kollaboration im Kern ausgelöscht wird.

Wir haben eine Seite, die absolute Macht hat, und einen "Partner", der tatsächlich nur ferngesteuert ist.

Wir müssen dafür auf die Subsidiarität verzichten, und damit auf die Möglichkeit zur Entkoppelung.

Dazu kommt, daß die notwendige Fern-Wirkung stets eine zusätzliche Last bedeutet.

Denn wir müssen auf Umstände und Strukturen einwirken, die von dem Ort, an dem die

Steuerung stattfindet, entfernt ist, entfernt in einen anderen Kontext.

und nur letztere sind tangibel

um den Binde- bzw. Anknüpfungs-Punkt in den real-Daten überhaupt zu finden,

müssen IDs aus dem DOM innerhalb der real-Daten nochmal wiederholt, also redundant vorliegen

damit das DOM ein echtes DOM ist, muß es die relevanten real-Daten duplizieren,

um sie in einem abstrahierten Kontext zugänglich zu machen

noch zusätzlich zur genannten Duplikation muß

die Abblidung der Strukturen aufeinander

an irgend einer Stelle repräsentiert werden.

man kann versuchen, die beiden Elemente der Duplikation aufzulösen.

Allerdings gibt es dafür überhaupt nur zwei mögliche Richtungen.

  • man löst die Parallel-Strukturen auf
  • man ersetzt das DOM durch reine Bindungs-Strukturen

Beide Ansätze laufen aber auf eine der schon genanten, anderen Alternativen hinaus.

Wenn man die Parallel-Strukturen beseitigt, enden wir bei irgend einer Form von Fernsteuerung.

Wenn man die Modell-Natur aus dem DOM entfernt, das heißt, dort nur noch reine
Binde-Strukturen speichert, dann endet man bei einer Form von Introspektion. Entweder,

das Rückgrat und die Navigation verbleibt bei dieser Introspektion; dann haben wir eines

der typischen Objekt-Systeme. Oder die Binde-Daten werden zu einem reinen Anhang

an eine selbständig bestehende Datenstruktur; dann enden wir bei klassischer Introspektion.

reflektiert die Zahl der Struktur-Element

...will sagen:

für die habe ich bereits eine effiziente Implementierung,

die darauf beruht, den Content beiseite zu schieben.

Ich brauche also nur ein Container-Frontend (z.B. einen Vector ohne Inhalt) zusätzlich,

um den verschobenen Inhalt erst mal aufzunehmen.

Also zählen Kinder-Collections nur als ein Strukturelement.

rekursiv,

duch Bindung bestimmt

das ist der wesentliche Kniff,

durch den das Problem mit der "absrakten, opaquen" Position entschärft wird

  • Diff-Anwendung wird massiv und in der Breite stattfinden
  • sie wird als Reaktion auf UI-Events auftreten
  • sie dient dazu, andere UI-Operationen einzusparen
  • also muß speziell das Traversieren bis an den Anwendungsort bedacht werden

...d.h. die bis jetzt geschriebene TreeApplikator-Implementierung

ist erstaunlich leichtgewichtig. Zu den zwei Indirektionien der Sprache

kommt nur entweder ein weiterer aus der GenNode bzw stattedessen ein dynamic cast hinzu.

Alles andere steckt in dem expliziten Mutator-Typ

 -- das gibt einen wichtigen Hinweis --

...da wir eine verb-basierte Sprache implementieren,

also einen double-dispatch haben

weil wir den Anwendungs-Kontext noch überhaupt nicht kennen.

Man könnte also später, wenn das ganze System "steht",

das Diff-System noch einmal reimplementieren, dann mit einem vorgegebenen Diff-Typ

Beschluß: akzeptiert

im Sinn von "polymorpic value" ist das Backend virtuell

....wenngleich auch dieser aus einem Template generiert wird

(will sagen, es ist nicht sofort offensichtlich, daß wir jeweils einen Interpreter generieren)

wir verzichten auf Introspektion der Elemente

denn genau zu diesem Zweck haben wir die "External Tree Description"

...d.h,

kann zusätzlich zu einem anderen Adaptor

in die Mutator-Dekorator-Kette gehängt werden

und protokolliert somit "nebenbei" was an Anforderungen an ihm vorbeigeht

streng genommen ist es nur erlaubt, das ID-Symbol auszuwerten

Visitor bedeutet zwei Indirektionen

...und das ist nicht akzeptabel für ein reines Selektor-Prädikat!

denkbar nur bei Sub-Objekten

gilt für alle praktischen Anwendungen

....auch wenn man zehnmal meinen könnte,

Kinder eines reinen Wert-Typs wären sinnvoll --

sie sind es nicht!

Jede sinnvolle Entität hat mehr als ein Attribut!

denn es macht keinen Sinn, Entitäten und reine Wert-Elemente

auf der gleichen Ebene in der gleichen Sammlung zu mischen.

D.h., entweder man hat ein Objekt, das als Kinder z.B. eine Liste von Strings hat,

oder man hat eine Entität, die z.b. zwei getypte Objekt-Kinder-Sammlungen hat,

wie z.B: eine Spur mit Labels und Clips

"target matches spec"

aber existiert nominell und kontext-abhängig

das sind die konkreten Implementierungen

für spezifische Arten von Bindings

kann niemals geschachtelte sub-Mutatoren modellieren

ja wirklich, das wäre nicht sinnvoll!!!!!

auch wenn man meinen könnte, es geht.

Grund ist nämlich, es kann jeweils nur ein Onion-Layer für ein gegebenes Element "zuständig" sein.

Und aus Gründen der logischen Konsistenz darf dieser Diagnose-Layer niemals für ein Element zuständig sein,

denn sonst würde er es für darunter liegende Layer verschatten.

immer Mitwirkung des Elements

weil beim Assignment die Spec (=GenNode) eben

zwar die ID des Zieles, aber den neu zuzuweisenden Wert enthält.

Also wird sich das Ziel nicht anhand des neuen Wertes finden lassen,

weil es eben grade noch nicht diesen neuen Wert trägt.

generische Repräsentaton ist so gewählt,

daß sich alle relevanten Eigenschaften darstellen lassen

wenn also ein Teil der diff-Funkttionalität nicht verfügbar ist,

dann wird es wohl so sein, daß sie auch nicht gebraucht wird

zwar erscheint es nicht sonderlich sinnvoll,

als target auch eine Menge von primitiven Werten zuzulassen.

Es gibt aber auch keinen wirklichen Grund, dies zu verbieten,

sofern es gelingt, die Funktionalität gutmütig zu degradieren.

...will sagen,

da sind mehrere Layer an praktisch ungebundenem Template-Code dazwischen,

so daß zu befürchten steht, daß ein unpassendes Lambda erst weit entfernt

eine womöglich irreführende Meldung generiert

erfordert wirklich Kooperation

...denn wir verwenden hier als "private" Datenstruktur

eine etwas komische Collection von Strings,

in die wir die String-Repräsentation der Spec-Payload schreiben.

In der Praxis dagegen würde man wirklich einen privaten Datentyp verwenden,

und dann auch voraussetzen, daß man nur Kinder dieses Typs (oder zuweisungskompatibel) bekommt.

Mein Poblem hier ist, daß ich in dieser Demonstrations-Datenstruktur keine nested scopes repräsentieren kann.

Aber hey!, es ist meine private Datenstruktur -- also kann ich einfach eine Map von nested scopes

daneben auf die grüne Wiese stellen. Ist ja nur ein Test :-D

...dankenswerterweise hat der subscript-Operator von std::Map

die nette Eigenschaft, beim ersten Zugriff auf einen neuen Key

dessen payload per default-konstruktor zu erzeugen.

der Builder in der nested DSL generiert einen sonderbar falschen "this"-Typ,

genauer gesagt, eine TYPID die falsch ist.

Und zwar kommt es da zum "Übersprechen" von einem Typ-Parameter in den anderen.

Im Besonderen hab ich beobachtet, daß, wenn man auf den 3.Typparameter ein Lambda gibt,

dann auf dem 4. oder 5. Typparameter der bisherige /alte Typ des 3.Typparameters auftaucht,

u.U auch eingeschachtelt als ein Argument.

Habe mich aber davon überzeugt, daß die eigentlichen Typ-Parameter in Ordnung sind.

Und zwar habe ich das verifiziert

  • durch Ausgeben der Typen im Konstruktor (mithilfe meiner typeStr<TY>()
  • durch Einbauen einer Static-Assertion mit Signatur-Match

gemeint ist:

die native Datenstruktur ist eine Collection von Elementen,

welche ohne Weiteres direkt in eine GenNode gepackt werden könnten. Denn dann läßt

sich eine einfache Default-Implementierung des Matchers angeben

Typisches Beispiel: eine STL-Collection von Strings.

wir integrieren Attribute nicht, weil es so schön symmetrisch ist,

sondern weil sie essentiell zum Wesen von Objekten gehören.

Wenn wir Änderungen an Objekt-Strukturen als Diff erfassen wollen,

dann müssen Attribute irgendwie sinnvoll integriert sein

immer in der Klasse verankert

⟹ es geht eigentlich nur um den Wert des Attributes

manche Felder sind optional

unter der Maßgabe,

wie ETD ein Objekt repäsentiert

"Anwendung" : meint das Anwenden eines Diffs auf ein Ziel-Objekt

"nicht nutzen" : meint ignorieren und verwerfen der Information

meint: ETD -> Objekt und dann später Objekt -> ETD

warum?

Weil sich in der ETD die Reihenfolge ändern kann,

und aber das Aufspielen eines Diffs auf beiden Seiten

zwingend die gleiche Reihenfolge erfordert!

Objekt -> ETD -> Objekt

warum?

weil das Quellobjekt keinen Diff erzeugen wird,

der sich letztlich nicht auf das Zielobjekt aufspielen läßt

abweisen, was das Kriterium sicher verletzt

mandatory : Wert muß per Konstruktor gegeben sein

default : es gibt einen ausgezeichneten Standardwert

das heißt, in dem ins-Verb ist dann ein komplettes Objekt enthalten,

nicht nur eine leere Record-Hülle, die nachfolgend populiert werden kann (aber nicht muß)

Konstruktor befüllt das Feld halt irgendwie.

Ab dem Punkt verhält es sich aber wie ein normales (mandatory) Feld

das Objekt selber kann erkennen, ob das Feld sich im "default-Zustand" befindet

ohne Prüfen ist emptySrc nicht implementierbar

...weil es für emptySrc keine neutrale Antwort gibt.

Denn dieses Prädikat wird von der typischen Implementierung des Diff-Applikators

in beiden Richtungen verwendet, also sowohl Prüfung auf empty ("expect no further elements"),

alsauch der Check, daß überhaupt noch Quellelemente anstehen

d.h., man kann nur global auf Prüfung verzichten 

und da habe ich mich bereits dagegen entschieden

Feld unterstützt default-Wert

Auslegung der

Primitiven

rationale: object fields are hard wired,

thus always available

Einschränkung: accept_until END

...nämlich indem alle Attribute als "berührt" und akzeptiert markiert werden.

Somit könnten sofort Zuweisungen als Nächstes passieren

analog wie assignElm

das heißt, es findet keine Verifikation statt

zu bindende

Operationen

sieht nach Ober-engineering aus,

zumal das erhebliche Statefulness bewirkt

unterstelle Ziel als konstruierbar aus Payload

da effektiv bereits der Setter diese Funktionalität enthalten kann und muß,

denn der Setter nimmt eine GenNode

injectNew tolerieren

....man könnte genausogut auch beim ersten Mal zuweisen

denn die Diff-Anwendung auf GenNode unterstützt Zuweisung

ausschließlich bei schon existierenden Elementen. Demnach muß dort auch jedes Attribut

  • entweder schon mit dem Konstruktor mit gegeben worden sein
  • oder vorher einmal explizit eingefügt

...denn wir vermeiden dadurch Komplexität.

Der gesendete Diff muß einfach passen!

Genau deshalb haben wir auch in GenNode verschiedene Varianten des gleichen Grundtyps,

damit wir nicht in die ganzen Ungewissheiten der widening conversions laufen!

d.h. der Attributwert hat Wertsemantik und wird einfach zugewiesen

...d.h. der Attributwert ist ein Objekt und damit ein nested Scope

Problem: immutable values

das alles passiert dann im Lambda

Dilemma: defaultable fields

....mit der ETD,

bzw der Anwendung des selben Diffs auf eine GenNode-Struktur.

Konsequenz: wenn ein feld defaulted war, und nun explizit gesetzt wird,

muß dies als INS geschehen, denn eine Zuweisung an nicht aufgeführtes Element ist verboten

folglich ein Problem,

zu erkennen, wenn wir fertig sind

....weil das defaultable field noch nicht vom Diff berührt wurde.

Aber es ist kein optional field, d.h. wir haben keine Flag, die es als "defaulted" kennzeichnet

Lösung: alles immer explizit

diese Lösung war zunächst mein Favorit.

Sie erscheint sehr elegant, weil man im TreeMutator überhaupt nichts dafür tun muß.

Und die Zusatz-Forderung, daß dann eben das Diff richtig gesendet werden muß,

erscheint "geschenkt", da wir ohnehin zunächst einmal die Diffs explizit im Code erzeugen.

Aber, nach längerer Überlegung wurde mir der Ansatz mehr und mehr zweifelhaft.

Das ist die Art von Verkoppelungen, hier die implizite Annahme einer bestimmten Implementierung,

die ein System unerklärbar und schwer wartbar machen. Das ist die Art von "Features",

für die man sich nach einiger Zeit entschuldigen muß.

Und noch schlimmer: eigentlich läuft dieser Ansatz darauf hinaus, die Konsistenzprüfung

am Ende zu deaktivieren. Nur wir machen das nicht explizit, sondern durch die Hintertür.

Also dann besser klar und ehrlich!

...denn unter dem Strich würden wir hiermit volle Unterstützung für opitonale Attribute einführen,

also eine Attribut-Semantik auf eine Feld-Semantik draufpflanzen.

Aber in der vorausgegangenen Analyse habe ich mich schon davon überzeugt,

daß wir keine Attribut-Semantik brauchen. Und wenn doch, dann bietet das Diff-System

immer noch die Möglichkeit, die Attribute explizit als Sammlung darzustellen.

auf die empty-Prüfung am Ende verzichten

denn in den meisten, wichtigsten Fällen get es um einen non-empty-check,

bevor ein anderes Verifikations-Prädikat angewendet wird.

jedwede "bessere" Implementierung muß zwingend einen Container verwenden,

der dann die Lambdas für die einzelnen Setter auf den Heap legt.

Das ist hier tatsächlich viel schlechter, als das bischen lineare Suche

....durch meinen allerersten Draft,

für den ich damals gezwungen war, die GenNode zu erfinden :)

gleiches Argument...

...damit unterstellen wir, daß später eine Symbol-Tabelle aufgebaut wird.

Dann kann man sich immer noch überlegen, ob man dann an dieser Stelle bereinigt

in einem Fall kann man sie aus der Closure abgreifen

im anderen Fall muß es doch der Client leisten.

Keine klare Linie

...das heißt, es gibt nur minimale, themantische Überlappung.

Also ist die Verwendung von Vererbung hier sogar die beste Lösung

Geschachtelte Typdefs lassen sich vermeiden:

BareEntryID speichern!

...das heißt, wie rum man es auch auflöst, wird die Lösung auf einer Seite schlechter

  • wenn wir für den Payload-Typ einen Typ-Parameter nehmen, blähen wir den Standard-Fall (Setter) auf
  • andererseits ist es unbstreitbar einfach so, daß für den Mutator-Builder die Typisierung komplett implizit ist, das muß die Closure mit sich selbst ausmachen, einfach indem in der Closure ein geschachtelter TreeMutator konstruiert wird, der eben mit diesem impliziten Kind-Typ umgehen kann.
  • wenn wir stattdessen nur einen Key-String speichern, wird zum Einen die Match-Prüfung aufwendiger (Stringvergleich statt Vergleich von Hashes), und außerdem wird ein Typ-Mismatch nicht mehr auf der Ebene der Verb-Anwendung entdeckt und entsprechend gekennzeichnet, sondern wir hoffen, daß es dann innerhalb der Closure zu einem Fehlzugriff auf die Payload der GenNode kommt. Noch schlimmer im Mutator-Fall, da sind wir dann schon im geschachtelten Scope und hoffen, daß dann der eingeschachtelte Mutator irgendwo auf Widerspruch läuft.

...gedacht für verschiedene UseCases.

  • Fall 1: String-Key und der Typ muß irgendwie implizit/explizit gegeben sein
  • Fall2: GenNodeID

...die offensichtlichsten Dinge übersieht man nur zu leicht!!!!!

Da es ein nested scope ist, ist es immer ein Objekt,

also repräsentiert als Rec<GenNode>

zwei Bindings

zwei Collection-Bindings

...diese Abkürzung ist nur auf den Konstruktur aufgepflanzt,

nicht aber in der eigentlichen Implementierung verankert.

Das wollte ich nicht, weil ich längerfristig doch davon ausgehe,

daß es einfach einen Metadaten-Scope gibt

Die Inkonsequenz nun ist, daß im Rec::Mutator keine Magie dafür vorgesehen ist

...mit den Lambdas kann ich nur die Sicht auf die Werte steuern,

nicht aber das eigentliche Verhalten des Bindings.

Denn die Lambdas haben keinen Zugriff auf die Ziel-Datenstruktur!

...wir wollen mehrfach geschichtete TreeMutator-Subklassen,

aber tatsächlich liefert jeder DSL-Aufruf einen Builder<TreeMutator<...>>.

Die normalen DSL-Aufrufe sind eben genau so gestrickt, daß jeweils der oberste Builder entfernt wird,

ein neuer Layer darübergebaut und das Ganze wieder in einen Builder eingewickelt wird.

Dadurch ist es schwer bis unmöglich (wg. den Lambdas), den resultierenden Typ anzuschreiben.

Daher bin ich zwingend auf Wrapper-Funktionen angewiesen, die diesen resultierenden Typ

vom konkreten Aufruf wieder "abgreifen". Ich kann daher nicht die DSL-Notation verwenden,

um den Dekorator für die Behandlung des Typ-Feldes einzubringen.

Mut -> Rekursion

Problem: partielle Ordnung

...das heißt,

das AFTER-Verb wird übersetzt in ein skip_until,

und das läuft dann entweder in jedem Layer

oder nur in dem Layer, der auf die Spec paßt.

In jedem Fall gerät dadurch die relative Verzahnung der Elemente untereinander aus dem Takt

...das heißt also, es wird stets der zuerst gebundene Layer komplett durchgespult,

gefolgt dann von dem nächsten Layer.

Die Konsequenz ist, daß es keine Mischung der Typen geben kann.

Es müssen immer zwingend alle Elemente eines Typs von einem Layer behandelt werden

und diese Elemente müssen geschlossen hintereinander in der Reihenfolge liegen

auf Basis des neu geschaffenen TreeMutators

....man könnte später geeignete Automatismen schaffen,

die sich diesen TreeMutator beschaffen

  • indem erkannt wird, daß das eigentliche Zielobjekt ein bestimmtes API bietet
  • indem andere relevante Eigenschaften des Zielobjekts erkannt werden

...das so häufig in C++ auftretende Problem:

wie baue und verwalte ich eine konkrete Implementierung,

ohne gleich ein ganzes Management-Framework einführen zu müssen.

Letzten Endes lief  das auch in diesem Fall auf inline-Storage hinaus...

....daß ein unbedarfter client diesen Trick übershieht

und daher den Rückgabewert wegwirft.

Argument: we soweit einsteigt, die Metaprogramming-Lösung zu nutzen,

sollte auch intelligent genug sein, die API-Doc zu lesen.

Standard == Interface DiffMutable implementieren

Client soll direkt mutatorBinding bieten

nicht generisch: mutatorBinding

Lösungsversuch: extern template

...im Klartext: diesen Zugriff von der generischen Implementierung

auf den eingebauten Stack-Mechanismus benötigen wir nur...

  • einmal zu Beginn, bei der Konstruktion
  • wenn wir in einen geschachtelten Scope eintreten
  • wenn wir einen Solchen verlassen

Zwar sind indirekte Calls aufwendiger, aber letzten Endes auch wieder nicht soooo aufwendig,

daß sie uns im gegebenen Kontext umbringen...

intern: eingebaute initDiffApplication()

...wird automatisch vor Konsumieren eines Diff aufgerufen

Widerspruch: TreeMutator ist Wegwerf-Objekt

Lösungsversuch: doppelte Hülle

kann daher TreeMutator konstruieren

...und zwar per mutatorBinding

implementiert somit initDiffApplication()

TODO: Namensgebung

TreeMutator-Binding muß opaque bleiben

Buffer-Größen-Management vorsehen

das heißt

  • ein sinnvoller Startwert wird heuristisch vorgegeben
  • wenn die Allokation scheitert, die Exception fangen und die tatsächlich benötigte Größe merken

...das heißt:

gegeben ein syntaktisch sinnvoller top-level-Aufruf ("wende das Diff an")

-- wie bzw. von wem bekommen wir dann ein Binding, das einen passenden TreeMutator konstruiert?

erscheint mir die am wenigsten überraschende Lösung.

und zwar per handle.get()

erscheint mir fehleranfällig und irreführend für den Nutzer der Schnittstelle.

Denn er muß zwar das Objekt in das Handle platzieren, dann aber auch noch einen Pointer zurückgeben,

der dann auch noch NULL sein kann, zum Signalisieren von Fehlern.

Ich empfinde das als schlechten Stil

naja, das wäre billig, aber auch wieder beliebig.

Es macht keinen Sinn vom API-Design her, sondern man müßte es halt machen,

weil die Implementierung den Zeiger auf den geschachtelen sub-Mutator umsetzen muß.

die Diff-Sprache verlangt,

daß vor dem Öffnen des geschachtelten Scopes

dieser zumindest einmal per ins "angelegt" wurde.

...das ist ein Versuch, den Code für den Leser verständlich zu halten.

Die Idee ist, daß es einen high-level Unit-Test gibt, der die gesamte Diff-Anwendung durchspielt

und dazu passend einen low-level Unit-Test, der analog die gleichen Operationen macht,

allerdings direkt auf dem TreeDiff-Interface durch Aufruf der passenden Primitiv-Operaionen.

Letztere müssen für jede Art von "onion-layer" (konkretes Binding) erneut implementiert

und daher auch jeweils eigens per Unit-Test abgedeckt werden.

das ist hier sinnvoll. Das Binding sollte komplexer sein,

als in der Praxis auftretende Bindings. Warum? Weil letztere immer etwas einseitg sind

und damit Abkürzungen im Code-Pfad ausnützen. Die Gefahr schlummert aber im Zusammenspiel

der konkreten Bindings mit mehreren "onion layers"!

...denn es ist sehr verwirrend, welche Signatur denn nun die Lambdas haben müssen

...denn es kann keinen Default-Matcher geben....

...sonst wird niemand Lambdas bereitstellen können, oder gar Diff-Nachrichten erzeugen.

Das ist nun kein spezielles Problem der gewählten Implementierungs-Technik, sondern rührt daher,

daß der Client hier eigentlich ein Protokoll implementieren muß.

wenn überhaupt, dann im Matcher im Binding-Layer implementieren

...denn wir haben nun mehrere Layer,

und der Selector kann einfach anhand von Ref::THIS keine sinnvolle Entscheidung treffen.

Daher versuchen dann alle Layer dieses Element zu behandeln, oder gar keiner

Und da der Selector nur die Spec anschauen darf, läßt sich das auch nachher nicht mehr korrigieren

Daher habe ich mich entschlossen, dieses Sprachkonstrukt zu entfernen

entfernt, da schlechtes Design

entfernt, da schlechtes Design

anscheinend nicht notwendig

  • diese wird im Nexus behandelt, in dem die Tangible::mark()-Methode aktiviert wird
  • in dieser wiederum steckt eine Default-Handler-Sequenz, plus ein Strategy-Pattern

Marker-Typ MutationMessage

....denn dann müßte der Benutzer die Mechanik sehr genau verstehen, und stets eine auto-Variable definieren.

Sinnvoll wäre dieser Ansatz nur, wenn das UI-Bus-API eine MutationMessage const& nehmen würde,

denn dann könnte man den Builder-Aufruf inline schreiben.

Da wir aber stets den Diff moven und dann iterieren, scheidet const& aus

Und für eine reine Ref erzeugt C++ niemals eine anonyme Instanz!

...und diesen mit VTable bestücken.

Dafür wird die äußere Hülle non-virtual

und kann noncopyable gemacht werden..

Das erlaubt dem Benutzer, einfach zu schreiben

MutationMessage(blaBlubb())

...aus gutem Grund!

Der Nexus speichert nämlich eine direkte Referenz in der Routingtabelle

  • Map hat kein emplace_back
  • Map hat kein back()

Beides ist erst mal sinnvoll. Map hat zwar ein emplace, aber das fügt eben irgendwo ein

Und es gibt nicht sowas wie das "zuletzt behandelte" Element

Reihenfolge

erhalten!

...hat eine "zufällige" Reihenfolge, die von den Hash-Werten der gespeicherten Daten abhängt.

Das bricht mit unserem grundsätzlichen Konzept der kongruenten  Daten-Strukturen

Ein Diff, das von einer ETD gezogen wurde,

läßt sich nicht auf eine Map-Implementierung aufspielen

Entscheidung

...zum Beispiel wie grade hier, beim MockElm

das wird vermutlich niemals wirklich in einem vollen Diff-Zusammenhang gebraucht.

Und dann ist unbestreitbar eine Map eine sehr einfache Implementierung

und auch im Diff-Applikator nicht wirklich schwierig zu unterstützen

Problem: InteractionControl

...was andernfalles komplett vermeidbar wäre,

da im Übrigen das UI-Modell nur mit LUIDs und generischen Namen arbeitet

besser: InvocationTrail

Command und Verhaltensmuster

bleiben zusammen

...was ich einen Monat später schon wieder vergessen hatte...

hier geht es darum, eine Regel zu generieren,

die dann den zugrundeliegenden Command-Prototyp automatisch mit konkreten Aufrufparametern binden kann,

sobald bestimmte Umstände im UI einschlägig werden

Das kann ich für die ersten Tests auslassen, und stattdessen einfach

den InvocationTrail manuell im Testcode binden

die Alternative wäre, den Record mit allen Argumenten in den InvocationTrail zu packen.

Dann würden wir diesen aber weiter versenden, um Aktivierungen zuzustellen.

Das würde bedeuten, die Argumente x-fach zu kopieren (oder mich zu einem ref-counting-Mechanismus zwingen)

Daher ist es besser, einmal, wenn die Argumente bekannt werden, diese zum Prototypen zu schicken

gemeint, das Model-Element (Tangible) sollte einen solchen Overload anbieten,

der unimttelbar Datenwerte nimmt und sie in einen Argument-Record packt

Wichtig (offen): Instanz-Management

Regel: nur was sich parallel entwickeln kann,

muß auch geforkt werden

act, note: Nachricht upstream

mark: Nachricht downstream

Bus-Design is selbstähnlich

Kennzeichen ist die EntryID des zugehörigen Elements

Die Lösung für diese wecheslseitige Abhängigkeit

ist, den Nexus als Member im CoreService zu haben,

weil man dann seine Addresse schon weiß, bevor er erzeugt ist.

Dummerweise rettet mich dieser Trick nicht im Shutdown,

denn hier nun läuft tatsächlicher Code aus dem Destruktor heraus!

bei einem echten Downstream könnte man dafür sorgen,

daß er grundsätzlich vor dem Nexus weggeht. Aber nun kommt, auf dem Umweg

über den Core-Service, der Nexus nach dem Nexus....

ich will nicht damit anfangen, daß man einen Zeiger umsetzen kann....

beendet Deregistrierung,

wenn ein BusTerm sich selbst deregistriert

Mechanismus, der es erlaubt

  • log-Nachrichten aus Mocks zu hinterlassen
  • in der Test-Fixture auf diese zu matchen

konzeptionell: fertig

Implementierung der real-world-Variante fehlt!

Dienste im UI, erreichbar über den Bus.

Sie stellen die Verbindung zu zentralen Belangen her

wie Session- und State-Managment, Commands etc.

Compiler-Bug Gcc-#63723

gelöst in GCC-5 -- backport unwahrscheinlich

eine virtuelle Funktion

pro möglichem Umwandlungs-Pfad

wir verwenden die Basis-VTable

und layern nur die tatsächlich möglichen Umwandlungen drüber

empfängt alle state mark notificatons

nach Perspektive

nach work site

d.h. der usage context entscheidet, ob wir einen Wert,

eine Referenz oder einen konstanten Wert verwenden

Record selber ist immuable

aber hat eine Builder-Mechanik

eigentlich fehlte nur die get()-Operation

erledigt... ähm vertagt

aber nicht wirklich; der workaround könnte schon die Lösung sein #963

ich hatte damals beim Variant und zugehörigen Buffer die Sorge,

daß ich die Implikationen einer generischen Lösung nicht durchdringen kann.

Und ich wollte keine Zeit auf einen exzessiven Unit-Test verwenden

generische Lösung verschoben #963

C++11 erlaubt =default

nicht klar, ob wir das überhaupt brauchen

  • entweder nur die unmittelbaren Kinder -> komplexe Logik fällt auf den Client
  • oder nur die Blätter -> man kann die Baum-Struktur nicht wirklich nutzen

Entscheidung

was wir brauchen

geht nicht:

rekursiver Abstieg in der Mitte eines Iterators

das war die Quintessenz der ganzen Entwicklung zum IterExplorer

Nachdem ich die depth-first / breadth-first -Strategien systematisch aufgebaut hatte,

habe ich das dann reduziert und kompakt nochmal geschrieben.

Sehr schön!

übrigens: genau den verwenden wir auch zur Job-Planung

...denn wir müssen den Weg zurück finden.

Wenn also eine Datenstruktur nur einfach verzeigert ist, oder direkt rekursiv (wie bei uns),

dann ist es absolut unmöglich, eine Traversierung mit konstantem Speicher zu machen.

Das geht nur bei einer Struktur mit Rückreferenzen -- diese enthalten dann nämlich genau den Speicher,

der während dem Einstieg in die einfach verzeigerte Struktur auf dem Stack liegt. Aber letztere

braucht nur eine logarithmische Menge an Speicher, und das auch nur während der Traversierung.

Dies ist die Abwägung, und darunter läßt sich nichts weghandeln.

Der einzige verbleibende Freiheitsgrad ist, bei einer unmittelbaren rekursiven Programmierung

direkt den Prozessor-Stack für die Speicherung des Rückweges mitzuverwenden;

in dem Moment, wo ich mich für einen Iterator entscheide, ist diese Möglichkeit weg.

kann genauso effizient werden

aber nur, wenn man die Initialisierung hinbekommt

oder diese Logik

fest verdrahten

da es sich um einen disjunktiven Typ (entweder-oder-Typ) handelt,

könnte man die Storage mit beiden Bedeutungen überlagern.

Voraussetzung wäre, daß man anhand der konkreten Daten gefahrlos  jeweils herausfinden kann,

welcher Zweig grade gilt. Da wir aber keine Introspektion haben (und auch nicht wollen!),

würde das auf Taschenspielertricks mit der Implementierung hinauslaufen

  • GenNode und Record beginnen beide fraktisch mit einem String. Man müßte diesen interpretieren können
  • oder man nutzt die letzten Bits des Pointers, um sich dort eine Flag zu speichern...

Damit ist schon klar: sowas macht man nicht ohne Grund

Entscheidung: falls eingebetteter Record

Begründung: das Durchlaufen und Rekonstruieren eines Baumes

ist letztlich doch ein sehr spezieller Fall, und rechtfertigt nicht,

den HierarchyOrientationIndicator in jeden Iterator einzubetten.

Zumal -- wenn der level zugänglich ist -- kann man diese Mechanik genauso gut

dort direkt ansiedeln, wo sie gebraucht wird.

also keine Monade

Gleichheit

kombiniert den Wert-Match mit der Iteration

Zweck: kompaktes Anschreiben

von literalen Daten

Object builder

Problem ist, wir definieren den Typ Record generisch,

verwenden dann aber nur die Spezialisierung Record<GenNode>

Und die Builder-Funktionen brauchen eigentlich spezielles Wissen über den zu konstruierenden Zieltyp

Mutator selber is noncopyable

Ergebnis move

pro / contra

Move ist gefährlich

aber auch deutlich effizienter,

denn wir müssen sonst das ganze erzeugte Ergebnis einmal kopieren.

Nicht sicher, ob der Optimiser das hinbekommt

nur auf dem Mutator

dieser ist nicht kopierbar

und muß dediziert erstellt werden

möglicherweise schon gelöst,

denn Record ist insgesamt immutable.

Also können wir einen Find mit einem const_iterator machen

was sinnvoll ist,

hängt vom Payload-Typ ab

bei einer 'key = value' -Syntax mit strings

ist nur ein Value-Rückgabewert sinnvoll

...auch kann man auf diesem Weg die Storage konfigurierbar machten

da wir einen IterAdapter verwenden, können wir nur eine 'pos' (einen Quell-Iterator)

als Zustands-Markierung verwenden; die gleiche 'pos' wird aber auch inkrementiert und dereferenziert.

Daher ist die einzige praktikable Lösung, daß die Typ-ID in einem weiteren Vektor gespeichert wird.

Das könnte dann ein Metadaten-Vektor sein.

Natürlich ist dieser Ansatz nur sinnvoll, wenn wir wirklich Metadaten brauchen.

Denn jeder Record zahlt den Preis für die komplexere (zusätzliche) Datenstruktur!

scheidet aus, wegen Wertsemantik

mit speziellem Ref-Typ

-- im DataCap

heißt: in der Diff-Verarbeitung wird dieser spezielle check verwendet

m.E. die einzig saubere Desgin-Variante!

gemeint ist:

  • man kann alternativ auch eine RecordRef direkt in eine elementare GenNode packen
  • diese verhält sich dann nicht transparent, denn sie hat eine andere Identität als ihr Ziel
  • das kann aber als spezielles Ausdrucksmittel genutzt werden

heißt: wird direkt von standard-equality so behandelt

brauche speziellen Builder,

der das so fabriziert

bekomme einen

"ungenutzten" DataCap

Idee: Ref-GenNode

als Ref erkennbar

(Prädikat)

hash-identische

Ziel-ID ableitbar

Verarbeiten

von Teilbäumen

Interpreter definiert Sprache

ROOT

INIT

leeres

Objekt

pick(Ref::CHILD)

würde sagen: ja, aber auch nur für das after-Verb!

allgemein halte ich einen wrap-around für keine gute Idee,

weil er zu Zweideutigekeigen führt und daher Struktur oder Konsistenzfehler überspielt

läßt sich stets duch eine inverse Folge von find und pick  emulieren

vorerst verworfen, da zusätzlicher Prüf-Aufwand

...Grund: sie werden durch einen jeweils komplett anderen Ansatz implementiert

  • "Liste" beruht auf dem Attribut-Iterator und dem Aufbauen einer neuen Attribut-Sammlung
  • "Map" beruht darauf, alle Operationen an die Storage zu delegieren

das heißt, man kann Attribute in einer "sinnvoll lesbaren" Ordnung anschreiben

und später angefügte Attribute bleiben so erkennbar.

Vorteilhaft für Version-Management

profitiert also von allen Verbesserungen des allgemeinen Algorithmus

"hoch effizient", unter der Annahme, daß fast immer nur konforme Änderungen kommen.

Weil dann nämlich die in unserer Implementierung ggfs. kostspieligen Umordnungen entfallen,

kommen wir auf lineare Komplexität für die Verarbeitung

+ NlogN für den Index zur Diff-Erzeugung

unsere Impl der Diff-Erzeugung (!)

baut einen Index auf (N*logN), um Einfügungen/Entfernungen zu erkennen und Umordnungs-Suche zu unterstützen.

Wenn wir aber von ausschließlich konformen Operationen ausgehen,

wird dieser Index nicht benötigt. Leider können wir das aber nicht garantieren, denn

es könnte ja zwischenzeitlich ein Attribut gelöscht und dann später (am Ende) wieder

angehängt worden sein, was dann eben doch einen Index erfordert, um einen

korrekten Listen-Diff zu erzeugen

d.h. wenn die Storage hoch-optimiert ist,

dann überträgt sich das auf die Diff-Behandlung

da wir Attribute in einer Liste speichern,

müssen wir für jede Einfügung eine vollständige Suche machen

...gemeint ist: extra, anders als die normale Listenverarbeitung.

Auch wenn diese andere Implementierung nur delegiert

danach noch auftretende Attribute

erfordern Sonder-Behandlung,

indem sie an die Attributs-Liste angehängt werden

wegen Entscheidung für das "Listen"-Modell zur Attribut-Handhabung

das heißt:

  • es wird einfach vom zuständigen Layer (der für die Attribute) aufgegriffen
  • es hat keinen Einfluß auf die nach außen sichtbare Reihenfolge
  • diese Reihenfolge bleibt gruppiert nach Attributen / Kindern

...da das Kind in der Liste der Attribute nämlich garnicht gefunden wird

...wenn wir am Ende der Attribut-Zone stehen,

und die nächste Operation ein fetch eines Kindes ist, müssen wir implizit den

Wechsel in den Scope vollziehen und die Operation dort ausführen.

Aber an allen anderen Stellen in der Attribut-Zone ist ein solcher Fetch ein Fehler!

standardmäßig strikt

List-Diff

als Spezialfall

kann auch nicht

wegen dem Interpreter

leicht auf generischen Container

zu verallgemeinern

Erkennung hat die Sprache als Parameter,

und verwendet sie zur Token-Generierung

man kann auch dem List-Detector

eine Tree-Diff-Language geben

Frage: in-Place?

entscheidende Frage: wie addressieren?

und wird durch die Diff-Anwendung konsumiert

Immutablility erzwingt

  • persistente Datenstrukturen
  • garbage-collector

Lösung: wir arbeiten auf einem Mutator

auf dem Umweg über einen ContentMutator

Innereien des alten Record verbrauchen

Problem: Rekursion

wenn ein MUT kommt

erzeugt man lokal einen DiffApplikator für den geschachtelten Kontext

und gibt ihm rekursiv den Diff hinein. Wenn dieser Aufruf zurückkehrt

ist der gesammte Diff für den eingeschachtelten Kontext konsumiert

wenn ein MUT kommt,

pusht der Applikator seinen privaten Zustand

auf einen explizit im Heap verwalteten std::stack

und legt einen neuen Mutator an für den nested scope

Entscheidung:

interner Stack

....begründet duch die generische Architektur.

Die Trennung von Diff-Iteration und dem Interpreter ermöglicht verschiedene Sprach-Ebenen.

Allerdings werde ich für die Anwendung auf konkrete Datenstrukturen,

also den TreeMutator, vermutlich das andere Modell (rekursiv konsumieren) verwenden.

Problem sind mal wieder die automatisch generierten IDs.

Die sind natürlich anders, wenn wir die ganze Testsuite ausführen...

schmerzloses C++ API

Performance: guter Schnitt (etw. besser als boost spirit)

hat ein DOM-API und ein SAX-artiges API

das heißt: nicht einmal abhängig von der STL

wie gson

vjson war Google Code;

nach dem Umzug auf Github heißt es gason

lt. eigenen Benchmakrs deutlich schneller als rapitjson, welches eigentlich immer als der "schnelle" JSON-Parser gilt.

d.h. das Parsen schreibt den Eingabepuffer um, und Strings bleiben einfach liegen

kein Repo auffindbar

ich will nicht noch ein Objekt-System

saugeil

...nicht mehr das klassische gtk::Main

...können vom CSS-Stylesheet aus gesetzt werden.

Siehe Beschreibung im Beispiel/Tutorial

in der Implementierung, mywidget.cc

ist eine komplette Sequenz, wie man einen CSS-StyleProvider setzt

und auch ein Signal für Parse-Fehler anschließt

....how does the event dispatching deal with partially covered widgets

...for embedded widgets

...meaning, "this event is not yet fully processed",

i.e. the enclosing parent widget also gets a chance to redraw itself

Warning: allocation is the visible area

asked on stackoverflow...

...as can be observed

by printing values from the on_draw() callback

...otherwise adjustment values will cummulate,

causing us to adjust too much

...die anderen, die noch in Frage kommen würden,

sind nur für den Fall, daß ein Widget neu instantiiert wird

oder neu in das Window-System gemappt wird.

on_check_resize() wird nicht aufgerufen

...keine Ahnung, was ich beim ersten Mal falsch gemacht habe.

jedenfalls hab ich da sofort beim ersten Aufruf der Closure einen SEGFAULT bekommen.

Auch im zweiten Anlauf habe ich ein Lambda verwendet.

Möglicherweise ist der einzige Unterschied, daß ich es nun aus dem draw-callback

aufrufe, und daß demgegenüber bei der ersten Verwendung die Allocation des jeweiligen

Kind-Widgets noch gar nicht festgelegt war (denn das passiert erst beim draw).

...im Besonderen die guten Diagramme für Pulse, ALSA und Jack

bekannter Bug binutils #16936

Lumiera-Ticket #965

gelöst in 4e8e63ebe

...man "hilft" dem Linker mit

"-Wl,-rpath-link=target/modules"

laufen wieder alle

test.sh Zeile 138

Debian-Bug #724461

nebenbei ohweh:

ulimit -t 1 ist wirkungslos

Christian:  bash -c "ulimit -t 1; while :; do :; done"

und wir verbringen unsere Zeit mit contention

ist klar, hab ich gebrochen

siehe Ticket #587

Kollisionen jetzt bereits nach 4000 lfd. Nummern

Vorher hatte ich erste Kollisionen nach 25000 Nummern

erinnere mich an den

guten alten "Knuth-Trick"

wow: es genügt,

die letzten beiden Zeichen mit der Knuth-Konstante zu spreizen,

und ich komme locker auf 100000 Nummern ohne Kollision

Aug 10 04:51:39 flaucher kernel: gdb[8234]: segfault at 7ffe3fa79f50 ip 0000000000718b95 sp 00007ffe3fa79f40 error 6 in gdb[400000+574000]

Aug 10 04:51:39 flaucher kernel: traps: test-suite[8249] trap int3 ip:7ffff7deb241 sp:7fffffffe5c8 error:0

function gebunden an ein lambda

wobei ein Argument-Typ als vom Template-Argument

der umschließenden Funktion aufgegriffen wird

Bugreport für Debian/Jessie #795445

Git: debBild/Gdb_DEB.git

bison dejagnu flex gobjc libncurses5-dev libreadline-dev liblzma-dev libbabeltrace-dev libbabeltrace-ctf-dev python3-dev

dutzende Tests scheitern

verräterrischer Code im debian/rules

check-stamp:

ifeq ($(run_tests),yes)

        $(MAKE) $(NJOBS) -C $(DEB_BUILDDIR)/gdb check \

          || echo "**Tests failed, of course.**"

endif

        touch $@

au weia LEUTE!

speziell: unused-function bei dem Trick mit dem std::hash macht mir Sorgen.

und tatsächlich: das ist daneben, GCC hat Recht!

aktualisieren und neu bauen

standard hardening-flags setzen #971

wähle Kompatibiltät genau so, daß Ubuntu-Trusty noch unterstützt wird.

...damit man auch im Paketbau-Build-Output wenigstens einmal alle  generischen Platform-Schalter sieht

Ich meine also: zu Beginn vom Build sollte das Buildsystem einmal eine Infozeile ausgeben

...denn die stören jeweils beim erzeugen eines Hotfix/Patch im Paketbau per dpkg --commit

deprecated: auto_ptr

Tests mit TypeIDs scheitern

Doku durchkämmen nach Müll

hier nach offensichtlich obsoleter Info checken

WICHTIG: keine vorgreifende Infor publizieren!!!!!

die explizit angegebenen Paketnamen schon mal vorchecken

die Abschnitte zu den LIbraries prüfen / umschreiben

insgesamt sorgfältig durchlesen

knappe Kennzeichnung des Releases in den Kommentar

hier geht es darum, Konsistenz im Git herzustellen.

Wenn alles korrekt gemacht wurde, dürfte es hier keinen Rückfluß von Änderungen geben.

Bitte auch daran denken, zuerst den DEB-Zweig zu prüfen. Diesen aber nicht zurückmergen,

denn wir wollen keine DEB-Info im Master haben!

einzeilige Kennzeichnung wiederholen

die unmittelbaren Release-Dokumente durchgehen

Merge-commit auf den Release-Zweig.

Sollte konfliktfrei sein

...das heißt bauen und hochladen

Referenz: Debian/Jessie (stable) : i386 and x86_64

Probleme mit der Compile-Reihenfolge  #973

...führt sowohl eine README, alsauch ein Verzeichnis /usr/share/doc/lumiera/html auf, das (noch) nicht existiert

unter Debian/Jessie wird das ignoriert

stelle fest: Fehler auf Trusty,

nur Warnung auf Mint

das heißt, daß ich versuchen kann, das Problem erst mal "unter den Teppich zu kehren"

Die Wahrscheinlichkeit, daß irgend jemand Lumiera unter Ubuntu/Trusty installieren möchte, erscheint mir akademisch

bauen mit gcc-5 scheitert

in lib/hash-standard.hpp

mit gcc-5 gebaute Tests scheitern

bauen mit gcc-4.9 nicht möglich

es gibt Probleme beim Linken mit den Boost-Libraries, die auf Ubuntu/wily mit gcc-5 gebaut sind.

Wichtig: hier nur was wirklich gebaut ist und funktioniert!

eigentlich war die nur notwendig für das Video-Viewer Widget,

was nun leider tot ist. Wir haben noch keinen Ersatz. Deshalb lasse ich die Abhängigkeit

bestehen, aber irgendwann müssen wir das schon glattziehen

hardening-flags! #971

Ticket #722

seit gcc-4.8 ist kein static_assert mehr in der STDlib

Probleme mit der Compile-Reihenfolge  #973