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