How to configure AMS

This represents some of my ideas about how we make AMS customizable. This includes thoughts about how a patch files should look like, what information should be stored in it, what other information should be made customizable via config files, how those info is bind to ams and its gui classes, and a lot of the usual blablub i am infamous for on the ams lists ;-)
This text is currently labeled as an idea.

Requirements

A key requirement is readability of the patch files. As Matthias pointed out some time ago, there might be users who are blind and can not make much use of a fance GUI. It should therefor be possible to edit the patch file manualy in any text editor, and even create patches from scratch without much hassle. This requires the language we use to have a simple and intuitive syntax, and it also requires the absense of any implicit assumptions imposed by the programm regarding either syntax/gramma or semantics of the vocabulary used. In other words, for everything user does within the config or patch files, it has to be possible for him/her to know which statements are valid in which context and what effect this statements will have on ams.

On the other hand, we want flexibility. It should be possible to add new functionality, e.g. by contributing new modules. It should also be possible to completly change the appearance of the gui or parts of it (skinning). And of course there maybe other things desired by users that we cannot yet imagine.

And, as a third point, it would be very handy to impose default definitions on arbitrary levels. It should be possible to say
"All modules use foo gui except those of type bar, which should use fee. But not the instance fee:foom, since i want my special gui fam for it!"
And anyway, user does not want to specify anything he is not interested in. So for every aspect in ams, there should be a default value/behaviour. Of course it would be easy to hard code those defaults, but that's not the point! After all, user should have access to them, be it out of curiosity, or because he/she wants to redefine them. And i suppose, user does not enjoy browsing sourcecode for that purpose.

Problems

There is one main decision we have to make when we agree on a language. Do we want rich vocabulary, which would allow short statements, and make the patch files easy to read, or do we prefer a sparse vocabulary, which would make the language more generic, propably easier to parse(??) and maybe more flexible. (The latter two points are actualy an illution, as i will try to show.)?

A rich vocabulary:

<vco name="vco1"> <foo>2.0</foo> </vco> <vcf name="vcf1"> <foo> <bar name="lala"/> <bar name="golgol"/> </foo> </vcf>

As shown in the example above, each module or parameter will get its own tag. The advantages are obvisous: Patches are put together very quickly, everything looks pretty self explaining. However we could not use a DTD to validate instances of that language, since the pattern for <foo> would depend on the context it appears in. So we would have to use different names, which is an ugly restriction and is even difficult achieve, since we don't know what modules there will be in future, and what names they use. I first thought, this could be solved by using namespace prefixes for each module class, but it turned out that DTDs are not aware of namespaces (they would treat <vcf:foo> as a single name), so even if we make vco the default namespace of <vco>, the parser would not recognize that <foo> actualy means <vco:foo> in the context of <vco>.

On the other hand we could use a

A sparse vocabulary:

<item id="vco1" type="vco"> <item id="foo">2.0</item> </item> <item id="vcf1" type="vcf"> <item id="foo"> <item name="lala" type="bar"/> <item name="golgol" type="bar"/> </item> </item>

This would be a very generic gramma, for which it would be trivial to write a DTD that any parser could use to validate the syntax of a given instance against. The structure would impose something like an agregation relation between a parent item and its children, and by introducing another item <class>, it would even be possible to express that some element represents an instance of a certain class of items, or one could allow a <class> element to inherit some default behaviour from another <class>. So this would basicaly be a language which could express anything that could be desired within ams.

The problem however would be to communicate to the user which <item>s are allowed, i.e. recognized by ams and which are not. In addition, ams would have to make some assumptions on the structure of the files like which could not be expressed within the DTD without loosing much of the desired flexibility. So we are exactly where we started, only that i lost several nights of sleep to find out :-(

How Schema and friends might help

So obvisously DTDs are not strong enough to define a gramma that fits our needs. On the other hand it is, at least in my eyes, mandatory that we find some way of expressing the syntax of this files in a way that is backed up by some standard. Otherwise, we wouldn't have to think about xml, we could use our own markup, write our own parsers/validators and be fine. Again, the thing that makes me exited about xml in first place, is that can (in theory) express what the information in your xml files actualy means, without writing tons of manuals, etc. Moreover, if the semantic of your language is defined in a standarized, machine readable form, it will be easier to work with it, not only for your own tools, but also for generic third-party applications.

Fortunatly, the problems described above are long known, and there is a cure available. Forget about DTDs, let's use some Schema language.

There seems a vast ammound of different meta-languages available(W3C Schema, RelaxNG (and its anchastors),DCD, SOX, DDML, Schematron, DSD, Hook, DSDL, too name a few), which all claim to be a standard, and which all claim to be particular simple and powerfull. My impression is, that none of them is either. :-)
Anyway, for now, i took a closer look at Relax NG and i will use it in this document as an example. I guess, most of what we want could be represented in another language as well. The one thing they have in common, is, that they are all more powerfull as DTD. Another thing they seem to have in common, is that they are all not as accepted as DTD, and hence not as well supported API vice. If you are not interested in java api's that is... thoses XML geeks seem to prefer java for there reference implementations. Other languages they seem to be fluent in are functional languages like Haskell, which i can understand to some degree, as it is realy a nice language if you are experimenting with formal languages and grammas. (For those interested: On the RelaxNG site, there is a %quot;tutorial%quot; which describes in detail how to implement a validator in Haskell. Was interesting for me, since i have to learn Haskell for upcoming exams.) Unfortunately, they do not seem to care much about c. left alone c++. There is some chance that libxml++ (a wrapper for libxml2) might support RelaxNG and maybe others. At least libxml2 seems to. So for the rest of this text, i will assume, that the actual implementation of a validator/parser is no problem.

