#clojure log - May 14 2009

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

3:01 cads: hey, how should I implement a multimap where multiple values may act as a key for one map entry?

3:03 oh, that's just a normal map with value duplication :D

3:10 fffej: does gen-class allow you to annotate methods with java Annotations?

3:10 (I couldn't see anything in the docs)

3:15 replaca: fffej: I don't believe so

3:16 fffej: thanks!

3:20 tWip: that would be good, for example creating ejb3 entity classes

3:22 markusgustavsson: Something better would be to not have to create EJBs at all :) a boy can dream...

3:22 replaca: yeah, Rich has decided that he doesnt want gen-class to go all the way to all the functionality of java classes and is thinking about the best approach to that

4:16 cads: in the commandline repl, is there any way to make it interpret ctrl-c as abort-eval instead of exit?

5:41 unlink: Is there any way to determine if a script is being run directly or imported?

5:49 AWizzArd: script = Clojure program?

5:50 unlink: clojure asdf.clj vs clojure -e "(use 'asdf)"

5:52 AWizzArd: maybe in the args of the main method?

5:52 you could see if you can find "-e"

5:55 unlink: What main method?

6:02 AWizzArd: Of the class

6:02 unlink: fwiw clojure parses out everything before and including the script name

6:02 I'm not sure what class you're talking about

6:03 AWizzArd: did you say "clojure asdf.clj" short for a call to "java -cp clojure.jar ..."

6:03 ?

6:06 unlink: yes, java -cp clojure.jar clojure.main asdf.clj

6:11 AWizzArd: the idea is that you don't call clojure.main

6:11 but instead your own main

6:11 and to that you can pass arguments, such as -e

6:11 then the basic idea is: if your main method was not called, then your program was not called directly

6:12 (defn -main [args] ...)

6:12 and put a (:gen-class) into your (ns)

6:14 unlink: AWizzArd: But this requires AOT compilation, right?

6:14 AWizzArd: yes

6:15 I guess

6:15 well, don't know actually

6:20 achim_p: unlink: something similar was dicussed on the google group: http://groups.google.com/group/clojure/browse_thread/thread/ca60d98fb4f7e71e/16b0ebb277daf5b9

6:26 unlink: thanks

6:27 I'm getting a 500 from google, heh.

6:56 djpowell: Is there a guide anywhere on how to call Clojure dynamically from Java? I guess that is a question that a few people will ask.

6:56 clojurebot: paste

6:56 clojurebot: lisppaste8, url

6:56 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

6:57 djpowell pasted "Calling clojure dynamically?" at http://paste.lisp.org/display/80198

7:31 rhickey: djpowell: RT.var is the best way to get a handle on vars. Then use it for all interop that you can, i.e. you can get the var for require or use and use them to load code

7:33 djpowell: http://code.google.com/p/clojure/source/browse/trunk/src/jvm/clojure/main.java?spec=svn1368&r=1368

8:09 jdz: djpowell: i have not tested, but with gen-class you can create classes that behave just like ordinary Java classes

8:35 AWizzArd: ,(ref 0)

8:35 clojurebot: #<Ref@c707c1: 0>

8:36 AWizzArd: The is the c707c1 in that output guaranteed to be unique in that jvm?

8:36 yason: clear

8:37 AWizzArd: if it is for example the address in ram then it could not change, but if it is some hash code that gets calculated...

8:38 ,(let [r (ref 0)] [r (format "%x" (System/identityHashCode r))])

8:38 clojurebot: [#<Ref@13d422d: 0> "13d422d"]

8:48 bstephenson: I run (ref 0) twice in a row in my REPL and get back two different Ref@ numbers

8:48 dnolen: you created two refs

8:48 bstephenson: ahh

8:49 dnolen: ,(ref 0)

8:49 clojurebot: #<Ref@1fcbac1: 0>

8:49 dnolen: ,(ref 0)

8:49 clojurebot: #<Ref@b0ede6: 0>

8:50 bstephenson: (def x (ref 0))

8:50 ,(def x (ref 0))

8:50 clojurebot: DENIED

8:50 dnolen: yeah you can't def clojurebot.

8:50 AWizzArd: ,(let [x (ref 0)] (println x))

8:50 bstephenson: well, if that was allowed by clojurebot, when you see the ref for x, it is the same every time

8:51 dnolen: ,(let [refA (ref 0) refB (ref 0)] (= refA ref B))

8:51 clojurebot: java.lang.Exception: Unable to resolve symbol: B in this context

8:51 dnolen: ,(let [refA (ref 0) refB (ref 0)] [(= refA refB) (= refA refA)])

8:51 clojurebot: [false true]

8:52 AWizzArd: The thing is: is the hash code of that ref unique for the running session?

8:53 well, probably not for the running session

8:54 but I hope at least for any two refs that currently still live that hash code will be pairwise different

8:54 jdz: if that is a hash code then why should it be different?

8:54 i mean, necessarily different?

8:55 rhickey: AWizzArd: no guarantee that hash codes will be different, by definition they are not identities

8:56 AWizzArd: jdz: yes, that was what I said about 1,5 minutes before you entered ;)

8:57 So, (let [a (ref 0), b (ref 1)] (= (System/identityHashCode a) (System/identityHashCode b))) ==> true is possible.

8:58 rhickey: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#identityHashCode(java.lang.Object)

8:58 makes few promises

9:00 AWizzArd: right

9:19 yason: uh, I'm failing to find a simple membership test function for sequences, such as "x in seq" (Python), "indexOf" (JS), etc.

9:19 dnolen: ,(.indexOf 'a ['a 'b 'c])

9:19 clojurebot: java.lang.IllegalArgumentException: No matching method found: indexOf for class clojure.lang.Symbol

9:20 dnolen: oops

9:20 ,(.indexOf ['a 'b 'c] 'a)

9:20 clojurebot: 0

9:20 dnolen: ,(.indexOf 'c ['a 'b 'c])

9:20 clojurebot: java.lang.IllegalArgumentException: No matching method found: indexOf for class clojure.lang.Symbol

