The problem could be that #{} in clojure is a set literal, try using clojure.lang.PersistentHashSet/create
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@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+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
The code works BUT if I try to pass in a map for example like so
Object result = foo.invoke( "hello","world","#{:a 1 :b 2}");
The easiest might be to just pass a map literal (in String form)
through the Clojure reader. Variable integers or other simple objects
can just be incorporated using the Java String + operator; the
concatenation will always start with a string literal such as "{" so
this will work in general. (It's likely keywords etc. will be constant
while numbers might be variable.)
--
Protege: What is this seething mass of parentheses?!
Master: Your father's Lisp REPL. This is the language of a true
hacker. Not as clumsy or random as C++; a language for a more
civilized age.
Am 18.09.2011 um 04:58 schrieb Eamonn:
> I tried the following
> Var keyword = RT.var("clojure.core", "keyword");
> Var hashMap = RT.var("clojure.core", "hash-map");
> hashMap.invoke(keyword.invoke("a"), 1);
>
> then I created the following function
> (defn foo[key paramMap](key paramMap))
>
> Object result=foo.invoke(keyword.invoke("a"), hashMap);
You pass the hash-map function, not a map. Just as in clojure you have to capture the return value.
Object theMap = hashMap.invoke(keyword.invoke("a"), 1);
Object result = foo.invoke(keyword.invoke("a"), theMap);
You get caught be the keyword lookup, because keywords return nil on non-map/set objects. If you change your foo as follows, you will get 5.
(defn foo [k m] (k m 5))
> But I got null returned but when I do as you suggest
> Object result=foo.invoke(keyword.invoke("a"),
> hashMap.invoke(keyword.invoke("a"), 1));
> I get 1 returned
Here you pass the return value of the hash-map call directly. Hence it works.
Sincerely
Meikel
It's a complete mystery to me why people in the 21st century still promote messing around with strings as FFI when an easy and simple programmatic interface exists, which will *always* work – not only with literals the reader understands. Not to speak about quoting hell and other gotchas.
Calling this “easiest” and “will work in general” is really a joke.
Tell me which is simpler:
Reader.read("{:foo 1 :bar " + x + "}");
or
Var keyword = RT.var("clojure.core", "keyword");
Var hashMap = RT.var("clojure.core", "hash-map");
hashMap.invoke(keyword.invoke("foo"), 1, keyword.invoke("bar"), x);
Nobody suggested using the reader in the cases where it is actually
more compact to express using stuff like the above, by the way.
Am 18.09.2011 um 10:11 schrieb Ken Wesson:
> Tell me which is simpler:
>
> Reader.read("{:foo 1 :bar " + x + "}");
String x = "13rabc";
Have fun.
> Var keyword = RT.var("clojure.core", "keyword");
> Var hashMap = RT.var("clojure.core", "hash-map");
> hashMap.invoke(keyword.invoke("foo"), 1, keyword.invoke("bar"), x);
This one is more simple. This is clojure code. And the example shows what unnecessary boilerplate is required in Java which Clojure hides from you. Everyone knowing how to call a clojure function understands this code after learning how to get a Var from a namespace and how to to invoke it.
And most importantly: it works. Also for the x above. Just like that. Nothing more involved.
For yours you have to know what x is. You have to quote it if you want to pass it as a string. You have to escape various quotes in strings. You have to know features of the reader.
> Nobody suggested using the reader in the cases where it is actually
> more compact to express using stuff like the above, by the way.
Compactness says close to nothing about simplicity.
Sincerely
Meikel
Syntactically invalid Clojure code would fail just as much in Clojure
source as it would in Java source.
If x is expected to be a string, it needs to be quoted. If it's not,
then you have a type error that will blow up at runtime, same as
usual.
>> Var keyword = RT.var("clojure.core", "keyword");
>> Var hashMap = RT.var("clojure.core", "hash-map");
>> hashMap.invoke(keyword.invoke("foo"), 1, keyword.invoke("bar"), x);
>
> This one is more simple. This is clojure code.
No, it's Java code, and butt-ugly Java code at that.
> And the example shows what unnecessary boilerplate is required in Java which Clojure hides from you. Everyone knowing how to call
> a clojure function understands this code after learning how to get a Var from a namespace and how to to invoke it.
Capability of understanding isn't the issue. Speed of understanding
is. It takes a lot longer to parse that. And it's harder to be sure it
doesn't have errors.
> For yours you have to know what x is. You have to quote it if you want to pass it as a string. You have to escape various quotes in strings. You have to know features of the reader.
Your point being? You have to know this stuff to write functioning
Clojure source code, too -- including what types you expect in what
parts of your business logic.
>> Nobody suggested using the reader in the cases where it is actually
>> more compact to express using stuff like the above, by the way.
>
> Compactness says close to nothing about simplicity.
In this case, it does.
if you find this too tedious to write and use it quite often, then there is always the possibility to hide things a little bit behind a facade.
class Clj {
static final Var seqVar = RT.var("clojure.core", "seq");
static final Var keywordVar = RT.var("clojure.core", "keyword");
static final Var hashMapVar = RT.var("clojure.core", "hash-map");
static Object seq(Object x) { return seqVar.invoke(x); }
static Object kw(String n) { return keywordVar.invoke(n); }
static Object kw(String n1, String n2) { return keywordVar.invoke(n1, n2); }
static Object hashMap(Object... args) { return hashMapVar.applyTo((clojure.lang.ISeq)seq(args)); }
}
This would make names a little bit more meaningful (less “invoke”s) for the functions you use most. And you might use your own function names. Of course this won't reach the sugar you get from Clojure itself.
theMap = Clj.hashMap(Clj.kw("a"), 1, Clj.kw("b"), 2);
foo.invoke(Clj.kw("a"), theMap);
This translates directly into:
(let [the-map (hash-map :a 1 :b 2)]
(foo :a the-map))
It should be easy to understand what's going on despite the noise. I believe Java devs are used to noise.
And FWIW: Not quoting "13rabc" by accident in the other scenario will not result in the Reader complaining but puzzled looks where this magical value came from. I personally don't particular like these moments.
My 0,02€. YMMV.
Sincerely
Meikel
Just skimming this on the phone, has no one mentioned RT.map?
You can also do it the other way around, use gen-class
and write yourself a static entry point callable from Java.
You get all the Clojure runtime init stuff done and you can define your dependencies in
the clojure file (require or use). Then you can dive into the Clojure world for as long as you need it
and return some Javaish value directly usable by your Java code.
You can write a single routine to pass clojure expressions as strings or several ones depending how your
code is structured.
Of course you need to AOT the clojure files you want to call. If you are in
a Java centric world this is not an alien concept at all.
If you need an example, look at the top of this file (gen-class) and the bottom for fns starting with -.
https://github.com/lprefontaine/Boing/blob/master/src/boing/bean.clj
The wiki describes also the Java API so you can link the Java API code versus its use.
https://github.com/lprefontaine/Boing/wiki/Using-Boing-from-java
Luc P.
--
Luc P.
================
The rabid Muppet
Since I've ended up discussing it with a few people here at The
Strange Loop, I thought it opportune to provide an example of interop
into CFML (another dynamic scripting language on the JVM), using a
little bridge library I created:
// assumes x is declared with some value...
// variables.clj contains the root Clojure "binding":
var core = variables.clj.clojure.core;
var result = variables.clj.myns.foo( core.hash_map( core.keyword( "a"
), 1, core.keyword( "bar" ), x ) );
The bridge injects a specified set of namespaces into the root binding
so they can be accessed as a nested structure with a "method missing"
style mechanism used to sugar-coat the calls to invoke(). _ is
automatically translated to - in symbols.
We use a convention that namespace._sym() returns a reference to
namespace/sym whereas namespace.sym() calls (namespace/sym) - with
namespace._("sym") for symbols that aren't valid CFML identifiers.
That allows us to do stuff like:
var data = [ 1, 2, 3, 4, 5 ]; // native CFML array
var result = core.map( core.partial( core._("*"), 3 ), data );
for (var elem in result) {
// realizes result of map as each elem value is obtained
writeOutput( elem & "<br />" );
}
Whilst not as clean as pure Clojure, it allows for great interop as
well as exposing a lot of the power of Clojure directly into our CFML
code (and, yes, for anyone who thought CFML was all <tags> there is a
full "JavaScript-like" scripting language in there too!). We run all
our CFML code on the JBoss community project, Railo.
Behind the scenes it uses clojure.lang.RT and RT.var() and .invoke() /
.deref() for everything.
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/
Railo Technologies, Inc. -- http://www.getrailo.com/
"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)
Hi,
It was recommended in the past to go through the clojure side of things. That means for me to call hash-map rather than RT.map. By creating a small helper class one can get one's own Clj.map while still going through the official API as recommended. Hence I didn't mention RT.map.