To give a specific example of what I'm trying to do, I'd like to use
velocity templates in Clojure.  So I have this code:

(in-ns 'velocity)
(clojure/refer 'clojure)

(import '(org.apache.velocity.app VelocityEngine))
(import '(org.apache.velocity VelocityContext))
(import '(java.io StringWriter))

(defn render [template context]
  (let
      [ve (new VelocityEngine)
       ctx (new VelocityContext context)
       out (new StringWriter)]
    (.init ve)
    (.evaluate ve ctx out "clojure" template)
    (.toString out)))

And then I can do:

(velocity/render "foo is $foo" {"foo" "bar"})

But obviously this isn't going to work:

(velocity/render "foo is $foo" {:foo "bar"})

So short of modifying the Java implementation of either Clojure or
Velocity to be indifferent to Strings/Keywords, I either have to:

1) Only pass String-keyed maps into this method
2) Have this method turn all the Keywords into Strings before creating
the VelocityContext

I'm leaning towards #2, just because I would expect (velocity/render
"foo is $foo" {:foo "bar"}) to "work", and others might too.  I'm
thinking about how to build a MVC web app with Clojure, and I would
have the model layer return Keyword-keyed maps that represent data
stored in the database, and then I'd like to pass those values into a
method like this to be the view layer.

What are your thoughts?  Should I change the model layer to return
String-keyed maps?  Or convert the Keywords to Strings before building
the VelocityContext?

On Oct 13, 9:58 am, Rich Hickey <[EMAIL PROTECTED]> wrote:
> On Oct 13, 9:34 am, Paul Barry <[EMAIL PROTECTED]> wrote:
>
>
>
> > I was thinking this is a little different because the Keyword data
> > type is unique to Clojure.  So once in the Java land, you are never
> > going to want to use Keywords.  In Clojure, I agree, the difference
> > between Keyword and String should be explicit, but in Java, I feel
> > like it's just pragmatic to be able to pass in a String and get the
> > value with the matching Keyword.
>
> > I think this might be possible to do because many of the methods that
> > implement java.util.Map are wrappers on the clojure methods.  For
> > example, in APersistentMap, you could change get from:
>
> > public Object get(Object key){
> >         return valAt(key);
>
> > }
>
> > To something like:
>
> > public Object get(Object key){
> >   if(key instanceof String) {
> >     if(contains(key)) {
> >       return valAt(key);
> >     } else {
> >       return valAt(stringToKeyword(key));
> >     }
> >   } else {
> >     return valAt(key);
> >   }
>
> > }
>
> > I'd have to look at all the other methods that implement
> > java.util.Map, but if they are all separate from the actual methods
> > that make clojure maps work like they do, you could get the best of
> > both words.  But if everyone thinks this is a bad idea, then I'll just
> > write my function to convert all Keywords in a Map to a String before
> > passing them to Java.
>
> > > Hi Paul,
>
> > > I think that I would rather see things remain explicit, i.e. if you
> > > need to interoperate with Java you convert manually before throwing
> > > the map over.
>
> > > In the Rails world they tried to solve a similar problem (string vs.
> > > symbol keys) by wrappering Hash to be indifferent between string and
> > > symbol keys, and it is still confusing. Now you have to remember
> > > whether you have the wrappered kind or not...
>
> > > Stuart
>
> > > > Now that clojure maps are Java Maps, it is easier to inter-operate
> > > > with Java code that has methods that take a Map as one of its
> > > > arguments, because you can just pass the Map right into the Java
> > > > code.  The problem is that often times, the Java method is expecting
> > > > the Map to have String values in the keys, definitely not clojure's
> > > > Keywords.  So if you have a {:foo 1} clojure map that you pass to a
> > > > Java method, which then calls map.get("foo"), you won't find that
> > > > value.
>
> > > > Does anyone have any suggestions for how to handle this?  You could
> > > > just use Strings for the keys in the clojure map, but then that map
> > > > might not work with other clojure functions that expect the keys to be
> > > > Keywords, not Strings.  You could pass the map through a function that
> > > > converts the Keywords to Strings before using it in Java, but I
> > > > thought that was the whole point of making clojure maps implement Map,
> > > > so I wouldn't have to do (jmap {:foo 1}) everytime I want to pass a
> > > > Map to Java.
>
> > > > I'm wondering if there is some way to make a clojure Map be smart
> > > > enough to return the value even if you give it string.  Probably not,
> > > > because then what do you do with {:foo 1 "foo" 2}.  Anyway, just
> > > > wondering if anyone else has run into this Keyword/String mismatch
> > > > problem and if you have an elegant solution.
>
> If a Java method took a String, you'd pass it a String. If it takes a
> map with String keys you should pass it exactly that. There seems to
> me to be absolutely no reason not to use strings for keys in that map
> on the Clojure side too. Nothing in Clojure expects maps to have
> keywords for keys - strings, numbers, and Clojure collections all make
> fine keys.
>
> Keywords are often used as keys in examples, as that map usage idiom
> stands in, in Clojure, for 'objects with properties' in many cases.
>
> Automatic conversion is a slippery slope. Even manual conversion is
> wasteful and counterproductive. All code using the same map should
> have the same notion of what's in it, IMO.
>
> OTOH, if you are the consumer of the map on the Java side, and just
> need to supply its values as strings to other Java code,
> Keyword.getName() is non-allocating/copying and guaranteed to return
> an interned String (without the ':').
>
> Rich
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to