cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Marc Portier <...@outerthought.org>
Subject Re: [cforms] Forwarding: Explanation of "dynamic stuff in form model"
Date Mon, 05 Jan 2004 23:34:31 GMT
Tim,

your postings on the list urged me to get some deeper into this

specially on the 'cyclic' stress on the building process brought in by 
the class/new stuff
and specially how that clashes with the 'private final' mantra I've been 
chanting :-)


obvious observation is that the cyclic stuff will prevent us from doing 
any 'final' declaration on the pointer from 'new' to it's 'class'...

still thinking out loud here... but this is somewhat the fixed 
building-pattern I see to support the cyclic stuff:

(I'm using Node for both explaining the works in WidgetDefinition and 
Binding Realms)
(and still using the 'class' naming while mixing that with the proposed 
change for 'new' --to--> 'use' since it more naturally explains the 
ideqas of this pattern.
By the way: yet another alternative for renaming class: 'prototype', hm, 
that sounds familiar, maybe someone else had already suggested this?)



The Assistant (see the current Binding-build process for this, AFAIK the 
widgetDefinitionBuilding does not have a similar thing yet) should be or 
at least have access to some 'ClassResolver' with two main methods: 
addClass("key", theClassNode) and useClass("key", theUserNode)



Now the ClassResolver would have internally two Maps:
- one of added fully created Classes:
     key=name of the class, value= the classNode
- one of yet unsatisfied registered Users
     key=name of the class it is waiting for,
     value=List of waiting 'uses'


Now we could just traverse the DOM-Node with the builders we know
- A ClassNodeBuilder would just go about creating a new ClassNode with 
it's nested (final list of) children, and then adding that to the 
ClassResolver with it's 'key' (be that the @id or @type)

addClass in Resolver would:
1/ add the classNode to its internal map with the mentioned 'key'
2/ and then notify the waiting (defined ahead) Users by running through 
the potential available List of them at 'key' in the other map,
3/ these last will need a public setClassNode to receive the reference 
to this node

- symmetrically the UseNodeBuilder (which cannot have any nested 
children, correct?) just creates the UseNode but has to leave open it's 
reference to the class at the time of creation (no final helas) and then 
hands it over to the ClassResolver to register it for 'use' of that 
specific 'key'

useClass in Resolver would then:
1/ check if the requested classNode is available in it's first map
2/ if so: set it on the passed userNode
3/ if not: register the passed userNode in the Map of waiting userNodes


finally, to make the user -to- class reference 'almost' final we might 
provide the setClassNode(theClassNode) with some test:
if (this.myClassNode == null) {this.myClassNode = theClassNode}
to at least make sure that it can only be set once (I know: this is me 
nitpicking again...)

hell, I would even go so far as throwing an exception:
public void setClassNode(ClassNode theClassNode)  {
   if (this.myClassNode != null) throw new XXXException("...");
   this.myClassNode = theClassNode;
}

at the end of the process we could additionally check if there are any 
unsatisfied Users waiting, and maybe throw some exceptions or at least 
create log-warnings


if above is not flawed then it achieves:
- no need for DOM searches, (and the proposed cheating on the order of 
declaration and use)
- still surviving the immutable thingy, although not with a pure 
private/final: we did create our own guarded set-once member
- no need for two passes or a secondary tree of objects...
- run-time classes that have no residu of their complex build up 
procedure (no resolve() or setParent() getParent() stuff, being able to 
remove the untrue additions to the Binding interface...)
- no need for bidirectional parent-child pointers

which would relieve most of the original reservations I had...

regards,
-marc=



Tim Larson wrote:

> [Forwarding Marc's reply.]
> 
> Timothy Larson wrote:
> 
> 
>>I will try to explain the static and dynamic aspects that
>>were added to cforms with class/new and union.  Please let
>>me know any areas this does not clear up for you.
>>
>>Class/new in the form model:
>>  A *general* utility to allow for widget definition reuse.
> 
> 
> This sounds like confirmation of how I saw them
> 
> 
>>  It is not at all specific to the dynamic stuff in the form
>>  model, but just happens to also be useful for that application.
>>
> 
> 
> this sounds comforting...
> 
> 
>>Union in the form model:
>>  Please see the sample form model design GUI for an example
>>  of its use.  The widget definitions are handled in the normal
>>  static way at definition building time.  The difference is the
>>  widget instances are created on demand at runtime (this is the
> 
> 
> where is that done precisely?
> are you adding widgets to the definition-tree during the interaction 
> session?
> where do I find this in the code? js-event-handling?
> 
> how does this work in conjunction with the cache inside the 
> DefaultFormManager?
> 
> how do they get dynamically removed again?
> 
> 
> 
>>  "dynamic stuff in the form model").  Note that this non-recursive
>>  use does not require class/new.
>>
>>Recursive form models:
>>  If we combine the features of class/new and union we can
>>  statically specify theoretically infinitely recursive forms,
>>  where the actual recursive depth is controlled by the data
>>  that is present, such as required to create form-based GUI's.
>>
> 
> 
> lemme see if I get this:
> you have one statically build tree of WidgetDefinition's
> you derive an instance of that tree
> in that instance-tree you dynamically add new instance-widget-nodes that 
> refer to definitions in the original tree?
> 
> so the cache DOES keep on just working! (new derived instance trees are 
> not affected by added nodes in another instance...)
> 
> and now I finally get it: the ready-build form-defintion tree will also 
> need to have the class definitions present (I was still thinking the 
> assistant would be the only one needing those --> hence stressing the 
> reuse of the available DOMtree) some other type-of-assistant should be 
> available that knows the build class items that might get referenced 
> later on?... on second thought: the new-definition just holds a pointer 
> to this class-definition, no?
> 
> OK, I just _think_ I understand now
> lemme think some more on how to deal with this...
> (thx for taking the time to persist on me here, I don't think looking at 
> the sample was going to yield the same depth of understanding, or am I 
> really just a lasy but?)
> 
> in any case: this fights big time with how binding is currently working!
> The binding processing is (only) driven by the tree-structure of the 
> binding definition file... your use of one and the other will require us 
> to let binding be driven by the actual instances that need to be bound, 
> no?...
> 
> during load the backend-model needs to drive
> during save it is the form-model's turn
> 
> 
>>  Problem:
>>    A class that contains a "new" reference to itself would
>>    specify an unlimited recursive definition.  A smart builder
>>    would notice that the class contains a reference to itself
>>    and would substitute a simple Java object reference to the
>>    first (and only) definition it built to represent the class.
> 
> 
> yep, the thought crossed my mind
> 
> 
>>    With this trick we do not run out of memory attempting to
>>    re-create the class definition inside itself over and over.
>>
> 
> 
> yep, but the resulting widget-def-graph is no longer non-cyclic
> 
> 
>>    So we have no problems until we try to create an instance
>>    from this class definition.  The instance of the class
>>    cannot use the object reference trick to handle the infinite
>>    recursion, because each nested instance needs to have its
>>    own data.  Therefore the simple recursive class definition
>>    cannot be instantiated on finite physical hardware.
>>
>>  Solution:
>>    Since we only have trouble with the instance, we only need
>>    to introduce dynamic behavior in the instance.  Notice that
>>    the definitions are never dynamically created or modified.
> 
> 
> yes, confirming my sudden insight above
> 
> 
>>    The only dynamic activity is the act of choosing when to
>>    create instances from the definitions.
>>
>>    We need a way to delay creation of the nested instances
>>    until they are actually required, which implies we need a
>>    way to indicate or determine when the nested instances
>>    become required.  This indicator could be stored in a normal
>>    widget to give us all the things a widget gives, such as
>>    binding, validation, and user interaction.  While we could
>>    use a boolean (required/not-required), why not make it a more
>>    general selector that indicates which nested instance from
>>    a set of options is currently required.  This is what was
>>    implemented as the Union widget.  Maybe it should have been
>>    called the "Selector" widget instead?
>>
> 
> 
> so the union class is the one that does the addition of nested widget 
> instances?
> 
> so when you derive a form-instance of it, it has no children, but then 
> creates them when it gets its selecting-value set?
> 
> and by creating a selection that has possibly nested another union, we 
> can go on playing this game... pfew...
> 
> 
>>    The rest of the interaction between class/new and union is
>>    just to catch non-terminating recursion caused by form design
>>    errors where class/new and union were not used appropriately
>>    as described above.  No use allowing the server to fall over
>>    with out-of-memory errors if we can catch the problem early.
>>
>>Dynamic behavior in form bindings and templates:
>>  The recursive forms described above still need bindings to
>>  load and save their data and templates to present their data
>>  to the user.  This forces us to mirror the class/new and union
>>  concept to the binding and template implementations.
>>  Like the definition handling above, the bindings and templates
>>  can be statically specified just as they normally are, with
>>  just the object reference trick added to the building process
>>  to prevent infinitely recursive building.
> 
> 
> yep.
> 
> 
>>  The dynamic selection of bindings or templates to process is
>>  controlled by "union" bindings or templates which are driven by
>>  the actual data being loaded or the data in the form being
> 
> 
> yeah, that was my observation above... bindings (like form definitions) 
> just now their kids, and (should) have no dynamic behaviour
> 
> but I think the dynamics here would just need to be in how the 
> processing of the load() and save() are working, so I guess we can just 
> have a union binding that 'selects' one appropriate child-binding based 
> on the available child in the form-model or backend-model?
> 
> if that child-binding would be (or containing nested down) a new-binding 
> then that just points to it's class binding who should continue based on 
> the narrowed down context
> 
> and again if down here is another union-binding, then we have a moment 
> of model-driving up in the cycle
> 
> avoiding cyclic stuff can be worse here: during load of a cyclic 
> object-graph for instance we could be doomed, no?
> 
> 
>>  saved or templated.  Notice that the bindings and templates
>>  are never dynamically created or modified.  The only dynamic
>>  behavior is the choice of when to invoke the bindings or
>>  templates to perform their binding or templating.
>>
>>The "static final" issue with the model, binding, and template:
>>  The way class/new resolution currently works prevents the use
>>  of the "final" modifier because the last build step, resolve(),
>>  acts like a linker, replacing each "new" references to a
>>  "class" with references to the definitions, bindings, or
> 
> 
> yeah, but we already discussed that we could do this resolving at 
> build-time by inspecting the DOMtree and create the class-definition 
> when we need it, and then later hook it up in the tree when we pass it.
> 
> once the reference is in place we can get into the dynamics during 
> processing time, no?
> (unless you want to dynamically assemble the 'id' of what the 'new' is 
> pointing to?)
> 
> 
>>  templates contained in the referenced class.  Note that this
>>  all occurs at build time, and the definitions, bindings, and
>>  templates are are never modified after the build is completed.
> 
> 
> indeed, that's why we could do it inside the build-classes rather then 
> inside the binding classes.
> 
> 
>>  Also note that the definitions, bindings, and templates are
>>  created only once (when their containing class is built) and
>>  they are then only *referenced* with Java object references
>>  into each place where the class is referenced by "new".
>>
> 
> 
> yes.
> 
> 
>>  As described above, the only places were there is dynamic
>>  behavior is in the choice of when to create widget *instances*,
>>  when to call bindings, and when to perform templating.  The
>>  definitions, bindings, and templates themselves are completely
>>  *static* (never modified) after they are first built.
>>
> 
> 
> hoeray!
> 
> 
>>  There are various techniques we could use, such as the DOM
>>  tree processing you described, to allow us to use the "final"
>>  modifier.  I am not totally convinced (yet) that it is worth
>>  the effort to satisfy the compiler, or that the subtle resolving
>>  issues will be easy to address.
>>
> 
> 
> hm, I agree that my stress on static final is a quite academic one
> 
> IMHO it communicates a vision more then anything else, and sticking to 
> it requires us to allign with the vision... it's probably only because I 
> had that original vision, but I feel that the end-result of our 
> discussions are yielding a cleaner design that more nicely separates 
> build from actual processing...
> 
> but again, I might be alone here: your commit confused me, now things 
> are more in place (and just some commits waiting)
> 
> the effort on your side was getting past my bonehead, the advantage is 
> that I'll be more aware and able to help out and discuss in future
> 
> let's hope that will eventually pay off :-)
> 
> 
> 
>>Hope this adds clarity,
> 
> 
> it does, thx.
> 
> -marc=

-- 
Marc Portier                            http://outerthought.org/
Outerthought - Open Source, Java & XML Competence Support Center
Read my weblog at                http://blogs.cocoondev.org/mpo/
mpo@outerthought.org                              mpo@apache.org


Mime
View raw message