9:20 dnolen: ,(.indexOf ['a 'b 'c] 'c)

9:20 clojurebot: 2

9:21 dnolen: ,(some #{'y} ['x 'y 'z])

9:21 clojurebot: y

9:21 yason: ok so java it is -- is that efficient?

9:21 dnolen: if you just want to test membership

9:21 yes.

9:21 yason: plain membership test is fine, akin to "x in seq" in Python

9:22 the set thing with (some) is ugly though :)

9:22 dnolen: then use some.

9:22 yason: I'm surprised there isn't a built-in like (member?) or something

9:23 dnolen: heh, it's idiomatic. and more general

9:23 ,(some #{'a 'b} ['x 'y 'b])

9:23 clojurebot: b

9:24 yason: Yeah but it's ugly, you have to know and recognize the pattern.

9:24 By the way .indexOf doesn't work for lazy sequences

9:24 dnolen: just as you have to recognize list comprehension for Python. to each his own ;)

9:25 yason: dnolen: well, the latter works for lazy seqs too so I consider it a better fit

9:25 I've used the (some #{...} ) before but it always felt like a hack :)

9:26 but hey, thanks anyway for validation

9:28 dnolen: no prob. you could always add your own fn, (defn in? [coll x] (some #{x} coll))

9:35 jdz_: ,(contains? [1 2 3] 3)

9:35 clojurebot: false

9:35 jdz_: ,(contains? '(a b c) 'c)

9:35 clojurebot: false

9:35 durka42: man, dev.java.net is really slow

9:35 dnolen: (,doc contains)

9:35 ,(doc contains)

9:35 clojurebot: java.lang.Exception: Unable to resolve var: contains in this context

9:36 dnolen: ,(doc contains?)

9:36 clojurebot: "([coll key]); Returns true if key is present in the given collection, otherwise returns false. Note that for numerically indexed collections like vectors and Java arrays, this tests if the numeric key is within the range of indexes. 'contains?' operates constant or logarithmic time; it will not perform a linear search for a value. See also 'some'."

9:36 jdz_: oh, that's not for sequences

9:36 durka42: and not for values

9:36 jdz_: what do you mean not for values?

9:38 ,(some (partial = 'c) '(a b c))

9:38 clojurebot: true

9:41 Chousuke: ,(some #{'c} '(a b c)) ; this is a fun trick

9:41 clojurebot: c

9:41 jdz_: it kinda feels wrong to me when testing for only one value...

9:41 Chousuke: I guess so.

9:42 but it's a clojure idiom.

10:02 durka42: clojurebot: paste?

10:02 clojurebot: lisppaste8, url

10:02 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

10:06 durka42: trying to using Chouser's JNA to prove Charles Nutter wrong:

10:06 lisppaste8: durka42 pasted "vim" at http://paste.lisp.org/display/80211

10:27 drewr: Is there an idiomatic way to capture exceptions from an Executor?

10:33 jdz: What's Executor and how its exceptions are different from any other exceptions?

10:37 drewr: jdz: It's an abstraction for spawning command executing in threads.

10:38 Normally I would use an agent and its facilities for tracking down exceptions, but in this case I have an await in the code that gets spawned.

10:42 s/executing/execution/ ^^~2

10:43 I don't know the Java ways of dealing with that, but I'

10:43 m assuming it's the same in clojure.

10:45 jdz: i must admit i don't see what's the problem without any code

10:46 tWip: why not have the Runnable implementation store it in a field and access it?

10:47 drewr: tWip: Yes, I considered that.

10:48 Also, JCIP mentions UncaughtExceptionHandler.

10:48 tWip: why do you need to "capture" exceptions? why can't the runnables just catch them and do the appropriate thing

10:49 or have them notify some other code about them

10:51 drewr: tWip: Sounds good. Just wanted to make sure there wasn't something more pre-fab.

10:51 tWip: it's of course a design decision on where you want to react to problems

10:53 drewr: The convenience of agent-errors threw me off. :-)

11:11 liwp: does anyone here have any idea how to evaluate a form in slime in the current namespace rather than in 'user?

11:12 stuartsierra: It should happen automatically if your source file has a (ns...) at the top.

11:12 liwp: My problem is that when I send a form to slime with C-x C-e, it gets evaluated in 'user rather than in the namespace of the source file. And therefore my other code keeps using the old definition according to the namespace rather than the new definition.

11:12 stuartsierra: I've got the (ns ...) in the source file

11:12 dnolen: liwp: you need to evaluate the ns statement first.

11:12 liwp: I've change the namespace in the repl with (in-ns ...)

11:13 dnolen: I've compile the whole buffer with C-c C-k before...

11:13 stuartsierra: Try C-M-X instead of C-x C-e.

11:13 C-M-x I mean

11:14 liwp: stuartsierra: Ok, I'll give it a try when I get home

11:14 dnolen: not sure C-c C-k keeps things in sync.

11:15 when I'm in the REPL zone, I usually select all the working code and do C-c C-r to evaluate the region.

11:15 liwp: I'll just have to figure out the correct workflow for myself...

11:15 dnolen: then I use C-x C-e and C-M-x

11:15 liwp: dnolen: and that works fine with namespaces?

11:16 dnolen: it does for me, yes.

11:16 swank-clojure matches the buffer to a ns if you C-x C-e a name space definition.

11:16 liwp: dnolen: I haven't C-x C-e'd the namespace so maybe that's the problem

11:17 I guess compiling the file isn't enough for swank-clojure

11:17 thanks guys

11:17 markusgustavsson: C-c C-k followed by C-x C-e on single forms works fine for me

11:17 liwp: markusgustavsson: even with namespaces?

11:17 markusgustavsson: yeah

11:17 At least I think so.. can check to make sure :)

11:17 liwp: markusgustavsson: is your repl in 'user or in the other namespace?

11:18 markusgustavsson: it's in user, does not affect C-x C-e

11:19 dnolen: ok, I can confirm that markus is correct.

11:19 liwp: markusgustavsson: mine's not in 'user so I thought that might have something to do with it not working, but seems a bit weird

11:19 dnolen: liwp I take that back.

11:20 C-c C-k doesn't synchronize the file to an ns in the proper way.

11:20 liwp: dnolen: so it's broken for you too?

11:20 dnolen: yup

11:20 that's why I don't bother with it when doing stuff in the REPL.

11:20 only when sanity checking a file.

11:20 liwp: I haven't updated my slime/swank-clojure for a while so it might be that it's been fixed

11:21 markusgustavsson: liwp: just tried C-c C-k followed by C-x C-e on an additional defn and the new function gets added to the correct namespace - the one specified in my buffer - regardless of the ns in the repl.

11:21 But I don't have the latest svn versions of everything

11:21 liwp: dnolen: makes sense - I guess I need to figure out another work flow for myself, which is fine, C-c C-k just seemed like a simple way to load the file to clojure before making changes

11:22 markusgustavsson: good for you ;-)

11:22 stuartsierra: I use slime-eval-buffer

11:22 dnolen: ok, I just updated slime.

11:22 seems to work when everything is up to date.

11:22 liwp: stuartsierra: what't that bound to by default?

11:23 stuartsierra: nothing

11:23 liwp: dnolen: ahh, I'll need to update then

11:23 stuartsierra: I thought so, that's why I'm not using it. I might as well replace C-c C-k with it. Do you have it bound>

11:23 stuartsierra: no

11:25 liwp: thanks everyone

11:31 stuartsierra: Re the JSON "NULL" thing from yesterday -- even Firefox won't parse it.

11:32 danlarkin: where do they think they get off sending "NULL"... the nerve... :-o

11:32 stuartsierra: :)

11:38 danlarkin: that was kindof serious though, maybe I shouldn't patch to allow NULL

11:42 stuartsierra: I'm disinclined to do support it.

12:19 Anyone else having trouble connecting to Google sites?

12:20 unlink: Neither of the methods described in http://groups.google.com/group/clojure/browse_thread/thread/ca60d98fb4f7e71e/16b0ebb277daf5b9 work for detecting whether a script has been invoked directly or (use)'d.

12:20 That is, neither *ns* nor *command-line-args* depend on this.

12:21 danlarkin: stuartsierra: I am not, but I've seen a few people on the twitter and some remote coworkers are

12:22 stuartsierra: unlink: I think the recommended procedure now is to define a main function and invoke it.

12:22 danlarkin: thanks

12:22 unlink: stuartsierra: Invoke it where?

12:23 stuartsierra: On the command line.

12:23 unlink: stuartsierra: You mean with AOT compilation?

12:24 stuartsierra: unlink: not necessarily, although AOT permits you to run "java -cp ... your.class.name"

12:24 unlink: stuartsierra: Right, but I don't see how you could invoke a clojure method from the command line without AOT.

12:25 (or something silly like -e (use 'com.example.test) (-main))

12:25 stuartsierra: That's basically it. You can use the "-i" option to load the file, then "-e" to run it.

12:26 unlink: That seems like it's screaming for a language feature.

12:27 stuartsierra: Stephen G. suggested adding metadata to the namespace to identify a "main" function. I suggested always using "-main".

12:27 unlink: Alternatively a *name* binding could be used (borrowing from Python, ruby et al)

12:29 I would be fine with either a special "main" name or annotation or a binding for the script being invoked.

12:47 stuartsierra: unlink: another option is to have a separate "driver" .clj script that just calls your main function.

12:47 unlink: right

12:48 Python and Ruby users will expect the feature I'm looking for, and I think it's simply a good idea anyhow (for rapid development and for single-module projects).

12:48 stuartsierra: yes

12:53 ieure: Agreed, I was just looking for something like Python's if __name__ == '__main__' trick.

12:54 replaca: ieure: this comes up all the time and we need to come up with a nice way to do that. It shouldn't be hard to come up with a way that's nicer than python's!

12:55 technomancy: replaca: agreed; that trick is clunky as the dickens.

12:55 unlink: "idiom" :-)

12:55 replaca: technomancy: but I use it all the time and I feel the lack of it in Clojure

12:56 stuartsierra: Short answer: use AOT-compilation for now, suggest new feature.

12:56 replaca: that's right

12:57 technomancy: CLI launching methods have always been a weak point of clojure.

12:57 replaca: stuartsierra: did you see my comment yesterday about json.write vs. clojure-json performance?

12:57 unlink: Which brings up the related point that AOT compilation could be simplified.

12:57 stuartsierra: replaca: no

12:58 replaca: I ran a benchmark (cause I was testing pretty print dispatch) and simple json output was ~20x faster in clojure-json than in json.write.

12:58 I was testing with my API index from the contrib autodoc

12:58 stuartsierra: Which contrib SVN did you have?

12:59 replaca: within the last few, don't know exactly

12:59 stuartsierra: ok

12:59 replaca: I'm always up to date within a few days

12:59 dunno if there's something unusual about my case.

13:00 stuartsierra: I'll try it

13:00 replaca: it's almost 300K at the end

13:02 stuartsierra: yeah, you can grab some JSON from http://clojure-contrib.googlecode.com/svn/wiki/ApiDocIndex.json

13:02 stuartsierra: I've got tons.

13:02 replaca: stuartsierra: cool

13:15 stuartsierra: Hmm. c.c.json.read appears to be just slightly faster.

13:20 Testing c.c.json.write now

13:23 c.c.json.write is much slower, around 20:1.

13:24 It's probably the multimethods & derive.

13:24 danlarkin: combine forces!

13:24 stuartsierra: ok

13:24 danlarkin: stuartsierra: yeah I tested clojure-json's encoder with multimethods instead of cond... slowed it down so I took them out

13:29 stuartsierra: Sigh... elegance is always the first to fall.

13:31 hlship: If I have a symbol, say 'foo, how do I get the namespace for it? Context: want to write utilities to load resources from the classpath, relative to the symbol's namespace.

13:32 danlarkin: (doc namespace)

13:32 clojurebot: "([x]); Returns the namespace String of a symbol or keyword, or nil if not present."

13:33 hlship: user=> (foo 1)

13:33 2

13:33 user=> (namespace 'foo)

13:33 nil

13:33 So foo exists, but (namespace 'foo) returns nil, that's why I'm confused.

13:34 And (ns-resolve) seems to require the namespace in the first place.

13:35 jkantz: what's the fastest way to do a > comparison on integers?

13:35 I don't see any unchecked options for that

13:35 danlarkin: hlship: you're passing 'foo to the namespace function

13:35 hlship: 'foo has no namespace

13:35 hlship: 'user/foo does, however

13:36 jkantz: unchecked- functions are no faster than the checked variants

13:36 > will be suitably fast

13:36 no faster, that is, within a margin of error

13:37 lisppaste8: url

13:37 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

13:37 stuartsierra: Huh. Eliminating multimethods didn't make that much difference.

13:37 hlship: I want to be able to say (find-classpath-resource 'foo "style.css") and find /my/namespace/for/foo/style.css on the classpath

13:37 lisppaste8: danlarkin pasted "resolve*" at http://paste.lisp.org/display/80228

13:38 danlarkin: hlship: does resolve* help?

13:38 hlship: let me see ...

13:39 danlarkin: oh, no, resolve* is for resolving functions, not resources

13:40 jkantz: danlarkin, is that because the jit will eventually make the needed optimizations?

13:40 hlship: user=> (resolve 'foo)

13:40 #'user/foo

13:40 user=> (namespace (resolve 'foo))

13:40 java.lang.ClassCastException: clojure.lang.Var (NO_SOURCE_FILE:0)

13:40 user=> (ns-resolve *ns* (resolve 'foo))

13:40 java.lang.ClassCastException: clojure.lang.Var (NO_SOURCE_FILE:0)

13:40 user=> (namespace (resolve 'foo))

13:40 java.lang.ClassCastException: clojure.lang.Var (NO_SOURCE_FILE:0)

13:40 user=>

13:41 danlarkin: jkantz: yes. Also you can cast your variables with (int ...)

13:41 inside function-boundaries they'll stay primitive ints

13:41 hlship: Worse, in my tests (running from La Clojure in REPL), *ns* appears to be "user" regardless, which is odd

13:41 danlarkin: hlship: resolve returns a var, not a symbol

13:42 stuartsierra: Reflection makes a big difference, though.

13:43 hlship: Right, that's why I'm struggling.

13:43 In Java, I could just getClass().getClassLoader().getResource()

13:44 danlarkin: hlship: how about (:ns (meta (resolve 'foo)))

13:45 hlship: (one minute ...)

13:53 danlarkin: stuartsierra: how much faster is it with the hints?

13:54 stuartsierra: Reading is slightly faster, now I'm getting 2x faster than clojure-json. Writing is MUCH faster, but still about 2x slower than clojure-json.

13:54 Still experimenting.

13:55 danlarkin: I spent time optimizing encoding in clojure-json, but not much optimizing decoding, I guess it shows

13:56 stuartsierra: ok

13:56 It might be the difference between building a String and calling (print...)

14:03 hlship: (:ns (meta (resolve 'foo))) thanks! Should help.

14:04 replaca: stuartsierra, danlarkin: looks like the competitive free market is working!

14:04 stuartsierra: :)

14:04 hlship: now if there was only the concept of "this" for functions or namespaces

14:05 danlarkin: hlship: *ns*

14:05 replaca: stuartsierra: I did pretty printing versions of c.c.json.write and c.c.prxml in c.c.pprint.examples

14:05 kotarak: hlship: (fn this [] ....)

14:05 hlship: That was my first try, and (perhaps due to test-is), was coming up as "user"

14:05 ieure: What kind of Clojure benchmarking tools are there?

14:06 replaca: ieure: (time), -hprof, stuart put some profiling into contrib

14:07 stuartsierra: experimental...

14:07 replaca: ieure: those are the ones I think of off the top of mmy head

14:07 lisppaste8: hlship pasted "find-classpath-resource" at http://paste.lisp.org/display/80231

14:08 hlship: So (:ns (resolve 'foo)) works in REPL

14:09 ah ... so my problem, oops

14:09 kotarak: hlship: you have to replace - with _ also. Not only . with /.

14:10 ieure: Hmm. So I'm not sure if I'm doing something wrong, but this SQL query I'm running is OOMing the JVM. Seems like (with-query-results) buffers the whole (large) resultset.

14:11 I'm doing (with-query-results rs ["SELECT gobs_of_rows;"] (map (fn [row] ...)))

14:12 hiredman: at the repl?

14:12 ieure: Yes.

14:12 lisppaste8: hlship annotated #80231 "final version w/ test" at http://paste.lisp.org/display/80231#1

14:13 hlship: thanks for the help

14:13 hiredman: ieure: the repl is try to realize the map to print out the result

14:13 hlship: using the (meta) was a cool trick

14:13 ieure: hiredman, Hm, okay.

14:14 kotarak: ieure: maybe you can try (doseq [row (with----)] (println row)).

14:14 This should not hold on the head of the sequence

14:15 hlship: anybody doing web apps w/ clojure currently?

14:15 technomancy: hiredman: that needs to be a clojurebot faq like how he says map is *LAZY*

14:15 ,repl

14:15 clojurebot: java.lang.Exception: Unable to resolve symbol: repl in this context

14:15 technomancy: clojurebot: repl?

14:15 clojurebot: whose job is<reply>that is triddells job

14:15 dnolen: hlship: I've been using compojure to rapid prototype front ends, as well as playing around with GAE.

14:15 hiredman: ,clojure.main/repl

14:15 clojurebot: #<main$repl__5796 clojure.main$repl__5796@1342f5b>

14:16 kotarak: clojurebot: the repl is also holding onto the head of sequences when printing them.

14:16 clojurebot: You don't have to tell me twice.

14:16 kotarak: clojurebot: repl

14:16 clojurebot: the world <reply>what the world needs is more higher order functions

14:16 kotarak: clojurebot: the repl

14:16 clojurebot: the repl is holding onto the head of sequences when printing them.

14:16 hiredman: clojurebot: whose job is it to make you talk to twitter correctly

14:16 clojurebot: Alles klar

14:16 hiredman: er

14:16 whoops

14:16 hlship: I'm taking a breather from Tapestry and trying to build a Clojure web framework using Tapestry-style templates

14:16 but it will be action oriented, not component oriented

14:17 nurey_mac: hlship: looks nice, please no struts alike if you can :-)

14:17 hlship: hoping to make it highly parallel as well

14:17 hiredman: clojurebot: literal whose job

14:17 clojurebot: whose job is it to make you talk to twitter correctly

14:17 hiredman: clojurebot: forget whose job

14:17 clojurebot: I forgot whose job

14:17 hlship: nope; maybe more like Stripes perhaps

14:17 but with T5 templates

14:17 coming together nicely

14:17 hiredman: ~whose job is <reply>that is #someone's job

14:17 clojurebot: Roger.

14:18 hiredman: clojurebot: whose job is it to make you talk to twitter correctly?

14:18 clojurebot: Ik begrijp

14:18 hiredman: bah

14:18 hlship: up on GitHub: http://wiki.github.com/hlship/cascade

14:18 hiredman: clojurebot: whose job would it be to make you talk to twitter correctly?

14:18 clojurebot: that is kotarak's job

14:19 hlship: #tapestry

14:19 (oops)

14:20 nurey_mac: hlship: it cascade was out and 2 years mature, I would have tried to recommend it. I'm not having fun with rails,grails jsp style templates :-(

14:22 dnolen: nurey_mac: have you looked Enlive? I have a distaste for mixing code and markup. Enlive solves that particularly problem nicely.

14:22 technomancy: enlive is awesome

14:22 * technomancy hopes to never go back to interpolation-style templating

14:22 nurey_mac: thanks guys, I'll read about it

14:23 stuartsierra: :-Dc.c.json.write is now a little faster than clojure-json

14:23 You have to call it a few thousand times to see the effects, though.

14:24 danlarkin: stuartsierra: sweet, now just clean up that ugly api :)

14:25 replaca: stuartsierra: did you get that big cond out of there? A table would speed things up

14:25 stuartsierra: No more conds.

14:25 technomancy: stuartsierra: thoughts on using keywords as map keys instead of strings?

14:25 replaca: stuartsierra: yay!

14:25 stuartsierra: technomancy: Use c.c.walk/keywordize-keys

14:26 replaca: ok, one small cond, but mostly multimethods

14:35 technomancy: ok, you talked me into it. Bind *json-keyword-keys* to true.

14:36 technomancy: stuartsierra: nice! =)

14:36 * danlarkin thinks *json-keyword-keys* should have a root binding of true :)

14:37 technomancy: stuartsierra: it's weird since JS treats object keys as strings, but when you use dot notation it suggests keywords/symbols

14:37 clojurebot: http://clojure.org/data_structures#toc8

14:37 stuartsierra: I'm reluctant to do that, b/c there's no way to verify that a string makes a valid keyword.

14:37 technomancy: stuartsierra: oh! I have a patch for that

14:37 stuartsierra: What if the string is something like "foo/bar"? Do you get a namespaced keyword?

14:38 technomancy: clojurebot: issue #13

14:38 clojurebot: Titim gan �ir� ort.

14:38 technomancy: hiredman: he should get hooked up to google code. =)

14:38 http://code.google.com/p/clojure/issues/detail?id=13&colspec=ID%20Type%20Status%20Priority%20Reporter%20Owner%20Summary

14:38 hiredman: is there any way to get templated clojurebot replies?

14:39 something like clojurebot: issue (\d) is<reply>http://code.google.com/p/clojure/issues/detail?id=\1

14:39 danlarkin: I don't like this issue :) I like being able to create symbols/keywords that aren't readable

14:40 technomancy: danlarkin: sure; just use (. clojure.lang.Symbol (intern ns name))

14:40 but you need to know what you're doing

14:40 danlarkin: technomancy: oh yes, that's just as convenient as 'foo :)

14:41 stuartsierra: http://clojure.org/todo mentions "arbitrary symbols in | |" but Rich has wavered on this.

14:46 replaca: stuartsierra: I sometimes wonder if multimethods are just a fancy syntax for cond :-)

14:48 cemerick: replaca: *everything* is just a fancy syntax for cond ;-)

14:50 twism: agrees with danlarkin that *json-keyword-keys* default should be true

14:51 but stu brings up a good point about "foo/bar" json keys

14:56 stuartsierra: Also, I don't want to change the API if I can help it.

15:00 technomancy: well contrib isn't 1.0 yet... so if you're going to change the API, now's the time. =)

15:01 stuartsierra: yeah, I'll think about it.

15:01 danlarkin: at least make it consistent :)

15:01 stuartsierra: consistent?

15:02 danlarkin: well there's read-json-string to read and then json-str to write

15:03 stuartsierra: That follows read-string and str in Clojure.

15:03 danlarkin: it's gross :-o

15:03 stuartsierra: yes

15:08 * stuartsierra is working

15:12 stuartsierra: ok, now read-json takes a string too.

15:13 That leaves read-json, print-json, and json-str.

15:13 danlarkin: read-json and write-json? pretty please

15:13 mmm

15:14 stuartsierra: print-, not write-, because it prints to *out*

15:14 * stuartsierra feels henpecked.

15:15 danlarkin: :)

15:18 stuartsierra: So I guess it should be called c.c.json.print, but whatever.

15:21 metasyntax|work: If I do (ns foo.bar.Test (:gen-class)) and then (compile 'foo.bar.Test) I get a java.io.IOException: No such file or directory (Test.clj:1)

15:22 Running `java -cp ... clojure.main` from a directory such that it has children foo/bar/Test.clj beneath it.

15:23 * stuartsierra tries to remember what he was working on at the start of the day.

15:24 hoeck: metasyntax|work: bind *compile-path* to a dir where the compiled classes should go

15:25 metasyntax|work: like (binding [*compile-path* "."] (compile 'foo.bar.Test))

15:25 metasyntax|work: where "." must be on the classpath

15:26 metasyntax|work: Ah, I see. I think the IOException was because *compile-path* didn't exist.

15:26 So *compile-path* must both exist and be in the CLASSPATH for compile to work it seems.

15:27 hoeck: metasyntax|work: it's bound to "classes", but the "./classes" dir is probably not in your classpath

15:27 metasyntax|work: so it compiles the namespace but fails to load it after compiling

15:27 metasyntax|work: hoeck: That was a second-step problem, first I had to make the "classes" directory.

15:27 hoeck: But you're right, thank you.

15:28 hoeck: metasyntax|work: np :)

15:43 durka42: cool, they're getting ready to ship the book :)

15:53 twism: how would you set *json-keyword-keys*

15:53 ?

15:53 stuartsierra: binding or alter-var-root

15:53 twism: without (bind [*json-keyword-keys* ....

15:53 ah

15:53 what happened to set!

15:54 stuartsierra: set! won't change root bindings

15:55 twism: oh i just couldnt find set! in the api

15:55 on the website

15:55 ,(doc set!)

15:55 clojurebot: java.lang.Exception: Unable to resolve var: set! in this context

15:55 stuartsierra: http://clojure.org/java_interop#set

15:56 twism: thats my bad...

15:56 set! is java interop

15:56 stuartsierra: no prob

15:56 Not exactly, it's a special form. It works on thread-bound vars.

15:59 twism: *meant <twism> without (binding [*json-keyword-keys* ....

15:59 just correcting

16:02 metasyntax|work: With gen-class, how do I specify a static method?

16:03 I tried putting #^{:static true} into the metadata of the function but Java still claims it's non-static.

16:04 Something like (defn -test #^{:static true} ([x y] (+ x y))).

16:04 mattrepl: metasyntax|work: are you putting it in the function definition or the function signature

16:04 it needs to go in the signature

16:06 metasyntax|work: mattrepl: where do I put it there? in the parameter list?

16:07 mattrepl: at the the start, the #^ will attach the metadata to the next object, which will be the signature of the function you want to be static

16:07 metasyntax|work: mattrepl: OK, I see. Thanks!

16:08 mattrepl: =)

16:09 twism: stuartsierra: sorry about my ignorance... but what am i doing wrong here

16:09 (alter-var-root clojure.contrib.json.read/*json-keyword-keys* (fn [] true))

16:09 metasyntax|work: First time using Clojure here, it's very cool. The closer I can get to Scheme while still doing work the better.

16:14 stuhood: twism: the function needs to take the current state as an argument

16:15 twism: try: (alter-var-root clojure.contrib.json.read/*json-keyword-keys* (fn [_] true))

16:15 triddell: \

16:17 stuartsierra: yes

16:17 (alter-var-root #^clojure.contrib.json.read/*json-keyword-keys* (fn [_] true))

16:18 Or wrap read-json in your own function with a binding.

16:19 twism: thanks

16:24 kotarak: Did anyone encounter trouble with the latest clojure revisions? /Users/mb/Documents/Projects/Clojure/vimclojure/build.xml:66: java.lang.NoClassDefFoundError: clojure/core$this__4984__auto____4601 (util.clj:23)

16:24 Line 23 is the ns clause of the file.

16:25 twism: loves when all the tests pass

16:26 thanks stuhood and stuartsierra

16:29 Chousuke: kotarak: you sure you have everything properly compiled? :)

16:30 kotarak: Chousuke: I thought so, but it seems the jar is incomplete...

16:31 which is funny because the ant target uses <fileset dir="${classes.dir}" includes="**/*"/>

16:33 Hmm.. I think, I'm annoyed by the recent changes to the ns makro. :(

16:36 unlink: kotarak: what changes

16:36 kotarak: The ns makro now creates an anonymous function, which blows up for me for some reason.

16:41 Obviously the ns makro generates .class files which somehow vanish on my system. At least the code references this__ classes like the above, which do not exist.

16:42 Chousuke: kotarak: 1367 introduces the class you're missing.

16:42 kotarak: I'm using 1368 and the class names change...

16:43 Chousuke: I mean, it introduces the change that breaks clojure for you

16:43 kotarak: They come from the anonymous this# function in the ns makro. Which obviously generates an anonymous function per namespace.

16:43 Chousuke: yes. The change breaks things.

16:44 Chousuke: since it introduces an autogensym "this#" inside an anonymous function, which is what you seem to be missing.

16:44 might be a clojure bug :p

16:44 kotarak: I'm not really missing it: there are several of this core$this... functions. But not those needed, it seems.

16:44 Chousuke: yeah, so maybe the compiler is getting confused by it :/

16:48 mattrepl: do a find for the ones it's looking for, maybe they're getting written somewhere else?

16:51 kotarak: Ok. I found the class, and I know why it's not included in the jar.

16:53 Rich really makes it hard to split contrib into smaller jars. :(

16:57 stuartsierra: Didn't someone successfully split contrib into small jars using maven?

16:58 kotarak: I did using Ivy. But the anonymous this# doesn't allow to assign them to the correct jar.

16:58 stuartsierra: ah

16:59 kotarak: I have to make a general ns-jar which contains all this_bla .classes. :(

17:00 Proxy is although such an annoyance. :(

17:00 s/although/also/

17:07 unlink: Is there any reason the type annotation reader macro #^ doesn't understand primitive types?

17:08 stuartsierra: unlink: dunno, but you can use the int/byte/short/... functions to the same effect.

17:08 unlink: right

17:08 kotarak: I think for primitives the way is (let [x (int i)] ...)

17:08 unlink: It just seems silly to have 2 parallel idioms

17:08 stuhood: agreed.

17:10 kotarak: o.O clojure.core/types$...? Oh dear.... -.-

17:15 Chousuke: unlink: #^Foo x is a type hint; (foo x) is a coercion

17:16 unlink: Chousuke: What semantic difference are you trying to express?

17:16 AFAIK to the application programmer they are the same except they operate on different types.

17:16 Chousuke: (int x) makes x a native int; normally it's of the class Integer (you'd type it as #^Integer)

17:17 unlink: and therefore...?

17:17 Chousuke: if you just did #^int x, it'd be wrong, since x would actually be Integer

17:18 without the (int x) coercion that is

17:18 unlink: Which is counter-intuitive. I'm suggesting that #^int be changed to mean something like (let [i (int i)] ...)

17:19 Chousuke: er, but that's what it is already.

17:19 #^int doesn't exist :p

17:20 I suppose there's some mismatch with the array types having type hints

17:20 unlink: #^int means "cast me to the type int as needed"

17:20 danlarkin: unlink: but that's not what #^Integer means

17:21 unlink: Except here "the type int" has to be a user-defined type.

17:21 Chousuke: that would conflict with the meaning of #^Foo right now.

17:21 danlarkin: type hints aren't coercive

17:21 Chousuke: that's the main difference

17:22 type hints are just metadata; (int ..) etc are actual operations.

17:22 unlink: yes

17:23 Chousuke: if you want type casts for classes, use cast :)

17:26 danlarkin: cast doesn't do that

17:52 ieure: Hm. So kotarak suggested that I try to use doseq to solve my SQL OOM issue, but I'm having problems with that. (with-query-results) doesn't return the result sequence, and I can't seem to return it from the body.

17:53 And doing: (with-query-results rs [query] (doseq rs (fn [row] ...))) fails with: java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: Symbol

17:53 Ideas?

17:54 hiredman: ieure: have you read the doc string for doseq?

17:54 ,(doc doseq)

17:54 clojurebot: "([seq-exprs & body]); Repeatedly executes body (presumably for side-effects) with bindings and filtering as provided by \"for\". Does not retain the head of the sequence. Returns nil."

17:54 ieure: hiredman, I read the API documentation, which is much the same.

17:55 hiredman: with bindings and filtering as provided by \"for\"

17:55 anyway

17:55 dnolen: so why does this work again?

17:55 ,((ref +) 3 4)

17:55 clojurebot: 7

17:55 hiredman: you are using it wrong

17:55 dnolen: refs dispatch invoke to their values, I believe

17:56 dnolen: why them an not atoms?

17:56 hiredman: ,((ref #{1 2 3}) 1)

17:56 clojurebot: 1

17:56 dnolen: and not atoms

17:56 hiredman: ,((atom #{1}) 1)

17:56 clojurebot: java.lang.ClassCastException: clojure.lang.Atom cannot be cast to clojure.lang.IFn

17:56 hiredman: dunnp

17:56 ieure: hiredman, I'm sure I'm doing lots wrong, I really am not comfortable with Clojure yet.

17:56 hiredman: possibly it got overlooked

17:57 ieure: (doseq [i (some collection/seq here)] do stuff to i here)

17:57 ,(doseq [i (range 10)] (print i))

17:57 ugh

17:57 ,well?

17:57 clojurebot: java.lang.Exception: Unable to resolve symbol: well? in this context

17:58 hiredman: ugh

17:58 I guess I should fix that

18:02 ,(doseq [i (range 10)] (print i))

18:02 clojurebot: 0123456789

18:04 ieure: hiredman, I think I have it. It's running now, I'll see if it OOMs.

18:04 hiredman, Thanks for the pointer.

18:04 hiredman: sure

18:04 ieure: Still OOMs.

18:05 hiredman: can you pastebin the code?

18:05 lisppaste8: url?

18:05 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

18:05 ieure pasted "OOMing" at http://paste.lisp.org/display/80247

18:06 hiredman: how large are reach of the rows in the database?

18:07 ieure: 16 cols per row, 155k rows.

18:07 hiredman: but, like, how much data is in each row?

18:09 ieure: Could be anywhere from 100 bytes to 1kb or so.

18:09 hiredman: hmmm

18:10 I would remove the tokyo stuff, and just (doseg [row rs] (prn row))

18:11 to see if it is the result set

18:17 lisppaste8: ieure annotated #80247 "Still OOMing" at http://paste.lisp.org/display/80247#1

18:21 ieure: hiredman, Any thoughts?

18:21 Seems like the whole resultset is buffered, since I get "Running," a wait, and an OOM. I never see a single row printed.

18:23 hiredman: hmmm

18:23 ieure: sounds like it's time to up the memory limit on the jvm

18:26 ieure: hiredman, Crazy talk. 155k rows is my test data; I need this to handle 25m rows. Jacking up the memory limit isn't a solution.

18:27 I don't understand why rows can't be fetched individually and processed. This is the normal way one processes large datasets.

18:28 Chousuke: Sounds like you'll have to use the resultset directly, without wrapping it in a seq

18:29 dnolen: isn't it possible to use loop recur here?

18:29 and dump the stuff you're not using?

18:29 process element, (rest coll)

18:29 ieure: Chousuke, Not sure how to do that. I was trying (map), but it OOM'd, too.

18:30 Chousuke: if it's OOMing before you get anything printed, the problem might be with how with-query-result makes the seq

18:30 ieure: Chousuke, That seems to be the case, I'm retrying with just a (prn "Done") as the body. Looks like it's going to die, too.

18:31 hiredman: ~def with-query-result

18:31 ouch

18:31 Chousuke: results

18:31 ~def with-query-results

18:31 ~def with-query-results*

18:31 ieure: Looks like it's using (resultset-seq)

18:32 http://code.google.com/p/clojure-contrib/source/browse/trunk/src/clojure/contrib/sql/internal.clj#172

18:33 Chousuke: ~def resultset-seq

18:33 hiredman: whoops

18:33 damn

18:34 Chousuke: looks like it ought to be fine.

18:36 ieure: Yet it isn't.

18:37 hiredman: ~def resultset-seq

18:38 ieure: I'm using Clojure 1.0.0 and -contrib from SVN as of 05/04.

18:38 Cark: good evening

18:38 Chousuke: actually I think the "rs" will hold to the head of the seq, but it shouldn't OOM before you've done work with it...

18:42 instead of using (doseq [comment rs]), try using (if-let [comm (first rs)] (do (prn (genkey comm)) (recur (rest rs))))

18:43 the with-query-result body is wrapped in a lambda so it's a recur target

18:44 I'm not sure if the rs reference to the head is the real problem but my guess is that using recur should avoid that problem at least

18:46 ieure: Chousuke, But the code OOMs even with just: (sql/with-connection *db* (sql/with-query-results rs [query] (prn "Done.")))

18:46 Cark: a quick question : i need to parse text files, regexes won't do, should i use joshua choi's fnparse or kotka's parser ?

18:47 speed is not an issue, i'm looking for ease of use

18:47 hiredman: haven't seen kotka's, but fnparse is pretty nice

18:47 Chousuke: is kotarak's parser actually usable nowadays?

18:47 last time I looked at it it was rather outdated.

18:47 fnparse seems fine. it's using monads nowadays too :)

18:47 Cark: ok well thanks you 2, i'll go for fnparse then =)

18:48 hiredman: I am using an older version of fnparse

18:48 I think fnparse might currenlty be in the process of a rewrite to use monads or some other foolishnish

18:48 ness

18:48 :P

18:48 Chousuke: :p

18:49 monads are nice for parsing, though.

18:49 Cark: yep they say so

18:49 as long as i don't need to fully grok monads =P

18:49 Chousuke: nah :p

18:50 lisppaste8: ieure annotated #80247 "Still OOMing" at http://paste.lisp.org/display/80247#2

18:51 ieure: Chousuke, There's got to be something wrong with with-query-results, it OOMs no matter what's in the body.

18:51 Chousuke: hmm :/

18:51 unfortunately, I can't tell what it is.

18:51 hiredman: ieure: sounds like it's time to up the memory limit on the jvm

18:52 ieure: hiredman, Right, but that shouldn't be a problem unless it buffers every row.

18:52 hiredman: you don't know that it is a linear thing

18:52 Chousuke: ieure: it might even be that it's not the seq that is the problem.

18:52 or maybe it's generating too many thunks :>

18:53 ieure: Well, it works with LIMIT 5 in the query. :P

18:54 Chousuke: you could actually try changing doseq to dorun

18:54 er

18:54 ...

18:54 never mind

18:54 * Chousuke is tired

18:55 hiredman: you know the default jvm memory limit is only 128MB

18:56 Chousuke: hiredman: that shouldn't be a problem, because it should never hold that much stuff in memory in the first place.

18:56 ieure: Right.

18:56 Chousuke: unless ResultSet itself caches too much

18:56 which is a possibility.

18:57 ctdean: What's an easy way to look at memory usage in the repl?

18:57 Chousuke: it might be that you're just very close to the memory ceiling before you create the resultset

18:57 ieure: I really don't want to solve this the ghetto way.

18:57 Chousuke, This is the only code I'm running.

19:00 Chousuke: hm :/

19:01 I really can't say aything more.

19:01 the resultset-seq looks okay, so...

19:01 ieure: Well, fuck.

19:01 dnolen: ieure: post your problem to the list, some more eyes there as well.

19:02 ieure: dnolen, Yeah, I was going to see about opening a ticket, too.

19:02 Chousuke: All I can think of anymore is that it's ResultSet itself that runs out of memory.

19:02 dnolen: ieure: don't bother with a ticket, until people have looked at it.

19:02 ieure: dnolen, When you say list, do you mean the Google group?

19:02 Chousuke: yeah.

19:02 dnolen: ieure: yes.

19:10 hlship: I love lazy collections ... right up until my code loses all sense of cause and effect and I can't find the problem even w/ the debugger

19:55 eee: anyone here use clojure-dev?

19:55 it seems to come with some of contrib but not all

19:55 is that right?

19:56 memoize: today, i just quit my dayjob so i can work on clojure projects full time at home :)

19:56 eee: awesome

19:56 i've thought of that

19:56 haven't done it

19:56 what's your main project?

19:57 memoize: nothing in particular, im a clojure noob

19:57 eee: wow

19:57 memoize: just want to retrain my mind to think in clojure, so now i've got until the end of 2010

19:57 eee: you are welcome to help me with my stuff, if you like

19:58 i'm a noob to clj, too

19:58 memoize: i'd like to replace all my unix interaction with a clojure repl shell tho

19:58 eee: interesting

19:58 memoize: so that i'm always in clojure on the computer, live breathe it, dont use any other tools

19:59 eee: are you a lisper?

19:59 or new to that too

19:59 memoize: no, i come from the land of python and perl

19:59 eee: what's the best way to get the latest contrib?

19:59 memoize: svn update from the google project?

20:00 eee: i don't really want to build it

20:00 i could do that

20:00 if it builds ok

20:00 durka42: http://clojure-contrib.googlecode.com/svn/trunk

20:00 actually there might be a jar there

20:00 memoize: eee: it's just "ant" command, pretty easy

20:00 durka42: not sure

20:00 and it does build very easily

20:00 eee: ok

20:00 memoize: eee: i can put up jar files for you if you're that lazy :)

20:00 eee: i guess i could get ant for my mac

20:00 durka42: where "build" means "zip up all the sources in a jar" unless you pass -Dclojure.jar=/path/to/clojure.jar on the command line

20:01 memoize: durka42: does that option update clojure.jar to include clojure-contrib ?

20:01 eee: i'm working from eclipde

20:01 durka42: memoize: no, it compiles contrib against clojure.jar

20:01 eee: so I'll want a jar of class files . . . unless contrib is all clj?

20:02 durka42: the sources are all clj of coures

20:02 course*

20:02 eee: i wouldn't have guessed that actually

20:02 memoize: i bet you can just point CLASSPATH to the contrib source and svn update regularly

20:02 durka42: i think eclipse can integrate with ant

20:03 eee: i'll try that

20:03 yeah

20:03 durka42: memoize: that might work

20:03 memoize: eee: but you would need to get used to ant anyways if youwant to track clojure trunk; you working only against 1.0?

20:04 eee: i don't pay attention . . . whatever eclipse-dev uses

20:04 memoize: make sure its at least using 1.0 if you don't care :)

20:05 eee: gonna try svn

20:07 what are .cs files, I see in the console, I wonder

20:07 clojure source?

20:07 chessguy: csharp? :)

20:07 eee: good guess

20:07 chessguy! long time

20:07 * chessguy plays with .cs files all day

20:08 eee: i got the a-star done

20:08 chessguy: cool

20:08 eee: hmmmmm i remember seeing a graph package

20:09 gonna do some prims or djikstra now

20:10 * technomancy tries out rhickey's sdb lib

20:10 eee: i see. i didn't realize a bunch of stuff would just be at the clojure-contrib level

20:10 as files

20:11 that's wjere graph is

20:12 technomancy: I've got to say, I'm not a fan of the deps.zip approach

20:12 durka42: i believe that's why package managers were invented

20:12 technomancy: durka42: yeah, tell me about it

20:12 danlarkin: finally, someone agrees with me :)

20:13 technomancy: unfortunately one of the dependencies is a proprietary amazon jar that's not extant in any public repositories. =(

20:13 * durka42 tries to think of a good name akin to gems or eggs

20:13 technomancy: durka42: I was playing around with "corkscrew"

20:13 it vaguely sounds like something you'd use to manage jars

20:13 durka42: enclojures and clojureboxes are taken

20:14 technomancy: durka42: mvn does a great job modulo the act of writing a bunch of XML

20:14 I think we could wrap mvn in a delicious sexp layer and get something fairly rockin'

20:15 danlarkin: did you see the pom I put in clojure-http-client?

20:15 danlarkin: technomancy: I saw that you added it, but didn't look at it

20:16 technomancy: danlarkin: dysinger created clojure-pom which acts as a sort of base setup for any clojure project, and I just build from that.

20:16 basically all you do is add contrib (if you use it), and you're good to go. ends up being like four lines.

20:17 danlarkin: but do you need dysinger's thing installed somewhere or something?

20:18 technomancy: danlarkin: yeah, for now, but I'm going to get him to push it to a public repository so you won't need to do anything but "mvn install"

20:19 danlarkin: what do you do for dependencies?

20:20 danlarkin: technomancy: in terms of libraries I write? just list them in the readme. In terms of dep management for myself, ~/clojure/src/

20:21 eee: this was a whole can of worms wanting to depend on contrib

20:21 i find a lot of time always spent on config.

20:21 technomancy: danlarkin: so if you're writing an application that depends on clojure-json, then you just manually copy all the .clj files into src/ or deps/ of your project so it's on the classpath? or what.

20:22 eee: so if someone else did your config, then yes, clojure serves as a great functional language where you spend most of your time in your domain in your business rules, etc.

20:22 but that's a big if

20:22 danlarkin: technomancy: oh, no, my clj script adds add src/ directories and .jars in ~/clojure/src/ to the classpath

20:23 technomancy: gotcha

20:23 * durka42 can't wait for the next version of java which supports wildcards in the classpath

20:24 * eee thinks the real problem might be trying to mix the latest contrib with whatever clojure-contrib comes with

20:24 * eee i mean eclipse comes with

20:31 memoize: eee: there's nothing holding contrib back from using the latest goodies, nor would we want to until they decide on a 1.0 release

20:31 eee: i figured out my main problem

20:32 you can't see things in the namespace browser until you 'use' them

20:32 my next problem is: where would tests be if there are any. like so I can see usage

20:33 i'd like to understand the clojure-contrib.graph thingy (namespace?)

20:33 technomancy: eee: I have a test/ dir in the project toplevel next to src/

20:34 then the namespaces in test/ map to those in src but with the second-to-last segment being test

20:34 so org.clojure.foo is in src/org/clojure/foo.clj and tested with org.clojure.test.foo in test/org/clojure/test/foo.clj

20:34 eee: i found this. is that what you mean? wasn't nect to src http://www.google.com/codesearch/p?hl=en#oduOV9Ab97s/trunk/src/clojure/contrib/test_contrib/test_graph.clj&q=graph%20package:http://clojure-contrib\.googlecode\.com

20:35 technomancy: contrib does it differently

20:35 eee: ok

20:35 i get it, you were answering as to what your convention is

20:36 technomancy: oh, thought you were asking how to structure your own stuff

20:36 eee: i was looking specifically for the graph tests, but that is good to know that you are conscious of a need for a convention

20:36 yeah, sorry

20:37 technomancy: I don't like how contrib does it because I need to be able to calculate the namespace that tests a given namespace and vice versa so I can teach my editor how to toggle between tests and implementation.

20:37 eee: sounds like you are at an advanced level

20:37 technomancy: advanced elisp maybe. =)

20:38 not being able to toggle between test and impl sucks though

20:38 eee: i always say emacs is the reason lisp isn't more popular (ducking yet again)

20:38 technomancy: after working with clojure elisp feels a bit like tarzan-speak

20:38 eee: cntl-s doesn't save

20:38 so it's broken

20:39 copy and paste are broken too

20:39 durka42: c-x c-s

20:39 eee: because they aren't cntl-c and cntl-v

20:39 technomancy: eee: the kill ring is far more powerful than "standard" clipboard mechanisms; gimme a break.

20:39 eee: so most users punt in 5 seconds

20:39 durka42: (aquamacs still has cmd-s bound to save :))

20:40 technomancy: but elisp feels like "me get list. me alter list. you wait while I/O blocks process without concurrency primitives."

20:40 eee: i'm sure it's better

20:40 than most windows tools

20:41 Raynes: After working with Clojure, Scala feels like a scary new world where I'm lost and I can't find the golden coconut that will take me back home. But I'm getting used to object orientation now, so I'm having fun learning Scala. I just miss Clojure.

20:41 technomancy: well lots of people claim that swing is "broken" because it doesn't look like the rest of the OS. different isn't necessarily broken.

20:41 if everything has to be the same as what you're used to, then it causes stagnation.

20:42 eee: that's covered well in two of my favorite books

20:42 zen and the art of MM

20:42 technomancy: Raynes: you have to give the red key to the guard, then you can get to the room with the golden coconut.

20:42 eee: and the sequel

20:43 technomancy: Raynes: watch out for grues though.

20:43 eee: so what's the deal with structs

20:44 i know that makes no sense

20:44 but

20:44 * technomancy heads home; see you folks later.

20:44 eee: i'm not really sure what I do

20:44 (struct directed-graph #{:a :b :c :d :e} {:c #{:b :a} :e #{:c} :d #{:c :e} :b #{:d :a} :a #{:d :b}})))

20:45 so then I (let) something to a 'directed graph' struct

20:45 and then call functions on it?

20:45 Raynes: technomancy: Thanks!

20:45 guinea: What's the best way to construct and print a string that has number in it, in the form of java integers?

20:45 durka42: (doc format)

20:45 clojurebot: "([fmt & args]); Formats a string using java.lang.String.format, see java.util.Formatter for format string syntax"

20:46 durka42: ,(format "%d" 3)

20:46 clojurebot: "3"

20:46 guinea: sweet. thanks!

20:46 danlarkin: eee: structs are not classes

20:48 Raynes: danlarkin is a class!

20:51 arohner: if I call (fn inside a function body, does that create a new fn every time the function is called?

20:52 danlarkin: arohner: pretty sure it does, yes

20:53 arohner: but it's only compiled the one time?

20:53 i.e. each run through the function creates another instance of class fn_12345, and all instances of class fn_12345 have the same bytecode?

20:54 guinea: how should I print a newline?

20:55 arohner: guinea: (println) ?

20:55 you can also do (println "foo bar"), but that doesn't have the formatting options of (format)

20:56 durka42: or put \n at the end of the string

20:56 dreish: arohner: Yes, it is only compiled once, by eval.

20:57 guinea: durka42: \n didn't work within format. I was just reading the javadoc for it. But a separate println after the (.write (format ...)) would work.

20:58 arohner: guinea: are you trying to print to the screen?

20:58 ,(print (format "first line\nsecond line"))

20:58 clojurebot: first line second line

20:58 arohner: ok... that works on my terminal

20:59 guinea: arohner: no, to a java filewriter

20:59 hiredman: clojurebot tends to eat newlines

20:59 arohner: guinea: are you on windows?

21:00 hiredman: ~newline

21:00 clojurebot: thanks; that was delicious. (nom nom nom)

21:00 durka42: (System/getProperty "line.separator")

21:02 guinea: oh, it does work in newline

21:02 I just did it wrong

21:02 I mean, newline works within format

21:02 arohner: no, linux

21:34 ~newline

21:34 clojurebot: thanks; that was delicious. (nom nom nom)

21:35 technomancy: that's a new one

21:38 dreish: ,(println "In reference to the fact that clojurebot\neats\nnewlines.")

21:38 clojurebot: In reference to the fact that clojurebot eats newlines.

21:39 cp2: i wish clojurebot would be my friend

21:39 durka42: clojurebot: whose job is it to be cp2's friend?

21:39 clojurebot: Alles klar

21:40 durka42: that used to work

21:40 cp2: :(

21:40 dreish: ~whose job

21:40 clojurebot: whose job is it to be cp2's friend?

21:41 technomancy: clojurebot: whose job would it be to be cp2's friend?

21:41 clojurebot: whose job is it to be cp2's friend?

21:41 technomancy: clojurebot: stop copying me.

21:41 clojurebot: we can't stop here! this is bat country!

21:42 durka42: clojurebot: whose job is <reply>that's <someone>'s job

21:42 clojurebot: Ack. Ack.

21:42 durka42: ~whose job

21:42 clojurebot: that's <someone>'s job

21:42 Raynes: LOL

21:42 Fear and Loathing.

21:43 hiredman: ~who's job would it be to right the wrongs of the world?

21:43 clojurebot: what the world needs is more higher order functions

21:44 hiredman: :\

21:44 technomancy: he has a point though

21:44 hiredman: indeed

21:46 dnolen: technomancy: do you have any good examples of parsing lines from a file using elisp? You seem to be the resident elisp expert :)

21:46 technomancy: dnolen: what kind of file?

21:47 I did something sort of like that in my couchdb client, though it's very simplistic.

21:47 dnolen: just a text file, I'm sick of managing my classpath by hand.

21:47 I'm building a simple library management system using GAE

21:47 so that I can type

21:47 (install 'library-name)

21:48 from the REPL.

21:48 but in order this to work in Emacs I need all classpaths to be a text file.

21:48 in a text file.

21:48 durka42: how does GAE come in to that?

21:48 technomancy: dnolen: in a nutshell: (save-excursion (while (search-forward-regexp my-pattern nil t) (do-something-with (string-match 1))))

21:49 dnolen: no having to pay for hosting.

21:49 technomancy: that's if I have the file open already and loaded into a buffer correct? I found that much.

21:49 technomancy: err... hosting static files is very cheap. if you're worried about that I'll give you a shell account on my dreamhost. =)

21:50 right; you'd need to find-file first

21:50 dnolen: you can't do much with a file unless it's in a buffer

21:51 you could also use url-retrieve if it's a remote file, relax.el has a few examples of that

21:52 dnolen: cool, the other advantage of GAE is just scalability (maybe hosting jars, jnis), speed, security. I don't want to have to code that either.

21:53 technomancy: I'd strongly advise against a library management system that needs a dynamic server. it's much easier to build up a set of static files.

21:54 rubygems, maven, and elpa all go this route.

21:54 dnolen: hmm what do you mean by dynamic server?

21:55 technomancy: I mean more than a directory with files in it.

21:55 if any user operation causes code to run outside of apache or nginx or whatever, it's more complicated than it needs to be

21:55 dnolen: like you mean on the client?

21:55 technomancy: sorry, server-side code

21:56 dnolen: basically I'm starting off just by creating a wiki, I'm not even hosting files in the beginning.

21:56 technomancy: oh, ok

21:56 dnolen: just a json data about a where a library lives.

21:56 durka42: unless it looks like a simple list of files on the server but you're faking it with some fancy database or whatever

21:56 technomancy: I assumed you were using GAE for dynamic responses to client requests.

21:56 dnolen: there's a client library that checks the server to resolve the library location.

21:56 downloads the file, unzips, update the classpath.

21:57 technomancy: still missing the GAE connection

21:58 dnolen: just for the hell of it, I don't feel like hosting it myself, plus then people can also download the project from GitHub, develop locally to improve and it's easy to push up patches.

21:58 technomancy: gotcha

21:58 dnolen: you should take a look at my corkscrew project

21:58 dnolen: link?

21:58 technomancy: http://github.com/technomancy/corkscrew

21:59 it can already handle dependencies in git or svn or just grabbing a jar over HTTP

21:59 planning on adding mvn repo support as another backend so transitive deps would work

21:59 since that's where the real tricky stuff comes into play

22:00 clojurebot: corkscrew is a proof-of-concept build system and dependency manager (http://github.com/technomancy/corkscrew)

22:00 clojurebot: Ik begrijp

22:00 dnolen: heh looks almost identical to what I'm doing in terms of lib def format :)

22:00 technomancy: heh

22:00 let's join forces

22:01 dnolen: cool! I want this library thing fixed bad.

22:01 technomancy: actually the problem with corkscrew is that the fun stuff is basically done, the hard parts remaining are just integrating with the maven Java API

22:01 dnolen: you're not the only one. =)

22:01 I've been meaning to announce on the mailing list, but I was waiting till I had proof-of-concept mvn integration.

22:05 danlarkin: oof, I hate the 80/20 breaks

22:06 technomancy: danlarkin: yeah, if you ignore transitive deps, you can practically solve the problem in an afternoon.

22:07 danlarkin: I wish I could ignore 20% of the problems at work :)

22:10 technomancy: interesting article: http://enfranchisedmind.com/blog/posts/scala-not-functional/

22:11 makes a good case against the "Can't OOP and FP just get along well together?" mentality.

22:12 danlarkin: care to take a look at corkscrew and comment?

22:12 would love to get some more eyes on it.

22:14 danlarkin: technomancy: I very much like the idea

22:14 I will have to look at your implementation later, though

22:14 technomancy: right, no big deal

22:33 how do folks generally do logging? just regular log4j?

22:41 arohner: technomancy: that's what I do

22:41 cp2: asdf etc

22:43 technomancy: arohner: it's struck me as kind of noisy out of the box, but I guess you can deal with that

22:43 arohner: yeah. I have a function that's just (log severity "type" "message")

22:44 and I could get that down smaller if I wanted

22:44 technomancy: oh, I meant the output format. =)

22:44 arohner: oh :-)

22:44 technomancy: in the context of some of the apache libs it was pretty spew-happy

22:44 arohner: yeah, that can be dealt with too

22:44 though I'm used to reading apache logs

22:44 that, and there are good log viewers out there

22:45 technomancy: like less? =)

22:45 or grep -v INFO ? =)

22:46 arohner: :-)

22:52 technomancy: is it appropriate to release projects with the groupId of "org.clojure" even if it's not officially related to clojure?

22:55 * technomancy is still learning pom ettiquite

22:57 jmaness: has anyone seen an exception like this when compiling .clj? Exception in thread "main" java.lang.IllegalStateException: get already refers to: #'clojure.core/get in namespace:

22:57 "get" isn't even in the .clj file

22:58 technomancy: jmaness: are you "use"ing a library that defines a "get" function?

22:58 typically you want to require it :as something instead

22:58 jmaness: ah probably so. clojure.http.resourcefully

22:59 technomancy: jmaness: yes... that would be my fault. =)

22:59 jmaness: ah ok cool thanks. I'll try "require"

22:59 technomancy: jmaness: I'm on the fence about that. I think it's cute and maps to HTTP well, but it's unfortunate that you can't "use" it like any other lib

22:59 jmaness: the readme explains it.

23:00 but... having to read the readme carefully to try out the library without getting errors is unfortunate.

23:00 I might end up renaming it so you don't have that problem

23:00 jmaness: ah thanks. sorry I missed reading the README :)

23:01 technomancy: honestly I'd prefer it if clojure.core didn't define "get" since I perform HTTP get requests far more often than I use core's version of get.

23:01 but that's unlikely to change. =)

23:02 bradford: i want a function that applies a map of functions to a map fo values of the same keys.

23:02 (def test-map {:a 10 :b 5})

23:02 (def test-fns {:a #(%1 > 5) :b #(%1 < 5)})

23:03 technomancy: (map #((test-fns %) (test-map %)) (keys test-map)) is that too verbose?

23:04 jmaness: other than that silly get problem, is clojure-http-client working well for you?

23:04 I'm interested in feedback for improving it.

23:05 durka42: bradford: (merge-with #(%1 %2) test-fns test-map)

23:05 technomancy: durka42: dang; that's slick

23:05 jmaness: technomancy: so far so good. I'm trying to get basic auth working

23:06 technomancy: jmaness: ah cool; I haven't done anything with auth yet.

23:06 jmaness: patches welcome. =)

23:07 jmaness: technomancy: sure, I've cloned clojure-http-client, so as soon as I get something working, I'll send it your way

23:08 technomancy: cool. nothing like scratching your own itch.

23:11 bradford: i don't thing merge-with does what i want

23:12 durka42: then i misunderstood what you wanted :)

23:12 bradford: i think merge-with is for mergeing many maps and using a single function to resolve merging duplicate keys

23:13 what i am doing here is applying each function in a map fo function to each value in a map of values

23:13 durka42: so the way i called merge-with above, on duplicate keys it uses #(%1 %2), which is function application

23:13 technomancy: bradford: ah, so every function gets called with every value?

23:14 bradford: right

23:14 technomancy: yeah that's different

23:14 * durka42 is confused

23:14 durka42: what does (magic test-fns test-map) return?

23:14 technomancy: how would the return value look?

23:14 sounds two-dimensional

23:15 bradford: theresult of this function for the example I gave is {:a true :b false}

23:15 danlarkin: resourcefully/get strikes again!

23:15 durka42: Clojure=> (merge-with #(%1 %2) test-fns test-map)

23:15 {:a true, :b false}

23:15 technomancy: danlarkin: you can say I told you so now. =)

23:16 * danlarkin laughs maniacally

23:16 technomancy: rename it to hget?

23:16 bradford: durka42: i get: .Integer cannot be cast to clojure.lang.IFn

23:16 durka42: bradford: fix the functions in test-fns

23:17 bradford: durka42: bwaahahahah! thanks man

23:17 technomancy: hehe

23:17 bradford: also: if a #() fn has only one arg you can use % rather than %1

23:19 eee: it looks like clojure-contrib.graph doesn't define weighted graphs?

23:19 what if I wanted to add that concept?

23:25 i guess I can use a hash-map instead of a hash-set for the neighbors

23:39 bradford: if i get: ({:a 1, :b 0} {:a 0, :b 1}) from a for expression...

23:39 and then try to pass it to something that expects a number of maps {} {} then how to pass it?

23:40 eee: expects a number of maps

23:40 in a list?

23:40 i fixed number?

23:40 a

23:41 bradford: (defn counts [fns map] (merge-with #(+ %1 %2) (for [x map] (merge-with #(%1 %2) fns x))))

23:41 problem is with the outer merge-with

23:41 eee: it sounds like you are saying how do I send a list of maps to something that takes a list of maps

23:41 bradford: i know :-) ...it seems that way

23:41 eee: lemme look

23:42 bradford: (def test-fns {:a #(if (> % 5) 1 0) :b #(if (< % 5) 1 0)})


23:42 (def test-map [{:a 10 :b 5} {:a 4 :b 1}])

23:42 that are what i am passing to this counts fn

23:44 eee: ,(doc merge-with)

23:44 clojurebot: "([f & maps]); Returns a map that consists of the rest of the maps conj-ed onto the first. If a key occurs in more than one map, the mapping(s) from the latter (left-to-right) will be combined with the mapping in the result by calling (f val-in-result val-in-latter)."

23:44 hiredman: bradford: you use apply

23:44 eee: i was thinking of reduce

23:45 bradford: (defn counts [fns map] (apply merge-with (cons #(+ %1 %2) (for [x map] (merge-with #(%1 %2) fns x)))))

23:45 using apply + cons

23:45 eee: reduce the list comprehension using merge-with as the function

23:45 bradford: seems like there must be a better solution to this little coding problem

Logging service provided by n01se.net