On Fri, Apr 1, 2011 at 22:18, B Smith-Mannschott <bsmith.o...@gmail.com> wrote:
> On Wed, Mar 30, 2011 at 15:00, Stuart Sierra
> <the.stuart.sie...@gmail.com> wrote:
>> Take a look at http://www.stringtemplate.org/ for a Turing-complete,
>> purely-functional, Java-based template language designed for code
>> generation.
>

Well, I've spent the weekend wrangling with StringTemplate (ST) and
though I'd share my experiences so far. I'm sorry; this is a bit
rambling.

I chose to jump straight to ST 4, which came out at the end of March,
figuring there was no point in learning 3.x since 4.0 seems to be
where active development will go in the future.

This was a mixed blessing because the practical examples available on
the net and the majority of the documentation is actually still for
3.x, which is not completely compatible with 4.0.

Also, I found ST's behavior with respect to syntax errors in templates
to be less than helpful. Basically it'll throw a NullPointerException,
or maybe an IllegalArgumentException or just puke some stuff on the
console (generally hidden behind my emacs window). This is rough for a
learner.

Also, I'm generating java source code which includes uses of generics.
This interacts hideously with ST's default of using < and > to delimit
a template expression and  << and >> to delimit the beginning and end
of a template definition. This can be customized, but the
customization is not all I hoped for.

At first I tried to customize to « and » but this breaks the ability
to include comments in the string template group file. (Normally
comments are <! ... !>, presumably they would be «! ... !» when one
has customized the delimiter characters like I had. But, the fact is
neither syntax seemed to work. This cost me *hours* because while the
console printed out a huge number of error messages, they were always
the same error messages printed in such a way that the console never
seemed to scroll, so I thought I was looking at old output and had
fixed the problem (by changing <! to «!). The parse errors caused the
non-comment comment caused all kinds of strange behavior in later
templates, such as crashes. I found, for example, that:

someTemplate(a,b) ::= « ... »
«list1,list2:someTemplate()»

which is roughly analogous to:

(defn someTemplate [a b] ...)
(map someTemplate list1 list2)

Would crash complaining about not having definitions for i0 and i
(these variables are something ST defines implicitly for iteration. I
don't know the details.)

I found I could fix that by changing the template definition to
include i0 and i arguments, though I never used them in the template.
This just seemed demented. It was at that point that I went to bed.

This morning, I finally understood the comment problem and found that
if I changed the delimiters to $ and $ and the comments to $! and !$
all was once again well with the world. It's annoying though that
opening $ and closing $ are the same character, which doesn't aid
readability.

So, I've made some progress in my understanding of ST. Now that I sit
down and try to re-implement my existing code emission using ST, I
find a design question rearing its head. I'm not sure how much
complexity to push into the templates and how much to leave in
Clojure.

I could have a large number of very simple templates and use Clojure
to drive and assemble them. Alternatively, I could have a single
"entry point" to a large set of templates which call each other
internally. That means using Clojure to construct a data model (a map
of lists of maps of ...) suitable for consumption by ST.

First I through I'd take the first alternative, but then I decided to
try the second one first, though now it's looking like I will go back
to doing more in clojure and less in ST.  I already have a perfectly
serviceable model but it seems increasingly like I'd have to tear it
apart and build it up completely differently to get it into a form
that ST can consume in a reasonable fashion.

Here's  a simplified fragment of my model:

{ :class-name "SomeEnum"
  :id-field   :id
  :records [{:id "A", :payload 3},
            {:id "B", :payload 4}] }
produces:

enum SomeEnum {
  A(3),
  B(4);
  int payload;
  SomeEnum(int payload) {
    this.payload = payload;
  }
}

- I'm using keywords, but StringTemplate can't tolerate those as keys
- ST's variable's can't contain -, so I can't just convert the keyword keys
  to strings, I have to rename them too.
- the type of :payload is not stored explicitly anywhere, but it's a real
  java Integer in the model, so I just use (type) to figure out what it is.
- I have an function (unbox) which gives me the unboxed equivalent
where appropriate,
  otherwise identity. (ST provides Maps, as part of its template
language which could
  almost do this for me, but not quite.)
- I have logic to generate "java literal" versions of various values:
  i.e. 1.0M -> BigDecimal.ONE; 11.0M -> new BigDecimal("11.0")
  (ST supports ModelRenderers for this, I think).

It's looking more and more like using ST is going to involve as much
Clojure code as not using ST -- and that's not counting the additional
template code. This doesn't feel like a clear win.

I'm still very much an ST beginner, but I feel that I struggling
against an impedance mismatch of a sort. Maybe it's because ST is
designed to feed off an OO model, and I've got one that's functional
(all immutable data really).

Indeed, I ran across this just this evening:

  
http://steve.vinoski.net/pdf/IC-Clojure_Templating_Libraries_Fleet_and_Enlive.pdf

The author seems to have found the same mismatch between Clojure and
ST that I have, though he does a better job of explaining it. One of
the two alternatives he recommends  https://github.com/Flamefork/fleet
seems like it could fit to what I'm trying to accomplish. Still, I'd
like to first finish my attempt with ST before I decide wether to
stick with it or not.

// ben

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to