Good summary, some comments embedded.

"Geir Magnusson Jr." wrote:
> 
> This is a good conversation.  I want to try to summarize to help push
> towards some conclusion.  The following combines a whole pile if ideas from
> various people.
> 
> First, note that I am trying to look at this mainly from the point of view
> of the template author, and since we are talking about VTL behavior for the
> most part, I think that's appropriate.
> 
> There are three possibilities declared as needed so far for the 'state' of
> an reference :
> 
> A) There is a valid object in the context for a given key.
> B) There is a null in the context for a given key.
> C) The key isn't in the context.
> 
> And we want :
> 
> 1) In the template, to be able to know if a reference doesn't have a
> 'value'.  Note that this is different that they way I have previously
> expressed this, namely "Is a reference in the context?".  I think the goal
> is the same to the template author, in that either way, you can't do
> anything,  but 'having a value' may help clear the thinking.
> 
> 2)  We want to be able to deal with #set($foo = something null ) in a
> consistant way, and the aftermath able to be handled in the template. For
> instance, a method on on object in the context returns 'null'.
> 
> 3) We want to be able to deal with #set( $foo = something invalid) in a
> consistant way, and able to be handled in the template.  For instance, the
> RHS isn't a valid reference, it's null, or $foo.bar is just invalid -> bar
> isn't a method or key.
> 
> 4) We want to handle the app side putting null keys and values into the
> context w/o throwing our hands up and saying 'let the implementation decide'
> or having to sprinkle try{} blocks everywhere.

OK (but note that null keys isn't really required but can be added 
analogosuly to null values). I see this is aiming at the solution 
proposed below.

> 
> 5) We want the chained contexts to be handled in a reasonable way.  I
> personally feel strongly that to keep things simple and predictable when
> chaining multiple Context implementations, the chained context should be
> guaranteed not to be altered - it's read-only.  (Useful property for
> frameworks that might have a pool of pre-filled tool contexts, for example.
> And if the template is altering the context, constraining it to the local
> level and letting the app handle it seems the best to me.)

-0, I can very well imagine VMs updating the parent context (more below). 
Whereas the tools and defaults set up as a base context should be read-only.

> 
> One approach would be to make something referred to as 'NULL'.  Note this
> isn't the Java 'null', but something that combines B & C above.  I would
> envision as a singleton Object defined in AbstractContext or elsewhere that

Singleton pattern with a private constructor:
  final class Null {
     public static final NULL = new Null(); // populates it during class loading
     private Null() {} // no other instance can be made
     public static Null getNull() { return NULL; }
     public static String toString { return "NULL"; }
     public static boolean equals(Object obj) { return (obj==null) ? true : obj==NULL; 
}
  }

> would be placed into the context in place of null, and then would be used
> for comparison.  It would :
> 
> - for #1 above, be available for equality comparison in VTL a la  #if ($foo
> == NULL)  : which asks "Does $foo have a valid value".  We remove the

Now it could be simply #if ($foo == $NULL), no change in the parser!
Note that Jose also proposed a $?foo syntax.

> question "Is it in the Context?" because it's meaningless to a template
> designer.  I mean, if there is a value for this reference, we can do
> something with it.  If not, it doesn't matter if it's a null valued key in
> the context, or not in there.  The results are the same.  For debugging, we
> should have appropriate log messages generated both from the app side using
> the Context interface and the template side #set() directive so you can
> figure out why something == NULL

Please note that sometimes returing null is desireable:
  #set( $dummy = $hastable.put("KEY", "woobie") )
Do I have to place a bang into $!hastable to avoid a message?

> 
> - for #2 above, would handle the case when we do a null assignment in a
> #set().  Internally, we would just put the NULL object into the context for
> that reference, and log it if in debug mode (or whatever)

It's OK if the AbstractContext handles the NULL-object putting, and there
are no other means of accessing the HashMap behind from the application.

> 
> - for #3, the same thing - we would place the NULL into the context when we
> had an invalid RHS, and log of course.
> 
> - for #4, same thing
> 
> - for #5, we preserve the idea that chained contexts are immutable (if we
> decide we want that), and by putting NULL into the 0th or local context, we
> would functionally 'remove' the chained value so it won't be accessable.
> because we mask it : the local get() returns the NULL object.

-0 for immutable chained contexts. It should be the implementation/application
to decide that (more below).

> 
> This would be a useful feature with chaining : a framework could fill a
> context with a complete toolset, and then a permission layer/manager could
> chain that context and 'mask off' the tools that aren't allowed for a given
> user/session/whatever.

exactly!

