You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@velocity.apache.org by Art Gillespie <ag...@i-no.com> on 2001/04/17 06:38:51 UTC
Compiler
Has there been a lot of design work/discussion on the compiler? I've been watching the CVS tree for a few weeks, and I notice that the org/apache/velocity/compiler package hasn't moved much/any, although I see that Jason Van Zyl has put together a skeleton Compiler class.
Further research at the mail archives (search on compiler at theaimsgroup) doesn't reveal much, either, so please forgive me if I'm revisiting a design/implementation discussion that has already taken place or treading on anyone's pet compiler project territory.
Is the idea to make the compiled *.vm derive from org.apache.velocity.Template and implement merge()? This was my idea, and I've been working on traversing the AST Tree and generating Jasmin (for design only... I did get the impression from the mail archives that on one is interested in intermediate formats in the final implementation : ) ).
At any rate, I thought I'd check in before I spent too much time on this...
Is the compiler open for discussion/development?
-art
Re: Compiler
Posted by Art Gillespie <ag...@i-no.com>.
On Tue, Apr 17, 2001 at 06:29:56AM -0400, Geir Magnusson Jr. wrote:
> Jason van Zyl wrote:
> > I will clean up what I have and try to push it into CVS in
> > the next couple of days. What I have creates a Template class
> > in memory, something that could be placed in the cache.
> >
> > The idea is to try and get rid of all reflection in an attempt
> > to make the rendering go as fast as possible. What I am assuming,
> > in order for compilation to be of any use, is that the type
> > represented by a reference in VTL is constant. This is not
> > what Velocity assumes right now.
>
> I don't think that assumption has to be there. That 'polymorphism', in
> that
>
> $object.foo
>
> can be rendered from a Map or *any* class that looks like
>
> class MyClass
> {
> public String getFoo();
> public String get( String );
> }
>
> w/o inheritance worries is a really great feature.
>
>
Hmmm.... since we're talking about an in-memory compiler, theoretically we _could_ change the class' constants table on the fly in response to different types, adding new types as they come in on the Context and simply index into different type declarations for the method call. Back in the real world, I agree with Jason... if you use different classes arbitrarily (e.g. Moose v. Sheep with no common base class), you can't expect to not suffer the reflection penalty.
Perhaps compiling an entire template (the all-or-nothing) approach isn't the right way to think of this: we could do some heuristic monitoring at runtime and 'optimize' nodes that warrant it on the fly. Whereas in our discussion we create an in-memory class derived from Template that implements merge, we instead create an in-memory class derived from Node that implements render(). In a simple template, where types are deemed to be consistent, the root node may be optimized. (This would, in effect, be the same as compiling the entire template). In other scenarios, some nodes might be compiled while others still use reflection. In the event of an invocation error in a compiled node, we dispatch the context back to the compiled node's AST peer.
voila! Velocity Hotspot!
-art
Re: Compiler
Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Jason van Zyl wrote:
>
> Art Gillespie wrote:
> >
> > Has there been a lot of design work/discussion on the compiler? I've been watching the CVS tree for a few weeks, and I notice that the org/apache/velocity/compiler package hasn't moved much/any, although I see that Jason Van Zyl has put together a skeleton Compiler class.
> >
> > Further research at the mail archives (search on compiler at theaimsgroup) doesn't reveal much, either, so please forgive me if I'm revisiting a design/implementation discussion that has already taken place or treading on anyone's pet compiler project territory.
> >
> > Is the idea to make the compiled *.vm derive from org.apache.velocity.Template and implement merge()? This was my idea, and I've been working on traversing the AST Tree and generating Jasmin (for design only... I did get the impression from the mail archives that on one is interested in intermediate formats in the final implementation : ) ).
> >
> > At any rate, I thought I'd check in before I spent too much time on this...
> >
> > Is the compiler open for discussion/development?
>
> Sure is, I haven't gone very far with another version I have here.
> I will clean up what I have and try to push it into CVS in
> the next couple of days. What I have creates a Template class
> in memory, something that could be placed in the cache.
>
> The idea is to try and get rid of all reflection in an attempt
> to make the rendering go as fast as possible. What I am assuming,
> in order for compilation to be of any use, is that the type
> represented by a reference in VTL is constant. This is not
> what Velocity assumes right now.
I don't think that assumption has to be there. That 'polymorphism', in
that
$object.foo
can be rendered from a Map or *any* class that looks like
class MyClass
{
public String getFoo();
public String get( String );
}
w/o inheritance worries is a really great feature.
> So what I'm assuming is that in something like the following:
>
> ---
>
> $object.Name
>
> ---
>
> is that $object will change instances but that the $object to be
> displayed will at least have the same base class. So that bytecode
> can be produced that represents $object.getName(). In other words
> the reflection is done once and stored, this is how Velocity originally
> worked. Velocity now assumes that $object could be completely
> different from one rendering to the next.
I think that this is solvable. If you generate code like :
try
{
reference.getName();
}
catch( <whatever>Exception e )
{
introspect...
}
then you can make your assumption but also let Velocity be flexible.
> I am in agreement with Geir that this is the safest, as we discussed
> this
> when changes were made to support varying object types in the context
> from one rendering to the next, but I don't believe this is a normal
> usage
> pattern. I believe that in most cases the $object type is constant, and
> I would argue even further that if the type of (base class) does change
> then there is some poor design somewhere.
I'm not sure that is a valid assumption to make, because bean behavior
makes no assumptions about class hierarchy - simply a set of patterns
for getters/setters.
This is a huge 'paradigm shift' for Velocity - going from bean behavior
support to worrying about implements / extends...
> If you had some VTL like:
>
> ---
>
> Today's creature of the day is $creature.Name
>
> ---
>
> and the context builder had something like
>
> if (user.likesSheep())
> context.put("creature", new Sheep())
> elseif (user.likesMoose())
> context.put("creature", new Moose())
>
> and Sheep and Moose are totally disperate classes then
> I would say that's a design problem.
Why? A Sheep has wool and a moose slobbers. (Dunno... sorry, moose
fans..)
Even if they have the same base class, it says nothing about what kind
of additional methods the derived classes add.
So you could always do, in velocity :
<td> Wool : </td><td> #if($creature.wool) $creature.wool #else N/A
#end </td>
<td> Slobber : </td><td> #if($creature.slobber) $creature.slobber
#else N/A #end </td>
Right? So it seems reasonable that a designer can have domain knowledge
about the data he/she has to handle - suppose you were making a form for
shipping your creature - you might want to know if you need to bring a
vacuum or a mop...
> And even if you had to pull data from disperate sources, I think
> it's still possible that adapters could be used to make what
> is placed into the context of a constant type.
People would beat us with a stick. You wouldn't only need a base class
then, you would need a uberclass adapter to make sure that a Sheep can
slobber. And then theres the maintenance problem of having to recompile
your adapter code whenever you add a new 'behavior'.
The current behavior means that the model can be dynamic and only the
designer has to deal with it. I use Maps all the time for this - when I
have a new 'property', it's a new key in the map :
$creature.wool
$creature.slobber
$creature.moo
Easy in the template.
> None of my applications
> have any changing object type behaviour. Using the model of JSP, or XMLC
> (Enhydra view mechanism) there is the notion of constant type. I haven't
> done a whole lot of research into the matter but my feeling is that
> the types should remain constant. Velocity protects you if this
> type changes but I would be curious to see how often this actually
> happens and when it does why it happens at all.
I use it as I said above : it means I generally don't have to hardcode
my data model - I have the 'data API', the contract between the model
and the designer, and then I am free to be as flexible [lazy] as I want
to be, and the designer never has to know. If I use a Map, great. If I
use a formal class with actual getter methods, cool too.. no one is the
wiser in template land...
> I think a compiler would work, but I don't think there is any point
> in compiling something where the object type in a context can change
> from one rendering to the next. I think both models would work
> (constant and changing types in the context) but I'm not sure how
> both would work together.
I think this is an assumption that may go away with a little
investigation.
geir
> I will put what I have in CVS in a couple of days. But this should
> get the ball rolling. I don't see any reason why a compiled velocity
> template could not be as fast as a compiled JSP page. Maybe Jasper
> and Velocity could even share the same compiler some day :-)
>
> I am currently using the BECL (Bytecode Engineering Class Library),
> which was previously called JavaClass. It's available from sourceforge,
> and I've been playing with the most recent version if anyone wants
> to take a look at it.
>
> There are also many considerations to deal with given #macros, pluggable
> event handlers, but we could definitely start simple and go from there.
>
--
Geir Magnusson Jr. geirm@optonline.net
Developing for the web? See http://jakarta.apache.org/velocity/
RE: Compiler
Posted by Paulo Gaspar <pa...@krankikom.de>.
> These are the cases I'm interested in hearing about. Why do you have
> varying object types for a single VTL reference?
Generic templates:
- Grids;
- Automatic form generation;
- Detail views.
The form generation I still only have in WebMacro, but I am going to
improve it over Velocity. Basically I loop over a list of field
definitions and field values to generate views over data. This means
that the value type changes a lot for each item (data field) in the list.
This (of course) is only good for very simple stuff, but +/-80% of my
data entry forms/detail views/listings are so simple that they can be
built from a simple definition.
I found out that using templates/macros simplifies a lot building and
customizing even this generic stuff, when compared to generating it all
in Java.
Have fun,
Paulo Gaspar
> -----Original Message-----
> From: jvanzyl@krankikom.de [mailto:jvanzyl@krankikom.de]On Behalf Of
> Jason van Zyl
>
>
> Paulo Gaspar wrote:
> >
> > Very interesting stuff Jason.
> >
> > However...
> >
> > > I am in agreement with Geir that this is the safest, as we discussed
> > > this when changes were made to support varying object types
> in the context
> > > from one rendering to the next, but I don't believe this is a normal
> > > usage pattern.
> >
> > Maybe it is not normal, but I have a lot of that in my framework. And
> > I can still thing of many other cases where I would use this.
>
> These are the cases I'm interested in hearing about. Why do you have
> varying object types for a single VTL reference?
>
> > However, it shouldn't be very hard to have 2 types of
> templates, or 2 types
> > of variables (as you mention for XMLC).
>
> I don't think so either. If users want to be a little more strict then
> they get full-on optimization with compilation, otherwise Velocity could
> easily fall back reflection or maybe we could use a hybrid system. Who
> knows, anything is possible.
>
> --
> jvz.
>
> Jason van Zyl
> jvanzyl@apache.org
Re: Compiler
Posted by Jason van Zyl <jv...@apache.org>.
Paulo Gaspar wrote:
>
> Very interesting stuff Jason.
>
> However...
>
> > I am in agreement with Geir that this is the safest, as we discussed
> > this when changes were made to support varying object types in the context
> > from one rendering to the next, but I don't believe this is a normal
> > usage pattern.
>
> Maybe it is not normal, but I have a lot of that in my framework. And
> I can still thing of many other cases where I would use this.
These are the cases I'm interested in hearing about. Why do you have
varying object types for a single VTL reference?
> However, it shouldn't be very hard to have 2 types of templates, or 2 types
> of variables (as you mention for XMLC).
I don't think so either. If users want to be a little more strict then
they get full-on optimization with compilation, otherwise Velocity could
easily fall back reflection or maybe we could use a hybrid system. Who
knows, anything is possible.
--
jvz.
Jason van Zyl
jvanzyl@apache.org
http://jakarta.apache.org/velocity
http://jakarta.apache.org/turbine
http://tambora.zenplex.org
RE: Compiler
Posted by Paulo Gaspar <pa...@krankikom.de>.
Very interesting stuff Jason.
However...
> I am in agreement with Geir that this is the safest, as we discussed
> this when changes were made to support varying object types in the context
> from one rendering to the next, but I don't believe this is a normal
> usage pattern.
Maybe it is not normal, but I have a lot of that in my framework. And
I can still thing of many other cases where I would use this.
However, it shouldn't be very hard to have 2 types of templates, or 2 types
of variables (as you mention for XMLC).
Have fun,
Paulo Gaspar
> -----Original Message-----
> From: Jason van Zyl
> Sent: Tuesday, April 17, 2001 07:32
>
>
> Art Gillespie wrote:
> >
> > Has there been a lot of design work/discussion on the compiler?
> I've been watching the CVS tree for a few weeks, and I notice
> that the org/apache/velocity/compiler package hasn't moved
> much/any, although I see that Jason Van Zyl has put together a
> skeleton Compiler class.
> ..............
>
> Sure is, I haven't gone very far with another version I have here.
> I will clean up what I have and try to push it into CVS in
> the next couple of days. What I have creates a Template class
> in memory, something that could be placed in the cache.
>
> The idea is to try and get rid of all reflection in an attempt
> to make the rendering go as fast as possible. What I am assuming,
> in order for compilation to be of any use, is that the type
> represented by a reference in VTL is constant. This is not
> what Velocity assumes right now.
>
> So what I'm assuming is that in something like the following:
>
> ---
>
> $object.Name
>
> ---
>
> is that $object will change instances but that the $object to be
> displayed will at least have the same base class. So that bytecode
> can be produced that represents $object.getName(). In other words
> the reflection is done once and stored, this is how Velocity originally
> worked. Velocity now assumes that $object could be completely
> different from one rendering to the next.
>
> I am in agreement with Geir that this is the safest, as we discussed
> this
> when changes were made to support varying object types in the context
> from one rendering to the next, but I don't believe this is a normal
> usage
> pattern. I believe that in most cases the $object type is constant, and
> I would argue even further that if the type of (base class) does change
> then there is some poor design somewhere.
>
> If you had some VTL like:
>
> ---
>
> Today's creature of the day is $creature.Name
>
> ---
>
> and the context builder had something like
>
> if (user.likesSheep())
> context.put("creature", new Sheep())
> elseif (user.likesMoose())
> context.put("creature", new Moose())
>
> and Sheep and Moose are totally disperate classes then
> I would say that's a design problem.
>
> And even if you had to pull data from disperate sources, I think
> it's still possible that adapters could be used to make what
> is placed into the context of a constant type. None of my applications
> have any changing object type behaviour. Using the model of JSP, or XMLC
> (Enhydra view mechanism) there is the notion of constant type. I haven't
> done a whole lot of research into the matter but my feeling is that
> the types should remain constant. Velocity protects you if this
> type changes but I would be curious to see how often this actually
> happens and when it does why it happens at all.
>
> I think a compiler would work, but I don't think there is any point
> in compiling something where the object type in a context can change
> from one rendering to the next. I think both models would work
> (constant and changing types in the context) but I'm not sure how
> both would work together.
>
> I will put what I have in CVS in a couple of days. But this should
> get the ball rolling. I don't see any reason why a compiled velocity
> template could not be as fast as a compiled JSP page. Maybe Jasper
> and Velocity could even share the same compiler some day :-)
>
> I am currently using the BECL (Bytecode Engineering Class Library),
> which was previously called JavaClass. It's available from sourceforge,
> and I've been playing with the most recent version if anyone wants
> to take a look at it.
>
> There are also many considerations to deal with given #macros, pluggable
> event handlers, but we could definitely start simple and go from there.
>
> --
> jvz.
>
> Jason van Zyl
> jvanzyl@apache.org
Re: Compiler
Posted by Jason van Zyl <jv...@apache.org>.
Art Gillespie wrote:
>
> Has there been a lot of design work/discussion on the compiler? I've been watching the CVS tree for a few weeks, and I notice that the org/apache/velocity/compiler package hasn't moved much/any, although I see that Jason Van Zyl has put together a skeleton Compiler class.
>
> Further research at the mail archives (search on compiler at theaimsgroup) doesn't reveal much, either, so please forgive me if I'm revisiting a design/implementation discussion that has already taken place or treading on anyone's pet compiler project territory.
>
> Is the idea to make the compiled *.vm derive from org.apache.velocity.Template and implement merge()? This was my idea, and I've been working on traversing the AST Tree and generating Jasmin (for design only... I did get the impression from the mail archives that on one is interested in intermediate formats in the final implementation : ) ).
>
> At any rate, I thought I'd check in before I spent too much time on this...
>
> Is the compiler open for discussion/development?
Sure is, I haven't gone very far with another version I have here.
I will clean up what I have and try to push it into CVS in
the next couple of days. What I have creates a Template class
in memory, something that could be placed in the cache.
The idea is to try and get rid of all reflection in an attempt
to make the rendering go as fast as possible. What I am assuming,
in order for compilation to be of any use, is that the type
represented by a reference in VTL is constant. This is not
what Velocity assumes right now.
So what I'm assuming is that in something like the following:
---
$object.Name
---
is that $object will change instances but that the $object to be
displayed will at least have the same base class. So that bytecode
can be produced that represents $object.getName(). In other words
the reflection is done once and stored, this is how Velocity originally
worked. Velocity now assumes that $object could be completely
different from one rendering to the next.
I am in agreement with Geir that this is the safest, as we discussed
this
when changes were made to support varying object types in the context
from one rendering to the next, but I don't believe this is a normal
usage
pattern. I believe that in most cases the $object type is constant, and
I would argue even further that if the type of (base class) does change
then there is some poor design somewhere.
If you had some VTL like:
---
Today's creature of the day is $creature.Name
---
and the context builder had something like
if (user.likesSheep())
context.put("creature", new Sheep())
elseif (user.likesMoose())
context.put("creature", new Moose())
and Sheep and Moose are totally disperate classes then
I would say that's a design problem.
And even if you had to pull data from disperate sources, I think
it's still possible that adapters could be used to make what
is placed into the context of a constant type. None of my applications
have any changing object type behaviour. Using the model of JSP, or XMLC
(Enhydra view mechanism) there is the notion of constant type. I haven't
done a whole lot of research into the matter but my feeling is that
the types should remain constant. Velocity protects you if this
type changes but I would be curious to see how often this actually
happens and when it does why it happens at all.
I think a compiler would work, but I don't think there is any point
in compiling something where the object type in a context can change
from one rendering to the next. I think both models would work
(constant and changing types in the context) but I'm not sure how
both would work together.
I will put what I have in CVS in a couple of days. But this should
get the ball rolling. I don't see any reason why a compiled velocity
template could not be as fast as a compiled JSP page. Maybe Jasper
and Velocity could even share the same compiler some day :-)
I am currently using the BECL (Bytecode Engineering Class Library),
which was previously called JavaClass. It's available from sourceforge,
and I've been playing with the most recent version if anyone wants
to take a look at it.
There are also many considerations to deal with given #macros, pluggable
event handlers, but we could definitely start simple and go from there.
--
jvz.
Jason van Zyl
jvanzyl@apache.org
http://jakarta.apache.org/velocity
http://jakarta.apache.org/turbine
http://tambora.zenplex.org
Exceptions
Posted by Tim Joyce <ti...@hoop.co.uk>.
i am getting inconsistent behaviour:
i put an object (foo) in the context that has the method:
public String getBar() throws Exception e {
throw new Exception();
}
i write in my template:
$foo.getBar(), then i get a MethodInvocationException from which i can use
getWrappedThrowable() to access the exception (great). and
Tue Apr 17 13:05:48 GMT+00:00 2001 [error] Method getBar threw
exception for reference $foo in template test/TemplateServletTest.vm at
[41,4]
in the log
but if i write:
$foo.Bar, i simply get
$foo.Bar
printed on my page and a comment in the log:
Tue Apr 17 13:03:52 GMT+00:00 2001 [warn]
org.apache.velocity.runtime.exceptio
n.ReferenceException: reference : template = test/TemplateServletTest.vm
[line 4
1,column 4] : $foo.Baris not a valid reference.
i would have thought than $foo.getBar() and $foo.Bar should produce the same
result?
cheers
timj
Re: Compiler
Posted by Christoph Reck <Ch...@dlr.de>.
I liked the WebMacro approach on the introspection. It did the
job once for every class, placed the per-class data in a global
map and reused this for every template. I know Geir has a concern
of the single point cache bottleneck (have you measured the
possible implication in a loaded system?).
As far as I have looked at it, Velocity does a similar job but
keeps the introspection cache on a per-request basis, thus only
speeding-up foreach loops, and similar class accesses. I guess
this means an performance impact if many different classes are
put into the context and each is accessed only once.
Velocity has a cache-enhancement that when parameters are sub-classes
the additional access signature is also cached. Still this means
dozens of java statements until the reflected method is executed.
It seems that Geir has enhanced speed by doing a "try-the-obvious"
getMethod() before entering the introspection mecanism. This makes
the introspection mecanism/cache somewhat obsolete.
I may be wrong in my above understanding, since I have not done
deep analysis after geir added the ica/icb stuff. Please correct
me if I've made wrong statements.
Compiling (in memory please - to avoid being like JSP) means that
the template is a class. References are simple Context.get method
accesses. Identifiers are compiled into some type of method lookup.
Since the classes in the context is not necesarily known at compile
time (or may change thereafter), there must exist some type of
post compliler and lookup tables for these accessor classes. This
ends up in being something like a reflection cache - avoiding
the Method.invoke().
An implementation like this would be on the bleeding edge of
technology and could possibly be a performance boost.
To really improve performance we will need to assess different tradeofs:
* central cache bottleneck
* per-request cache overhead
* compiled methods (e.g. SDK1.3 reflection proxy classes/templates?)
And a mixture of these...
:) Christoph