Sorry, i'm not ready reading yet. To be continued soon :-)
The rest are just notes, which i will further elaborate, when i find some time. They are in german, but the final text will of course be translated into (bad:-)) english.

Verteilung der Verantworlichkeiten
  • jede klasse (oder andere Entität) die sich in irgend einer Form Konfigurieren läßt, stellt ein Schema zur Verfügung. das die entsprechenden elemente deklariert. Optimal: das Schema kann automatisch erzeugt werden. (Problem: Synopsis vermutlich nicht! s.u.)
  • Dieses Schema sollte minimal sein, i.e. es sollte keine unnötigen Einschränkungen der Sprache vornehmen. Anordnung der Elemente ist z.B. in den allermeisten Fällen irrelevant. Elemente, die default werte haben können, sollten immer optional sein!! Das von einer Klasse definierte Schema sollte sich nicht mit dingen ausseinander setzen, die nicht in ihre Verantwortlichkeit gehören. z.b. module machen keine aussagen über ui spezifische constraints (macht die entsprechende UI Klasse/Schema!). ABER: typischer Grenzfall: Module werden vermutlich ein elm. oder attr. deklarieren, das dem Benutzer erlaubt, anzugeben, mit welcher ui Komponente er ein Modul darstellen will.
  • Anderes Beispiel: UI-Klassen (bzw. deren Schemata) enthalten KEINE Einschränkungen für die von ihnen dargestellten Entitäten. ABER: Andersrum wird ein Schuh draus. Wenn es für eine Bestimmte Entität eine UI entsprechung gibt, so ist genau festgelegt, welche UI Plugins hierfür verwendet werden DÜRFEN. Diese Festlegung ist explizit. (s.u.) Im Schema einer UI-Klasse sind nur Entitäten declariert, die details der Darstellung (View) regeln, nicht aber des repräsentierten Models. (Beispiel Parameter vs ParameterEditor)
  • Defaults gehören NICHT ins Schema! Zum einen kann z.b. RelaxNG dies nicht formulieren, zum anderen soll Benutzer Defaults auf beliebiger Ebene bestimmen können OHNE die Schemata zu ändern. Schemata definieren allerdings die Mechanismen, mit denen Benutzer Defaults angibt.
  • Es gibt leider immer noch einige wenige "meta-meta-infos", die sich nicht durch Schemata ausdrücken läßt! Vielleicht läßt sich der eine oder andere Punkt noch lösen.