> 
> What's missing?
> 
> More inline :
> 
> Christoph :
> > Jose is pointing to a problem with the dropping using chained contexts.
> > So maybe the keeping the Context API simple is a *too* hard limitation.
> >
> > I originally said "dropping would work for me", but this does not
> > seem to apply for all applications. Vel should be simple but general
> > enough to avoid contradictions.
> 
> I agree 100%.  We should never limit generalization.  Does the above handle
> it?

Missing the notion of a mutable chained contexts and a #local...#end directive.

> 
> > Note that I'm not from the "no-null lobby", but am a "NULL friend" :)
> 
> > The only case I would rather see a NULL value is when I want to debug
> > the context and list the "keys = primitive-values (or class-name)".
> > Here it is usefull to see that foo exists and is invalid: "foo = NULL".
> 
> Well, that seems to be a java-side function rather than template side.
> There is a keys() method to Context, so you should be alble to get an array
> of keys. And then you can do a #if($foo == NULL) on the template side.

yes, I will probably need a PD to make keys() visible in the template
(to dump the context using a template or WM!).

> 
> > Now for the context chaining it will be necessary to differentiate
> > between a no-value and no-definition states. So there is a reason
> > for NULL values (Hi NULL friends :).
> 
> I don't think we need to differentiate in the template.  Logging them, yes.
> So the concept of a NULL would work if it covered both.  As the template
> author, you just want to know if it's usable, right?

OK, but I would like a way to avoid logs (using bang? - example above).

> 
> > Will VMs use context chaining? If so, will a macro be able to
> > update higher level contexts? I guess the best way to go is to have
> > a TransparentContext, where updates affect the parent contexts;
> > and a LocalContext (= VelocityContext?) instatiating a chaining by
> > a #local directive (as proposed in another thread) that makes all
> > #sets only affect the local one. Then safe VMs should allways
> > contain a #local...#end, which can be left away for speed purposes
> > and/or when it does not do any dangerous sets.
> 
> The use of chained contexts in the current impl is transparent.  Anything
> accessing the context will access the values in a chained context (layer >
> 0) if the 0th layed doesn't have anything for that key.
> 
> I don't understand the need to update a higher level context.  I think it's
> invasive, and really complicates the issue.  I think the real use for these
> things is allowing thelayering of tools and data in a clean, safe,
> recoverable way.  If the template needs to update the context, constraining
> those alterations to the local context (0th level) seems fine.  That seems
> like an app architecture issue to handle that, keeping the Vel chained
> context  idea simple and safe.

Im missing a form for WMs to update/return values. I tried to explain that
above. I know that VTL is not a programming language, but I believe this
is general enough. The mutable chained contexts and a #local...#end directive
would fix this.

> 
> > > > Well this is exactly my point. Christoph's solution of simply removing
> > > > the context entry does not work. Why?, because it would expose the old
> > > > value after the set operation which, I think is the more confusing 
> > > > behavior we can have.
> > >
> > > Hm.  It would expose a value in a chained context if it exists.
> 
> > Well, who defines which context implementation is in effect? It seems that
> > the AbstractContext shall allow NULL values, and the actual implementation
> > should refuse it if not proper; or eventually propagate it to the parent
> > context if it cannot handle it locally (after a local remove).
> 
> Well, the problem I see there is the utter confusion that results if you
> have multiple context classes with mixed null support.

I agree to the NULL handling you are proposing above. So no more confusion.

> 
> So I think that we should choose one or the other.    And if we have a
> solution like above (it doesn't have to be that) that keeps it clean and
> simple for the template designer, keeps the behavior consistant and
> deterministic, and handles all the issues so far proposed, then supporting
> NULL is a decent way to go.

yep.

> 
> [SNIP]
> > > Hm.  I agree that there is a difference, and to some degree it's
> > > important.  I wonder, though, if its more important to keep things
> > > simple for the template creator.  You do quite advanced templates.  I
> > > don't think the average user would come close to what you come up with.
> >
> > The template creator does not see the difference.
> > If he cares he could implement somehow a containsKey (e.g. #ifdefined)
> > to check the difference between a no-value and a no-definition.
> 
> there is a containsKey() in the Context interface that should be supporrted,
> so the java programmer has a way of checking.
> 
> If we do implement NULL and allow #if( $foo == NULL) then the template can
> also figure it out.  I don't though see that it's terribly important to
> distinguish between 'null value' and 'not in the context' on the template
> side of things. Either way, you can't do anything with it in the context,
> and the log can tell you what is going on.
> 
> geir

:) Christoph

Reply via email to