Modularität/UI-anbindung
  • Wenn im folgenden von Erweiterung oder Abänderung der Grammatik die Rede ist, meint dies immer eine Erweiterung in dem Sinne, daß neue Plugins für AMS verfügbar werden, die gegebenenfalls konfigurierbare Entitäten besitzen.
  • (Ich muß noch einen Abschnitt über Nomenklatur einfügen, sonst versteht mich keine Sau :-) )
  • Es gibt zu jeder Zeit GENAU EINE Grammatik, die für ALLE Patches bindend ist. Diese ist eine Kombination ALLER durch die jeweiligen Entitäten definierten Schemata. Dieses "Mergen" geschieht implizit durch verwendung von entsprechenden tags (z.b. include in RelaxNG) in den Schemas.
  • Es gibt ein "Root-Schema" das alle zu den Entitäten gehörenden Schemata einbindet. (kein "deep-copy"!") Dieses "Root-Schema" wird wärend der Boot Strapping Phase von ams aktualisiert. (ams durchsucht entsprechende Verzeichnisse nach neuen Schemata)
  • ALLE patterns (außer root!), die von einem Schema deklariert werden, befinden sich in einer define Umgebung. (sind also zunächst abstrakte Syntax Elemente!) Wird in dem Schema ein konkretes Element deklariert, so muß via proccesing instruction darauf hingewiesen werden, um welche art von Element es sich handelt. Ams fügt dann eine Refferenz auf das entsprechende Pattern an der an der richtigen Stelle im Root Schema ein.
  • Das ist ziemlich unschön! (meta-meta-Info!) vielleicht kann man das auch irgendwie durch namespaces ausdrücken.
  • Komplette Redifinition von Patterns ist VERBOTEN! (auch wenn RelaxNG entsprechende Konstruktionen anbietet) Offensichtliche Begründung: ES GIBT NUR EINE GÜLTIGE GRAMMATIK! Das impliziert das jede Mutation dieser Grammatik Instanzen der ursprünglichen Grammatik IMMER AKZEPTIEREN MUSS! (Anderenfalls drohen 30 Jahre schwerster Dunkelhaft mit einem Fasttag täglich! :-) )
  • Es ist allerdings erlaubt (und auch teilweise Notwendig!) Patterns zu erweitern. Das ist hinsichtlich des vorherigen Punktes ungefährlich, so lange es sich tatsächlich um eine "Aufweichung" des entsprechenden Patterns handelt. In RelaxNG heißt das: es ist z.b. ein Kombinieren eines vorhandenen Patterns mit einem neuen via combine="choice" zulässig. Im falle von combine="interleave" gilt: inhalt des neuen Patterns MUSS optional(bzw. zeroOrMore) sein!
  • Wichtiges Beispiel für Erweiterung im obigen Sinne: Definition einer Liste von UI Elementen, die für eine bestimmte Entität erlaubt sind. Dies sollte in jedem Fall explizit innerhalb der Grammatik geschehen. Denkbar: Entität besitzt ein Attribut "ui" für das nur solche Werte erlaubt sind, die von AMS als Namen einer existierenden UI Klasse ausgewertet werden können. Offenbar muß die Liste dieser Werte erweiterbar sein, da nicht bekannt ist, ob zu einem späteren Zeitpunk neue UI Plugins verfügbar sind. Die Entitär würde also hier eine Refferenz auf ein abstraktes Pattern enthalten, das im Schema einer neuen UI Klasse gegebenenfalls erweitert werden könnte. Hier würde es sich z.B. anbieten, ein globales pattern "_att_foo_ui_" zu definieren(für parameter vom typ foo). Würde nun ein neues UI Plugin verfügbar, das mit dem typ foo umgehen kann, so würde in dem entsprechenden Schema ebenfalls ein Pattern "_att_foo_ui_" definiert, das als einzigen erlaubteb Wert, den Namen des Plugins enthielte, (combine="choice"!) Da aber alle Schemata in vom Root Schema included werden, würde das pattern automatisch alle für den Typ foo passenden Ui Plugins enthalten. Schick, oder?
  • (Es gibt evtl noch eine viel nettere (weil einfachere) Lösung für dieses Problem: name classes in RelaxNG. Ich muß noch mehr darüber lesen.)
Defaults
  • Wie bereits erwähnt, lassen sich Defaults nicht in einem RelaxNG Schema formulieren. Wie ebenfalls bereits erklärt ist dies auch gar nicht wünschenswert. :-) Haaach, das leben ist schön.
  • Was wir allerdings gerne möchten, ist ein Syntax für Mechanismen in der Grammatik festlegen, mit dem sich beliebige Defaults auf mehreren Ebenen festlegen und überschreiben lassen. (z.B. pro Modulklasse, oder für alle Parameter eines bestimmten typs innerhalb einer bestimmten Modulinstanz)
  • Ein großer Teil der Semantik die hinter einem solchem System steht, läßt sich leider nicht 100%ig explizit in RelaxNG formulieren. Schade.
  • Ebenfalls schade: Wir haben keine Mechanismen, mit denen sich Polymorphismus z.B. zwischen einer Klasse von Entitäten und deren Instanzen explizit formulieren ließe. Bzw, es ist schwierig auszudrücken, das eine Entität vom Typ myFoo eigentlich nur eine konkrete Instanz des abstrakten Patterns Foo ist, zumindest ohne häßliche Artefakte in unserer bisher noch recht sauberen Sprache zu erhalten. Daher können wir zunächst auch nicht so ohne weiteres sagen ob ein bestimmter Default wert für eine bestimmte Entität zulässig ist, es sei denn er wurde für genau diese Entität definiert.
  • Andererseits können wir ohnehin nicht einwandfrei garantieren, das

My Conclusion

Resources