#clojure log - May 20 2011

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

0:00 dnolen: zakwilson: the bad experiences w/ Clojure seems generally low - if they exist they're always of the obvious variety - "too many parens!"

0:01 zakwilson: I'm not new to Clojure, but I haven't used it for a customer project yet. Parens don't bother me. If I'm going to complain about something, it's the lack of user-defined reader macros.

0:02 dnolen: zakwilson: seems like a minor nit, a good overall design choice.

0:02 zakwilson: And maybe that exceptions feel too Java-ish (I'd rather have conditions that don't unwind the stack)

0:03 dnolen: zakwilson: but do conditions make sense w/ interop?

0:03 zakwilson: Not sure. Somebody did them as a library, and I haven't actually tried using it.

0:03 amalloy: dnolen: it sounds like that's not an issue for him, since he says jvm isn't a requirement

0:03 zakwilson: cc.condition is not recommended, is my understanding

0:04 core team really want a better exception/error system but afaik haven't figured out a good way to make it happen yet

0:04 zakwilson: Actually, the one I remembered was cc.error-kit

0:04 dnolen: zakwilson: so you would leverage Java libs in this project?

0:04 s/would/wouldn't

0:04 sexpbot: <dnolen> zakwilson: so you wouldn't leverage Java libs in this project?

0:05 zakwilson: I can't say that I won't. I will prefer Clojure libs or wrapped Java libs, but I'm sure there will be a bit of interop here and there.

0:06 I'm just saying, there's no reason I couldn't do it in a language that isn't hosted on the JVM.

0:06 dnolen: zakwilson: so who are the competitiors? CL? Racket? Haskell?

0:07 zakwilson: RoR is the main competition. I'm sure that will be easier at first, but I suspect Clojure will provide more flexibility later on.

0:07 dnolen: zakwilson: so it's website w/ templates and all that?

0:08 zakwilson: Yes. CRUD app with sugar on top.

0:08 dnolen: zakwilson: for a full blown website w/ templates, ORM, I don't really think Clojure competes much, but I think it depends on project timeline.

0:09 If the competition was say ... Sinatra, I would say Clojure 100%

0:09 zakwilson: ORM isn't a requirement, and I kinda don't like ORM. ClojureQL seems like a nicer compromise between writing SQL by hand and ORM.

0:11 dnolen: zakwilson: My point is simply that if you want RoR convenience - Clojure ain't there yet. If you understand that RoR convenience is actually a low ceiling, then yes Clojure is attractive.

0:12 zakwilson: Isn't that what I said when I mentioned RoR?

0:15 dnolen: zakwilson: heh, you did. But it's hard to make any kind of judgment w/o any understanding of project scope. Rails is now a somewhat shared domain of understanding. Clojure not so much.

0:16 zakwilson: I know. I was mostly looking for any known big problems. I've done a website with similar scope in CL before and did run in to trouble, namely that SBCL had issues with the virtualization used by some VPS hosts.

0:20 dnolen: zakwilson: perhaps others can chime in about JDK differences between platforms, there's been some mutter about it in the past, but not at the level of SBCL issues I think.

0:21 zakwilson: I don't forsee that sort of deployment difficulty with Clojure, and as platforms go, I'm hoping to do all development and production on Debianoids of some sort.

0:24 dnolen: zakwilson: well, I do RoR at work, and my experience is that most of what I do would be simpler, shorter, and faster in Clojure.

0:24 zakwilson: That has been my experience with non-trivial RoR as well. You have failed to talk me out of Clojure. Good job.

0:26 tomoj: zakwilson: so, pallet, chef, or..?

0:28 zakwilson: I'm honestly not familiar with either of them.

0:30 A quick look gives me the general idea of pallet. That sounds potentially useful for a project still on the drawing board.

0:37 nathanmarz: tomoj zakwilson: i'm a big fan of pallet. i use it for a lot of stuff

0:40 tomoj: guess I should try doing what chef does now with pallet

0:40 always felt it would be better in clojure

0:41 nathanmarz: it has a learning curve, but is worth it

0:41 and hugod is very helpful

0:43 tomoj: nathanmarz: was it you who pointed me to the bixo list?

0:46 nathanmarz: i don't remember

1:11 amalloy: seancorfield: we've added some new features to make it impossible for you to ever take your eyes off 4clojure

1:12 seancorfield: uh-oh

1:12 i've managed to get some work done over the last couple of weeks...

1:12 amalloy: i guess you're following @4clojure so you knew that already though

1:16 amac: whenever I try to jar my project with lein it blows away my lib and re-fetches the deps -- but in the process wipes out the mysql-connector.jar file I need in there. Is there a way to tell lein that this file is friendly and shouldn't be removed?

1:17 raek: amac: yes, there is an option you can add to the project.clj file (see the sample project.clj in the leiningen github repo)

1:18 symbole: Is it possible to force an evaluation of a macro parameter during macroexpansion time, i.e., outside a backquote?

1:19 raek: amac: also, I'm fairly certain that mysql-connector is in some maven repo (unless you need a homebrew version)

1:19 amac: I don't need a homebrew, I just couldn't find where it was hosted

1:19 raek: http://jarvana.com/ <-- good site for searching in maven repos

1:20 http://jarvana.com/jarvana/archive-details/mysql/mysql-connector-java/5.1.14/mysql-connector-java-5.1.14.jar

1:21 amac: sweet

1:21 thanks for that

1:21 also; :disable-implicit-clean true did the trick

1:21 :)

1:21 seancorfield: amalloy: actually i filtered out 4clojure because of all the annoying tweets about how xyz solved a problem :)

1:22 btw, Leagues links to http://4clojure.com/login/update is that intentional?

1:22 amalloy: yeah, the leagues page is kinda lame

1:23 i wanted to add a new link so people would know the feature exists

1:23 seancorfield: i've slipped to 48th... *sigh* ...i guess i need to start solving puzzles again at some point :(

1:24 amalloy: seancorfield: incidenally, you can follow @4clojure (the user, not the hashtag) to get only meaningful site updates. plus, we started using the #clojure tag at most once an hour, so you can't get annoying floods all at once

1:29 seancorfield: i'm off to amit rathore's day of clojure macros training on saturday :)

1:29 should be fun

1:30 and right now, i'm off to... bed! g'nite

1:30 amalloy: ah, enjoy

1:33 technomancy: amac: you can try "lein search" in the latest git

1:33 git lein

1:35 amac: technomancy: neat

1:35 * amac updating

1:36 * amalloy worked pretty hard before parsing that to *not* mean that git now includes a lein plugin

1:48 desertman: hi, i am trying to get compore running (this is on cygwin) , following https://github.com/weavejester/compojure/wiki/Getting-Started, I added to prj file, then lein clean, lein deps, and lein ring server, , get class exception for compojure.core

1:55 amalloy: desertman: on the information provided it all sounds fine, but not much information has been provided. gist up your error message and/or your project.clj and/or the code you're using, and maybe someone can help

2:18 desertman: this is my compojure issue : https://gist.github.com/982438

2:20 raek: desertman: you have your :use clause outside the ns form

2:21 desertman: ok, thnks

2:21 raek: since ns is a macro, it defines new meaning to the (:use compojure.core) code

2:22 using the normal clojure evaluation rules, it means "look up the :use key in compojure.core", where compojure.core is a class name literal

2:22 and there is no java class with the name compojure.core, hence the error

2:22 amalloy: same for the :require clause, btw

2:24 raek: if you just remove the right paren at the end of line 21, it should be fine

2:42 amalloy: raek: it's surprising how many beginners can fix their problem by removing some parens :). see, lisp's not that bad

6:14 clgv: what is the easiest way to store clojure data structures in a file for later reading and analysing?

6:20 fliebel: clgv: JSON? Or just… clojure, if it's safe data.

6:20 clgv: fliebel: just found amalloys blog entry about using pr or pr-str

6:20 fliebel: right :)

6:20 raek: clgv: (spit file (pr-str x)) or (binding [*out* (clojure.java.io/writer file)] (pr x))

6:22 the latter is problably better, since it won't make one huge string for the whole value

6:22 clgv: thx, raek

6:23 raek: ("file" can be a filename as a string or a java.io.File (a file path object), among other things. look at this page for more info on that: http://clojuredocs.org/clojure_core/clojure.java.io)

6:25 the reverse would then be (read-string (slurp file)) or (binding [*in* (clojure.java.io/reader file)] (read))

7:15 * raek just discovered that java comes with a javascript interpreter... http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/

7:55 patsp: Hi, have anyone already read the 4clojure.com problem "Graph Tour"? I don't understand why the second testcase should be false. Can anyone explain?

7:59 clgv: patsp: I think you can remove the double edges since you can visit one and return on the other

8:00 patsp: if you do that you have a graph were only one edge remains from d to each of the other nodes

8:01 patsp: so there is no possibility to use all of them, since you will get stuck in one of the 3 nodes (a, b or c) and you wont be able to visit the last remaining one

8:03 patsp: I think I remember a rules that states a necessary criterion for such an euler tour but quoting that one would spoil you the fun of solving the problem ;)

8:03 patsp: but the path a->c->d->b->a->d visits all edges

8:04 and I don't think that we should find a tour but a path because otherwise the first testcase is wrong

8:04 clgv: patsp: no it does not! there are two remaining edges [a b] and [a c] that you did not include

8:05 patsp: the spedicifation as a clojure set might be the error in the problem test cases

8:05 patsp: but the edges are representet as a set --> double edges are not possible

8:05 yes exactly

8:06 clgv: they use a set but mean to have more than one edge per node pair

8:06 patsp: ok, then it's clear, thx

8:07 clgv: maybe you have to write them if you cant get that problem solved due to this error

8:08 patsp: do you think an issue on github would be appropriate, or just email?

8:35 Just a note to my previous conversation: now the testcases for the 4clojure.com problem "Graph Tour" are correct.

8:45 wastrel: /win 19

9:34 gfrlog: okay so

9:34 if I want a (doall) that works on arbitrarily nested structures

9:35 i.e., ensure that nothing in my object is unevaluated

9:35 is my best bet to combine (doall) with something from (clojure.walk)?

9:35 or does this already exist?

9:35 chouser: hm

9:36 you don't really care about the return value, since you can just use the original objects

9:36 so I think you could use tree-seq instead, if you wanted

9:36 raek: I recall that someone made such a function

9:36 gfrlog: ,(doc tree-seq)

9:36 clojurebot: "([branch? children root]); Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one arg that returns a sequence of the children. Will only be called on nodes for which branch? returns true. Root is the root node of the tree."

9:37 raek: gfrlog: btw, what situation led to this problem?

9:37 gfrlog: raek: I am using Jena

9:37 um

9:37 I guess any database could have the same issue

9:37 I just need to make sure the results are all consumed before closing the connection, essentially

9:38 the fact that it's jena just explains why I'm not using clojureql or c.c.sql

9:38 I've got a number of data-access functions I've written, and I'd rather wrap them all in a general-purpose solution than reason through each one and add (doall) as needed

9:39 raek: if you have control over the code that builds the data structure, then one possibility is to let it call doall on all lazy-seqs it puts in the data structure

9:40 gfrlog: right

9:40 that's what I'm hoping to avoid

9:40 given that my automated tests are not likely to catch this

9:40 I'm already using a macro to def the data access functions, so adding it at that point seems simplest

9:41 raek: not likely to catch missing doalls in the generating code?

9:42 gfrlog: well I could do it if I really focused, but that's rather brittle, especially if I start changing things

9:42 raek: wouldn't (is (= [1 2 3] (with-... <generate sequence here>))) work

9:42 gfrlog: for testing you mean?

9:42 raek: yes

9:43 stuartsierra: a sequence won't be = to a vector

9:43 raek: where "with-..." is a macro like "with-open" that closes the connection before it retusn

9:43 gfrlog: stuartsierra: yes

9:43 raek: ,(= [1 2 3] '(1 2 3))

9:43 clojurebot: true

9:43 stuartsierra: oops

9:43 gfrlog: ,(= [1 2 3] (range 1 4))

9:43 clojurebot: true

9:43 gfrlog: stuartsierra: I take back my agreement

9:44 stuartsierra: I take back my assertion.

9:45 * raek (continuation-from-three-minutes-ago)

9:45 gfrlog: raek: yes I guess I ought to test for this too :(

9:46 raek: but laziness and resource management is indeed tricky

9:46 gfrlog: the trap is built into c.c.sql

9:47 I'm glad clojureql came along cause I was tired of typing (into [] (with-query-results r [...])) or making ad-hoc utility functions for it

9:47 also I was tired of not using clojureql

9:48 raek: if you don't need the random access of the vector, then doall is preferred here, I think

9:49 gfrlog: oh for c.c.sql? yeah that makes sense.

9:49 old habit I guess

9:49 probably saw it somewhere and never decided to think past "it works"

9:51 raek: in one of my libraries, I provide two variants of a function that parses lines from a socket: one that takes a sequence of lines and returns a lazy-seq of the parsed lines and one that uses the first which also ensures that the sequence is forced and that the stream is closed

9:52 gfrlog: and next you're going to say that you have a very intuitive way of naming the two?

9:52 raek: if the user wants to process the lines lazily, then he can use the low-level one and do the resource management himself

9:53 the naming is always the trickiest part :-)

9:53 gfrlog: parse-lines and parse-lines~

9:53 raek: I called them "directory-seq" and "read-directory", I think

9:53 * gfrlog shrugs

9:54 raek: the first one in analogy to "line-seq"

9:55 gfrlog: that seems good

9:56 raek: I think I considered "fetch-directory" for the second one. I looked for a word that implies that you get the whole thing at once

9:56 gfrlog: injest?

9:56 devour?

9:56 Fossi: gulp ;D

9:57 gfrlog: slurp

9:57 cemerick: jeez, what a shit-storm on the ML

9:58 I guess we were due

9:58 stuartsierra: now what?

9:58 raek: heh. "slurp" is not that bad... it has the right connotations if you are used to clojure.core/slurp

9:59 TimMc: slurp-dir?

9:59 Fossi: cemerick: got an archive link?

10:00 cemerick: http://groups.google.com/group/clojure/browse_frm/thread/f97699164e9be29e I gues

10:00 guess*

10:00 Fossi: thanks

10:02 ah, that thing again

10:02 edw: technomancy: You around?

10:03 TimMc: cemerick: Oh, "Mailing List". I kept looking for ML-the-language stuff. >_<

10:03 cemerick: Fossi: Just a vessel for everyone's particular gripes.

10:03 Fossi: yes

10:03 got the same feeling from that last discussion

10:04 cemerick: TimMc: yeah, damn that ML shit-storm. Stupid language anyway!

10:04 ;-)

10:04 Fossi: kinda peintless as well

10:04 *o

10:04 cemerick: Fossi: which means it's a shoe-in for a 100-message thread

10:04 * gfrlog runs off to start a DOS shitstorm

10:06 Fossi: having some experience with clojure in a java environment with lots of smart people all i can say is: lisp is not for everybody ;)

10:06 edw: Fossi: I have trouble believing that.

10:06 Fossi: the ide won't be the major problem

10:07 TimMc: Fossi: And tehrefore is doomed to never have widespread acceptance?

10:07 gfrlog: Fossi: what about people who learn FP before OOP?

10:07 Fossi: and it's still *way* harder to get a customer let you use anything but plain java anyway

10:07 at least it's a possibility

10:07 TimMc: Fossi: Why should they care what's in the JAR?

10:07 gfrlog: somebody write a clojure-to-java translator

10:08 Fossi: i don't necessarily believe in unlimited growth

10:08 edw: Fossi: Lisp with an IDE that lacks a REPL sort of misses the point. Lisp is different from what most people know. *Un*learning is the most important part of transitioning people to a Lisp.

10:08 Fossi: TimMc: because they pay and own the code

10:08 TimMc: Oh, that kind of customer.

10:08 Fossi: and they want to have at least the illusion of taking it somewhere else

10:09 *being able

10:09 edw: Fossi: Just say, "I'll deliver a jar with source."

10:09 TimMc: heh

10:09 Fossi: won't cut it

10:09 gfrlog: linguistic tricks are the best way to get referrals

10:09 TimMc: I don't see why any competant dev couldn't learn Clojure.

10:09 gfrlog: haha

10:09 Fossi: at least not with "bigger" ()500+ persondays projects

10:10 gfrlog: TimMc: once you define "competant" so as to make that a tautology, I agree

10:10 Fossi: TimMc: well, that's part of the problem

10:10 yes :)

10:10 edw: In my experience, if you want freedom to use tools that let you be productive, you're best off in an envrionment that isn't a development shop. I work for a marketing agency, and they don't care what I use.

10:10 Fossi: people are commonly having problems grokking java :)

10:11 edw: well, i guess those aren't the target of the "enterprise integration cloud buzzword" group that typesafe targets

10:12 gfrlog: on a totally unrelated note, why doesn't (memoize) use soft references?

10:12 Fossi: that sentence makes no sense whatsoever :)

10:13 raek: gfrlog: memoization and caches are not the same thing

10:13 edw: Fossi: The enterprise. Sigh. So sad.

10:14 Fossi: true

10:14 big moneys though

10:14 `fogus: gfrlog: That would be rude. ;-)

10:14 Fossi: and interesting problems too sometimes

10:14 raek: gfrlog: http://groups.google.com/group/clojure-dev/browse_thread/thread/227859e14deb0d7c/21414bdd6991dec6?lnk=gst&q=memoize#21414bdd6991dec6

10:14 gfrlog: raek: thank you sir

10:14 Fossi: at least when it comes to pure numbers/traffic (me being a web developer ;) )

10:16 gfrlog: raek: I guess the next question is why would anybody want to memoize when they could cache?

10:16 edw: Fossi: There's too much insecurity and arrogance in enterprisey environments.

10:17 gfrlog: maybe it makes the GC have to think harder?

10:21 is it strange that (with-open) uses (let) instead of (binding)?

10:22 TimMc: gfrlog: Because "memoize" sounds like "memorize" as pronounced by the priest from The Princess Bride.

10:22 And "cachify" doesn't.

10:22 gfrlog: maybe it is not so strange

10:23 TimMc: Makes sense to me.

10:23 gfrlog: I just find it unusable with my *model* var

10:37 TimMc: Oh man, this is going to be interesting.

10:38 I just started full-time at a company with a large-ish Java codebase. How long do you think it will be before I start trying to write Java macros? :-P

10:42 Actually, there is some interest here in rewriting one internal app in Clojure.

10:45 alandipert: TimMc: do it!

10:45 TimMc: Well, it's a matter of priorities -- if the app as it currently stands doesn't suck too much to maintain, it's not gonna happen. :-P

10:46 But the CEO and some other higher-ups have LISP background, so it's a definite possibility.

10:48 How does Clojure's licensing interact with commercial products? I notice that core and contrib would be distributed with the product.

10:49 edw: Do something that actually works and does something useful and show some buiness owner. They'll get a hard-on and will want you to add a few features. Say, "Oh, this little thing? It's something I was working on in my spare time. You'll have to ask my boss to let me spend some more time on it." And then you're off and running...

10:54 lucian: TimMc: it's EPL afaict, so it shouldn't

10:55 TimMc: http://en.wikipedia.org/wiki/Eclipse_Public_License like a weaker LGPL

10:56 gfrlog: I wrote a bit of code for a blog post the other day and somebody commented asking what the license of the code was :-|

10:56 never had to think about that before

10:57 Fossi: hate people licensing javascript with gpl :>

10:57 TimMc: Fossi: My apologies.

10:57 edw: And did they complain that you're a willing accomplice to capitalism by not GPL'ing it?

10:57 `fogus: Related to the memoization dircussion: https://github.com/fogus/unk

10:57 Fossi: TimMc: huh? :)

10:57 TimMc: Fossi: I do that a lot.

10:57 Fossi: it makes no sense

10:57 whatsoever :D

10:57 lucian: meh, i use GPL when i think it's appropriate. or AL 2.0 otherwise, usually

10:58 TimMc: It's easy to just slap on "GPL" when I have a random piece of software I want to release.

10:58 Fossi: even gpl people at the fsfe weren't able to fully grok what that means when i asked

10:58 lucian: the EPL is kinda braindead, though. it's sad that clojure uses it

10:58 TimMc: Fossi: What do you think makes the most sense for JS libs?

10:58 Fossi: dunno, bsd or epl or such

10:58 lucian: Fossi: i'd say LGPL

10:58 TimMc: How about LGPL?

10:59 Fossi: it's better than gps

10:59 TimMc: I can always relicense my stuff anyway.

10:59 lucian: no library should use an application license

10:59 Fossi: but still, what's "linking"?

10:59 lucian: Fossi: derivative work, same thing

10:59 Fossi: and what's "you have to distribute the source"

10:59 lucian: the GPL is enforceable for python just as much as for C, it's been established

10:59 TimMc: Fossi: That's the easy part.

10:59 lucian: why would JS be different?

11:00 Fossi: because you always ship the source to your "customers"

11:00 lucian: if you ship a runnable version

11:00 Fossi: and "linking" happens in their browsers

11:00 lucian: Fossi: not necessarily. it's a derivative work if it's designed to work with that, in the client's browser

11:01 Fossi: the most common interpretation was that you have to also serve an unminified version

11:01 /unobfuscated

11:01 lucian: yes, minification counts as obfuscation, which GPL forbids

11:01 well, sort of

11:01 GPL3 makes it clearer

11:01 TimMc: Fossi: Oof, forgot about minification.

11:01 Fossi: it's all not that clear

11:01 so it's a pita :)

11:02 * lucian shrugs

11:02 lucian: it's less of a PITA than a proprietary license

11:03 Fossi: no, my client has to buy those, if i need them

11:03 that's easy

11:03 but i'm liable if i use something "free" and misuse it

11:03 TimMc: Hell, how does commercial licensing work with JS?

11:03 Fossi: at least it's a danger

11:03 TimMc: copyign and whatnot

11:03 lucian: TimMc: same as with anything else. most things are easily decompiled

11:03 Fossi: TimMc: they ship obfuscated personalised versions

11:04 and some phone back

11:04 lucian: Fossi: but it's not necessarily easier. even if you pay, there's strings

11:04 Fossi: or only work on specific hostnames

11:04 lucian: GPL also has strings, seems fairplay to me

11:04 wow, that's evil

11:04 TimMc: No, I mean when a company buys a JS thingy and serves it on their site.

11:04 Fossi: lucian: yes, but those are mostly clearly defined in some contract

11:05 lucian: Fossi: again, they're reasonably clearly defined in the license

11:05 if in doubt, contact the copyright owner

11:05 Fossi: yeah, i did so a whole lot, you can believe me :)

11:05 and most people react like TimMc :)

11:05 lucian: well, it is sad that many people don't understand licensing, or simply don't care

11:06 Fossi: sometimes it's hard to reach people though

11:06 at least in a timely manner

11:06 lucian: yes, i know

11:06 but we have the advantage of few licenses

11:06 GPL is always GPL

11:06 Fossi: too bad that the js world never concurred to a saner standard than gpl :/

11:07 most intepreted language communities did

11:07 lucian: i guess you'd say that if you disliked the GPL

11:08 but really, there's no ambiguity with GPL and interpreted languages

11:08 * angerman wishes he could code in a sane language ...

11:08 lucian: JS's distribution is slightly different, but even that's not terribly important

11:10 Fossi: i just dislike the ambiguities of linking and minification

11:10 lucian: but there aren't any! :)

11:10 a derivative work is not defined by linking

11:11 and minification is considered runnable code, not source, usually

11:11 Fossi: the question isn't whether i have to commit back

11:11 that's easy

11:11 lucian: i suppose the second is slightly ambiguous, but you'd offer non-minified code anyway

11:11 Fossi: it's whether my code (that's proprietary) can call a part of gpl'd js

11:12 in the users browser

11:12 TimMc: lucian: I guess the central question is whether using JS on a web page counts as distribution.

11:12 lucian: Fossi: can't, it's a derivative work. simple

11:12 TimMc: That's the only difference, really.

11:12 lucian: TimMc: it does

11:12 Fossi: the distribution part is kinda okayish

11:12 lucian: does it get to the client, and run there? it's distributed

11:14 TimMc: I like the approach of having minification on the fly with versioned files -- foo-1.2.min.js is a minified + cached copy of foo-1.2.js, both of which are available over HTTP.

11:14 I call that "providing source".

11:14 * lucian too. although it doesn't have to be on the fly

11:14 Fossi: TimMc: well, you also want to concat those, but yeah, mostly stays the same

11:15 TimMc: foo-1234$bar-7654.min.js

11:15 LiveJournal was doing that at one point.

11:41 edw: Is there an idiomatic way to handle debug logging? I've written my own DEBUG function that takes a log level and a message and the message is logged if the current log level is equal to or higher than the passed in log level. I'd like to like clients of my project get this ability but don't want to unleash any new wheel designs upon the earth.

11:42 clojure.logging, perhaps?

11:47 dnolen: edw: https://github.com/clojure/tools.logging

11:48 edw: Sorry, that's what I meant. It's been placed in my project.clj...

11:54 Paredit and Clojure mode are not playing nicely using the clojure-jack-in command: C-k is bound to kill-line, not paredit-kill-line, and I'm getting "unbalanced parens" errors when I try to kill a line.

11:55 Do I need to make sure one loads before the other?

12:40 amalloy: edw: does the modeline mention paredit?

12:41 technomancy: edw: those should be orthogonal

12:49 edw: technomancy: Hey.

12:51 wastrel: i got vimclojure working with indenting

12:51 i just had to blow away my entire ~/.vim and install it fresh

12:51 edw: technomancy: If I start-up emacs with '-q' and install paredit and clojure-mode I get the same (problematic) behavior. I have a traditional SLIME, Clojure, Paredit set-up that works fine. To be specific typing C-k where the X is in here "(ns Xfoo.core)" will cause an unbalanced paren error.

12:51 Raynes: wastrel: You earn a shiny gold VimClojure medal! :D

12:51 wastrel: :p

12:51 i still want that fancy repl

12:53 lucian: wastrel: i'm trying out vimana right now

12:53 TimMc: edw: But is paredit-mode on in that situation?

12:53 technomancy: edw: clojure-mode 1.9.0 and paredit 22?

12:53 edw: TimMc: Yes.

12:53 technomancy: I followed your screencast instructions, and yes, Paredit 22.

12:54 wastrel: lucian: never heard of it

12:54 lucian: wastrel: it's a perl utility for managing vim packages/thingies

12:54 like pip/gem/etc

12:54 but for vim

12:55 edw: technomancy: This happens regardless of whether I set the set a clojure-mode hook or enable paredit-mode manually.

12:56 amalloy: edw: does M-x paredit-kill work?

12:57 edw: amalloy: 1. It is being invoked but 2. it will not kill if it means intelligently not killing part of the line due to the existence of parens that are needed for balancing.

12:57 amalloy: uh. that second sentence has a lot of words but i can't put them together in a meaningful way

12:58 edw: amalloy: In other words, C-k is being bound to paredit-kill. It's just not working properly.

12:58 amalloy: hm

12:59 edw: (foo |bar) + C-k should result in (foo |) but paredit reports an error and fails to kill "bar".

13:00 (Pipe = "point on next character")

13:00 amalloy: edw: yeah, i know. what error does it report? and does it work for (foo baz |bar)?

13:01 edw: It reports an unbalanced paren error. And no, doesn't work for any kill that requires intelligently killing a partial line.

13:02 amalloy: and if you switch to lisp-mode+paredit it works?

13:03 edw: Hold on... Lemme write some elisp...

13:04 Yup, it works fine in elisp mode.

13:05 With paredit...

13:05 amalloy: bummer

13:07 edw: In fact, if I switch the buffer from clojure-mode to lisp mode, paredit works fine.

13:08 amalloy: well, i'll try upgrading to latest git and see if i have problems

13:08 edw: I pulled from github like 30 min ago.

13:09 amalloy: right. i pulled a few days ago, and it looks like there are one or two irrelevant changes

13:09 rather, i suppose i pushed a few days ago :P

13:09 gfrlog: do defrecords have to be (import)ed?

13:09 that seems strange to me because I always thought of (import) as an interop thing

13:10 TimMc: gfrlog: they do

13:10 gfrlog: okeedokes then

13:10 things are not always what they seem

13:10 amalloy: gfrlog: defrecord is an interop thing too

13:10 it defines a java class

13:11 gfrlog: but isn't there reason to use it even when you're not otherwise interacting with Java?

13:11 ataggart_: With the defrecord changes in 1.3, I suspect less need to import the record classes

13:11 amalloy: gfrlog: it's a point you could argue either way on

13:11 ataggart_: gfriog: records are java classes, hence importing

13:12 but master branch has factory functions, so you could just require/use the relevant ns

13:12 gfrlog: yeah, I know that they're java classes; I just figured that they were also clojurey things and so might have some...special stuff....

13:12 amalloy: edw: unfortunately for you, still works for me on 1.9.0

13:13 ataggart_: gfriog: try out clojure master. Also see http://dev.clojure.org/display/design/defrecord+improvements

13:13 technomancy: edw: I'm getting that with 1.9.0 too =\

13:13 amalloy: technomancy: getting what? the buggy behavior?

13:13 technomancy: amalloy: yeah, error on C-k

13:14 amalloy: wth. why would it work for me, then. can one of you try checking out b53390 and see if it's still broken?

13:16 gfrlog: man now I feel bad for using records pre 1.3

13:17 technomancy: amalloy: works fine on b53390

13:18 gfrlog: ,(doc print-dup)

13:18 clojurebot: "; "

13:18 amalloy: rrrrgh. then it's probably my fault *somehow*

13:19 technomancy: amalloy: confirmed it's 4495e =\

13:19 dnolen: gfrlog: amalloy: defrecord, type, protocols are definitely not "an interop thing"

13:19 technomancy: not sure how I didn't catch it sooner

13:19 amalloy: technomancy: that one is known to be buggy. db908 fixes a bug in that

13:20 dnolen: gfrlog: defrecord has a lot of clojurey stuff

13:20 technomancy: huh

13:20 gfrlog: dnolen: yeah, this improvements doc is exactly the kind of stuff I was thinking about

13:21 amalloy: if i could, i would rebase-squash db908 into 4495e so nobody can ever use it :P

13:33 gfrlog: records are making me consider using (get) for all map accesses :(

13:34 amalloy: gfrlog: (:foo m) is easier than (m :foo) since it works for records too

13:34 gfrlog: it is

13:34 I guess that's good when I have literals

13:34 amalloy: gfrlog: it works when you don't, too?

13:34 gfrlog: but if it's a generic algorithm that can't assume the keys are keywords

13:34 amalloy: ah

13:35 gfrlog: then traditionally I would use (m k) instead of (k m)

13:35 but now it could be a record in which case (m k) doesn't work either

13:35 stuff about to get clunky

13:36 amalloy: yeah, get is the only real choice. you want to get things from an arbitrary k/v store

13:36 gfrlog: I can't think of a reason why records shouldn't be IFns just like maps...

13:36 oh wait

13:36 I guess you might want to do IFn yourself for some unrelated purpose?

13:37 amalloy: gfrlog: you lose perf

13:37 records don't encourage slow usages of them

13:37 gfrlog: you lose performance if they're IFns at all, or just if you use them that way?

13:37 amalloy: and treating them as ifn couldn't be nearly as fast as using the keyword and/or hinted field access

13:37 the latter

13:38 gfrlog: don't we prefer slick-looking code before performance?

13:38 amalloy: yes. so use a hash-map, not a record, please :P

13:38 records exist *specifically* for perf

13:38 gfrlog: oh.

13:38 ...and for programming to interfaces?

13:39 amalloy: reify, deftype...i mean, yes, they're good for interop too

13:39 gfrlog: I guess you can do that with maps too...

13:40 * gfrlog goes to remove the defrecord from his code

13:40 amalloy: yay

13:40 gfrlog: man I was feeling all good about having safer and more structured code

13:41 amalloy: you didn't really, though

13:41 cemerick: If the keys in your domain aren't "names" (broadly writ), then records were never really appropriate.

13:41 amalloy: you can still assoc/get arbitrary fields in a record

13:42 gfrlog: it does all feel a little loose. Maybe getting older and retreating to static languages is like getting older and becoming a conservative

13:43 I was just thinking the other day it'd be nice to have a jvm language that's static like scala and immutable/concurrent like clojure and something like haskell

13:43 dnolen: amalloy: gfrlog: you might want to do IFn yourself, has nothing to do w/ perf.

13:44 amalloy: those things aren't for interop, you gotta stop saying that.

13:44 gfrlog: dnolen: what's not for interop? records?

13:44 amalloy: dnolen: explain?

13:44 dnolen: gfrlog: deftype/record, protocols have nothing to do w/ interop.

13:44 gfrlog: yeah I never thought they did

13:45 I thought protocol/record was about programming to interfaces, while deftype was about clojure-in-clojure

13:45 dnolen: gfrlog: deftype is not about clojure-in-clojure tho it's useful for that too.

13:46 gfrlog: what else is it about?

13:46 dnolen: gfrlog: light weight data structures.

13:46 cemerick: gfrlog: Horse's mouth: http://clojure.org/datatypes :-)

13:46 amalloy: edw: what version of emacs are you using?

13:46 gfrlog: cemerick: yeah, that's where I got my impressions from

13:46 cemerick: any discrepancies are due to cognitive limitations

13:47 edw: 24.0.50.1. Ubuntu + OS X.

13:47 cemerick: gfrlog: welcome to the club. We're having jackets made.

13:47 edw: (Just got back, btw,(

13:47 gfrlog: cemerick: gonna think real hard about what color mine should be, but not sure if I can figure it out

13:49 edw: When I tried it under Ubuntu and flakiness resulted, I went to my OS X install and tried it. Same problem.

13:53 dnolen: gfrlog: amalloy: the statement that IFn will be slower than the provided keyword access is also not true.

13:53 gfrlog: dnolen: he was probably contrasting with direct field access

13:53 but that's a good point, since keyword access is provided

13:54 I'm not sure whether it's better to leave off the IFn implementation for consistency, or allow the user to override it

13:55 dnolen: gfrlog: done properly IFn can be made nearly as fast as direct access. milliseconds of difference even at 1e8 iterations.

13:56 gfrlog: that sounds like a good thing.

13:59 amalloy: edw: update: it works on emacs 23, but not 24. working on figuring out why

14:00 dnolen: gfrlog: amalloy: https://gist.github.com/983429

14:02 gfrlog: dnolen: Think I'm gonna have to run that more like 100000 times before the numbers mean anything to me

14:02 oh wait

14:02 I just saw the outer bit

14:02 edw: amalloy: Thanks for looking into this. FWIW, clojure-plug-in fails on the Emacs that ships with Snow Leopard, but does anyone even use that?

14:03 technomancy: edw: emacs 22?

14:03 edw: Ah yes.

14:04 technomancy: that's 4 years old; strongly considering dropping support for it across the board

14:04 gfrlog: dnolen: when I run it, the direct access version gets up to ten times faster

14:05 edw: technomancy: The 18 yo, comp sci freshman from '91 in me cries a little tear.

14:05 gfrlog: now that I think about it these numbers are rather disturbing...

14:06 dnolen: gfrlog: not on my setup, OS X 10.6 JDK 7 64bit

14:06 gfrlog: it is saying that clojure did something 100,000,000 times in 0.002374 milliseconds?

14:07 ataggart: lazy?

14:07 clojurebot: lazy is hard

14:07 gfrlog: ataggart: nope, dotimes

14:07 ataggart: quantum computer?

14:07 dnolen: gfrlog: my point is simply that this is the kind of thing that the JVM can detect and aggressively optimize.

14:08 method dispatch is cheap, if is cheap, identical? is cheap.

14:08 gfrlog: dnolen: that sounds plausible, but 1) my computer reports different times, and 2) how the hell are these times so low for so many operations?

14:08 amalloy: dnolen: case is surely faster than cond there?

14:08 dnolen: amalloy: it is not.

14:08 amalloy: but yes, fair point

14:09 dnolen: gfrlog: vtable lookup, 3 branch tests, integer comparison, doesn't sound like the computer has to do much.

14:10 gfrlog: dnolen: I changed it from 1e8 to 1e9 and it got faster

14:10 I don't think those are physically realizable times even in assembly

14:11 dnolen: times for 1e5 are about the same as 1e9

14:11 something else is going on

14:11 dnolen: gfrlog: not on my machine, 1e5 is 0.08 milliseconds for me.

14:11 gfrlog: so 1e8 should be 80 milliseconds

14:12 TimMc: gfrlog: 1.763 sec and 0.358 sec for me (1e8)

14:12 dnolen: gregh: it's 70ms on my machine which is what you'd expect.

14:12 oops.

14:13 gfrlog: I'm getting 0.005 msecs for just about everything

14:13 which is insane.

14:13 dnolen: gfrlog: what's your setup?

14:13 technomancy: edw: is 22 commonly used? I guess I honestly don't know.

14:13 TimMc: gfrlog: Can you factor some numbers for me? :-P

14:13 gfrlog: uh some kinda thinkpad

14:13 ubuntu 64 bit

14:13 okay let's see

14:13 if something does 100 million operations in 0.01 milliseconds

14:13 lemme ask wolfram alpha what that is

14:14 TimMc: 10 GHz

14:14 gfrlog: that's all?

14:14 ataggart: dnolen: case should be faster than cond for keywords and (in master) int-sized integers.

14:14 dnolen: ataggart: yeah I'm on alpha7

14:15 gfrlog: TimMc: WA says 10 terahertz

14:15 TimMc: gfrlog: Ah, you're right... milliseconds, not seconds.

14:15 gfrlog: http://www.wolframalpha.com/input/?i=1e8+%2F+%280.01+milliseconds%29

14:16 so like I said, this is not physically realizable even if we optimize it to one instruction per field access

14:16 TimMc: gfrlog: So... you can crack some rar files for me, yeah? :-P

14:16 gfrlog: nobody else is getting those numbers?

14:17 here's my output: https://gist.github.com/983477

14:18 dnolen: gfrlog: perhaps your JVM sees that the loop doesn't do anything.

14:18 gfrlog: that's the only thing I can conclude

14:18 so I think we need a different way to compare the performance

14:18 I was watching disclojure the other day and he did something similar

14:19 was measuring the performance of different (rotate) functions, but they were both lazy and I don't think he ever consumed them

14:59 manutter: part

14:59 doh, that's the second time I've done that.

15:00 offby1: could have been worse

15:10 arj: does anyone know how to handle java.nio.channels.ClosedChannelException in aleph?

15:26 gfrlog: is there a strong use case for reader-evaluation?

15:59 TimMc: gfrlog: What is reader-evaluation?

16:00 amalloy: yes

16:00 it lets you define print-dup for new types

16:00 TimMc: #= notation

16:02 TimMc: Ah, that.

16:03 gfrlog: huh.

16:04 ataggart: disabled by binding *read-eval* to false

16:06 TimMc: How do I get a reader again?

16:06 amalloy: &(read-string "1")?

16:06 sexpbot: ⟹ 1

16:06 TimMc: thanks

16:06 I tried read and read-str. :-P

16:06 gfrlog: amalloy: does "defining print-dup for new types" mean serializing something as a string that starts with #=(...)?

16:07 amalloy: yes

16:07 $google amalloy xml json clojure

16:07 sexpbot: First out of 14 results is: Don't use XML/JSON for Clojure-only persistence/messaging

16:07 http://hubpages.com/hub/Dont-use-XML-JSON-for-Clojure-only-persistence-messaging

16:07 gfrlog: okay. I guess that is a good use.

16:07 amalloy: gfrlog: ^ has an example

16:08 TimMc: And I suppose the de-serializer has to have the right environment for the evaluation to succeed.

16:08 gfrlog: amalloy: that there is a good dang example

16:08 ataggart: recently added to master is support for literal construction of arbitrary types, so you don't need to add a print-dup

16:08 gfrlog: yeah that part is not immediately clear

16:08 I at first assumed you'd just get clojure.core etc.

16:09 ataggart: correction, don't need to use the read-eval macro

16:09 gfrlog: what? we got a finger-tree syntax now?

16:09 amalloy: &(binding [*print-dup* true] (pr-str *ns*)) ;; gfrlog

16:09 sexpbot: ⟹ "#=(find-ns sandbox11964)"

16:09 amalloy: TimMc: how do you mean?

16:09 gfrlog: amalloy: holy cow!

16:10 TimMc: amalloy: Oh, for instance your constructor function would need to be in scope.

16:10 And isn't there something about eval not getting lexical stuff?

16:10 gfrlog: yeah it's probably just the deffed stuff

16:10 amalloy: yes, print-dup is very much not intended for use with lexical anything

16:10 gfrlog: but I think that'd be okay

16:10 amalloy: it's for persisting objects

16:11 * gfrlog wanders off to get a milk shake. not because he's uninterested, but because he really wants a milk shake

16:11 amalloy: &`String

16:11 sexpbot: ⟹ java.lang.String

16:11 TimMc: &(type `String)

16:11 sexpbot: ⟹ clojure.lang.Symbol

16:11 TimMc: right

16:12 amalloy: TimMc: that's why the recommended way to implement print-dup is like ##(str "=#" `(String. 10))

16:12 sexpbot: ⟹ "=#(java.lang.String. 10)"

16:12 amalloy: means you don't need to have String imported in order for reading to work

16:13 TimMc: I bet it works even better with #= instead of =#. :-)

16:13 Ah, nice trick.

16:13 ataggart: is there a bot running master?

16:13 amalloy: ataggart: neither sexpbot nor clojurebot

16:13 ataggart: k

16:16 hiredman: I'd like to have clojurebot's sandbox run has a seperate process, possibly connected via queue, which would make changing the version of clojrue available much easier, and possibly support multiple versions, just have work and five or six other projects and life competing for time :/

16:17 amalloy: ataggart: what's needed to get master running? git fetch, compile, mvn install, then depend on that version?

16:18 ataggart: I think alpha7 is only one commit back from master, you can just use that

16:18 amalloy: i'll fire up my fork of sexpbot with alpha7 if you want

16:18 ataggart: but otherwise, yes

16:18 oh I was just curious. no need to bother

16:18 amalloy: otoh it uses contrib stuff and i don't know how to migrate

16:18 ah

16:19 ataggart: I have master local anyway. bugs aren't gonna close themselves.

16:19 amalloy: ataggart: since i have you here, what is the story for using contrib in 1.3? if i have a project that needs pr-xml, can i just use alpha7 and contrib 1.2?

16:20 ataggart: thinking...

16:20 arohner: amalloy: I think I had problems with that because of some AOT code

16:20 ataggart: the only issue you might run into is that *foo* won't be dynamically rebindable

16:22 acually there are quite a few breaking changes, but you're unlikely to run into them. the ^:dynamic thing is main one.

16:22 amalloy: yeah, i've been tagging my code with :dynamic in preparation for eventually migrating

16:22 though pr-xml probably doesn't

16:23 yeah, looks like it doesn't. i guess i can patch that myself, except i don't know where i'd send the patch to

16:25 ataggart: amalloy: is this what you're referring to? http://richhickey.github.com/clojure-contrib/prxml-api.html

16:31 amalloy: yes

16:31 gfrlog: amalloy: print-dup couldn't be used to print reconstructible lazy seqs could it? because there's already a seq implementation?

16:31 amalloy: ataggart: in contrib 1.2.0 it includes things like (def ^{:private true} *prxml-tag-depth* 0)

16:34 gfrlog: print-dup is a multimethod; you can derive it

16:34 but it would be hard, if not impossible, to do in general

16:34 gfrlog: right, I'm just thinking special cases like iterate

16:35 amalloy: gfrlog: and if the base case of iteration is itself a lazy-seq?

16:35 gfrlog: punt

16:35 * amalloy returns for touchdown

16:35 arohner: anyone have experience using c.c.zip-filter.xml?

16:36 amalloy: arohner: very briefly, several months ago

16:36 * gfrlog is down by seven points

16:36 amalloy: gfrlog: six. i'm a terrible kicker

16:36 gfrlog: you could get half of a two-point-conversion

16:36 arohner: amalloy: I can't figure out why chouser's examples in c.c.z-f.x.clj don't require zf/descendants, but all of my code does

16:38 amalloy: arohner: possibly xml1-> instead of xml->?

16:39 TimMc: clojure.core.zermelo-fraenkel.xml ?

16:39 gfrlog: TimMc: of course

16:39 that's the version without AOC

16:39 TimMc: with, I believe

16:40 gfrlog: no with you want "zfc"

16:40 TimMc: Ah! Right.

16:40 dnolen: so who's gonna implement Generic Zippers for Clojure? http://okmij.org/ftp/continuations/zipper.html

16:40 arohner: amalloy: that only seems to affect whether I get "foo" or ("foo"), it doesn't change whether descendants is needed

16:40 TimMc: From an infinite directory of XML file, pick one element from each.

16:41 amalloy: arohner: i'm short on psychic powers. can you gist some of your code and a sample of your xml?

16:41 gfrlog: TimMc: and then use them to duplicate a spherical xml file

16:42 hiredman: dnolen: what is the difference between that and clojure.zip?

16:42 dnolen: hiredman: clojure.zip doesn't work w/ all data structures right?

16:42 amalloy: dnolen: it's pluggable, no?

16:43 hiredman: ,(doc clojure.zip/zipper)

16:43 clojurebot: "([branch? children make-node root]); Creates a new zipper structure. branch? is a fn that, given a node, returns true if can have children, even if it currently doesn't. children is a fn that, given a branch node, returns a seq of its children. make-node is a fn that, given an existing node and a seq of children, returns a new branch node with the supplied children. root is the root node."

16:43 wastrel: is clojurebot written in clojure

16:43 amalloy: yes

16:44 gfrlog: is sexpbot witten in sexp?

16:44 ataggart: dnolen: clojure.zip should make sense for any structure for which left/right/up/down make sense

16:44 dnolen: hiredman: amalloy: doesn't the returned zipper only work on one type?

16:44 wastrel: sexybot eh.

16:44 amalloy: dnolen: define branch as a multimethod if you have mixed data types?

16:44 TimMc: gfrlog: Why yes it is.

16:44 dnolen: correct me if I'm wrong, but there is no zipper for [{}]

16:45 ataggart: dnolen: maps don't fit since left/right doesn't apply

16:45 dnolen: ataggart: k no zipper for [()]

16:45 hiredman: some people have done zippers for maps, but there is not universal accepted zipper for them

16:46 amalloy: &(clojure.zip/zipper sequential? seq list [()])

16:46 sexpbot: ⟹ [[()] nil]

16:46 amalloy: dnolen: ^ should be able to traverse that structure just fine

16:46 dnolen: amalloy: does the zipper preserve the types?

16:46 amalloy: yes

16:47 hiredman: amalloy: I don't think it will

16:47 ataggart: newly added child types depend on what make-node fn you gave it

16:47 amalloy: i could be wrong, then

16:47 hiredman: any edits will turn the outer [] into a list

16:47 since you gave it the list function for constructing nodes

16:47 amalloy: hiredman: ah. yes, you're right for edits

16:47 it should preserve types for walking though, right?

16:49 dnolen: anyways, good argument for real generic zipper. would also put walk to it's much needed rest.

16:50 gfrlog: buncha clojure folk going to strange loop?

16:50 timvisher: hey all

16:50 hiredman: ,(require '[clojure.zip :as z])

16:50 clojurebot: nil

16:50 timvisher: is it possible to import package.foo.*?

16:51 ataggart: no

16:51 dnolen: timvisher: no

16:51 timvisher: whoo!

16:51 ok

16:51 hiredman: ,(-> [()] (zipper sequential? seq list))

16:51 clojurebot: java.lang.Exception: Unable to resolve symbol: zipper in this context

16:51 timvisher: thanks :)

16:51 amalloy: hiredman: ->>, btw

16:51 hiredman: ah, right, ahem

16:52 ataggart: timvisher: if you're using emacs, check out https://github.com/technomancy/slamhound

16:52 or nvm, emacs not required

16:52 amalloy: lein, though

16:52 ataggart: time to go stock up for the canucks game

16:53 hiredman: clojure.zip also tends to have bugs, since it isn't used a lot

16:53 technomancy: you can use it from the repl; kinda a pita though

16:54 amalloy: i wonder if whatever was breaking my slamhound/emacs integration has fixed itself yet

16:55 hiredman: ,(-> (z/zipper sequential? seq list '(())) z/next (z/replace ()) z/root)

16:55 clojurebot: ((()) (()))

16:55 amalloy: hiredman: that's not a bug, is it?

16:56 hiredman: amalloy: I believe it is, should result in (())

16:56 amalloy: oh. i was assuming root returned the zipper, not the node

16:56 hiredman: ,(-> (z/zipper sequential? seq list '(())) z/nex z/node)

16:56 clojurebot: java.lang.Exception: No such var: z/nex

16:57 hiredman: ,(-> (z/zipper sequential? seq list '(())) z/next z/node)

16:57 clojurebot: ()

16:57 hiredman: if I replace () with () I should get (()) out again

16:57 amalloy: yeah, i think you're right

16:57 hiredman: lots or corner cases

16:58 amalloy: hiredman: might be caused by (seq ()) yielding nil instead of (), i dunno

16:58 ,(-> (z/zipper sequential? identity list '(())) z/next (z/replace ()) z/root)

16:58 clojurebot: ((()) (()))

16:59 amalloy: guess not

16:59 hiredman: *shrug*

16:59 amalloy: oh. my use of (list) is what's broken

16:59 ,(-> (z/zipper sequential? identity identity '(())) z/next (z/replace ()) z/root)

16:59 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (2) passed to: core$identity

17:00 amalloy: ,(-> (z/zipper sequential? identity (fn [node children] children) '(())) z/next (z/replace ()) z/root)

17:00 clojurebot: (())

17:00 hiredman: ah, so you could use multimethods to create a generic zipper

17:00 amalloy: yes, it looks like

17:01 hiredman: dnolen: so done

17:01 amalloy: hiredman: the power of clojure: you and i implemented a generic zipper in just ten minutes :)

17:01 the time it took to discover that one already exists

17:06 dnolen: anyway the conclusion is you can make a fully generic zipper in the existing framework with just multimethods or protocols

17:11 stuartsierra1: Announcement: Clojure builds on JRockit 1.5, but the tests don't pass.

17:11 dnolen: stuartsierra1: very cool.

17:12 * hiredman has been doing all his work realated builds/test runs on jrockit

17:13 dnolen: stuartsierra1: is there a specific nature to those tests that fail?

17:13 hiredman: so far the only difference is jrockit is slower to start

17:14 arj: clojure is jrockingIt :-)

17:14 stuartsierra1: dnolen: something related to I/O classes, but I'm not sure what yet.

17:14 dnolen: hiredman: benefits?

17:15 amalloy: ah, I follow now, cool!

17:15 hiredman: dnolen: none so far

17:16 dnolen: generic zipper via protocols blogpost brewing ...

17:16 pjstadig: can someone explain to me why i should be excited about jrockit?

17:16 amalloy: the name sounds a lot like rocket

17:16 that's exciting enough for me

17:17 seancorfield: does alex taggart hang out here much? i have a Q about clojure.tools.logging

17:17 hiredman: ~seen ataggart

17:17 stuartsierra1: I think the excitement is about the potential for various JVM commercial enhancements becoming open source in the near future.

17:17 clojurebot: ataggart was last seen in #clojure, 24 minutes ago saying: time to go stock up for the canucks game

17:17 amalloy: seancorfield: he's here pretty often. was here just half an hour ago or so

17:17 seancorfield: darn... my timing sucks :)

17:19 pjstadig: stuartsierra1: ok...so that leads to my next question...why should i be excited about jrockit?

17:19 are there actual features that add value?

17:19 stuartsierra1: Probably not yet.

17:20 For certain applications, it may offer faster performance and better garbage collection strategies.

17:20 pjstadig: ok ... that's cool

17:20 that sounds more incremental to me than revolutionary...the way people have been raving about the announcement

17:21 the JRockit Virtual Edition looks kinda cool

17:21 technomancy: pjstadig: maybe it has more to do with shock that oracle is doing something right

17:21 stuartsierra1: yes, what technomancy said

17:21 It's a positive sign for the future of the JVM under Oracle, which had a lot of people nervous.

17:21 pjstadig: duly noted

17:33 wastrel: the clojure list is filling up my inbox :p

17:34 technomancy: digest mode. it changed my life.

17:34 amalloy: i just subscribe to the rss feed and tell it not to email me

17:35 pjstadig: yeah i've done digest mode for a while

17:35 clojure-dev is low volume and high enough signal-to-noise that i'll take that as single messages

17:39 amalloy: i don't get it. do you receive them straight in your regular inbox mingled with the rest of your mail? that's the only way i could see the volume being prohibitive, and it's easily fixed by adding a filter

17:39 danlarkin: aye, I filter all mailing lists into their own folders

17:39 and browse at my convenience

17:39 don't be a slave to your email!

17:40 technomancy: sometimes it's hard to ignore the fact that there's a number in the sidebar!

17:40 amalloy: i try to avoid receiving mail from mailing lists, and read them as rss/news, but same idea

17:40 technomancy: even if it isn't in the inbox

17:40 pjstadig: yeah but if it's not coming into your inbox then you may never read it

17:40 amalloy: pjstadig: sounds like that's exactly what you want :P

17:40 pjstadig: so you might as well take a digest

17:40 danlarkin: I have 33 thousand unread emails in my clojure mailing list folder

17:40 pjstadig: or just unsubscribe and search for what you want

17:40 danlarkin: my point exactly

17:40 just do the digest

17:41 amalloy: digests aren't as easy to work with. you can't have your mail client filter by thread, for example

17:41 danlarkin: exactly

17:41 technomancy: yeah... once I get back to gnus I'll probably go back

17:41 amalloy: or by sender. one day soon i'll get tired of ken wesson

17:41 pjstadig: i scan the ToC for any interesting threads an click the links to read them on the google groups site

17:41 technomancy: gnus lets you just chew through mailing lists like nobody's bizniss

17:41 pjstadig: i can scan 10's of messages in the blink of an eye

17:42 danlarkin: I only read threads I'm interested in

17:42 to each his own I guess

17:42 pjstadig: right...

17:42 so just do the digest

17:42 danlarkin: ...but my way is obviously better

17:42 pjstadig: no its not

17:42 it's worse

17:42 amalloy: *baffled*

17:42 pjstadig: actually i don't really care

17:49 dnolen: it's funny because according to google groups the peak of ML activity happened around Jan 09.

17:51 technomancy: back in the day you couldn't really use clojure without following the list though

17:51 dnolen: around which time I was posting horrible dribble about adding OO inheritance to structs.

17:52 * danlarkin remembers thinking it was genius

17:52 danlarkin: silly, silly times

17:52 technomancy: we all have our embarassing pasts

17:53 pjstadig: hehe

17:57 amalloy: one of my first posts was about how to create circular structures for quickly looking up "all Xs in group G" and "what group is element X in"

17:57 i'm still not entirely sure how i ought to have done that

17:58 danlarkin: two hash maps

17:58 amalloy: danlarkin: i might prefer one hashmap

17:59 hiredman: with some kind of composite keys?

18:00 amalloy: hiredman: there was no danger in my use-case of needing the same key more than once. eg, all Xs have "ids" that are strings, and all Gs have "ids" that are ints

18:00 hiredman: {[:group 'G] 'xs [:element 'x] [:group 'G]}

18:01 amalloy: *nod*

18:01 but you don't even need the :element/:group classifiers if there's never any overlap

18:01 {'G 'xs 'x 'G}

18:02 two hashmaps might be less unwieldy in practice, though. i don't remember exactly how i was going to use them; i haven't touched that project in a while

18:03 danlarkin: you could use the crazy db code I wrote for subrosa!

18:03 it "indexes" hash maps

18:03 * amalloy always jumps at the chance to use "that crazy ___ code"

18:04 danlarkin: I think it's actually pretty cool

18:04 I just have no documentation for it

18:04 which makes it pretty useless to anyone else

18:04 * amalloy is writing documentation for all the code he wrote before switching jobs

18:11 technomancy: te

18:11 oops

19:53 seancorfield: ataggart: i missed you earlier... had some Q's about tools.logging

19:53 ataggart: shoot

19:54 seancorfield: i have an app that currently does some fairly complex logging stuff - different levels going to different log appenders, including a DB log appender and an email log appender for different levels

19:54 it's not written in clojure right now

19:54 do you think it's worth creating a LogFactory for that and using tools.logging as i migrate the code around it to clojure

19:55 or should i just write custom logging functions

19:55 ataggart: what's the underlying implementation?

19:55 e.g., log4j

19:56 seancorfield: currently? mostly custom log appenders... the rotating file log appender may be based on log4j, possibly

19:56 the main difference i could see in approach is that what i'm using right now allows you to specify multiple log appenders per namespace

19:57 ataggart: well let's clear one thing up first, clojure.tools.logging doesn't actually do any logging. If your logging is based on log4j, then you can make your logging calls via tools.logging and it will automatically use log4j

19:57 seancorfield: so i figured i needed a custom LogFactory but i'm not sure whether it's worth the effort for the amount of customization we have in our app :(

19:57 i understand that

19:57 ataggart: k

19:58 I bring it up because the notion of appenders, etc., deals with the underlying implementation config

19:58 which is orthogonal to tools.logging

19:59 so the app you currently have is using its own custom stuff for logging or log4j?

19:59 seancorfield: like i say, i think part of it is using log4j

19:59 but it also has logging to the database and logging via email, all for different levels

19:59 ataggart: is the latter stuff also configured via log4j?

20:00 seancorfield: and the ability to have logging for a specific namespace go to multiple places

20:00 not yet... but if i can standardize it all on log4j it might be worth the effort

20:00 ataggart: yeah, I'd suggest that

20:00 seancorfield: i'm not familiar enough with log4j (yet)

20:00 ataggart: then you let the config do the work of routing stuff around.

20:00 seancorfield: so i'd hate to write a bunch of custom code, only to find i _could_ leverage something standard :)

20:01 so i might not even need to write a LogFactory...?

20:01 ataggart: I'm fairly sure any logging you want to do someone has already done an appender for

20:01 and yeah, no need to write a custom LogFactory

20:01 log4j is already provided

20:02 as is apache commons-logging, slf4j, and java.util.logging

20:02 seancorfield: at some point we want to be able to log arbitrary maps of data to a noSQL store as one of the appenders...

20:02 ataggart: tools.logging doesn't force anything to be a string

20:03 unless the underlying impl requires it

20:03 so if the "message" is a map, that object should make it to the underlying impl

20:04 seancorfield: as long as i use (log ...) and not (trace ...) etc?

20:04 those seem to call (logp ...)

20:04 ataggart: ya

20:04 seancorfield: 'k, good to know

20:04 log4j doesn't seem to support logging to a DB...?

20:05 ah, that's an optional extra...

20:07 very optional it seems... hmm... maybe i will end up writing my own log appenders after all...

20:08 there's a DBAppender available but it uses a very specific format that doesn't match what we want / already use

20:09 ataggart: it's been a while since I looked but it was fairly straightforward

20:09 seancorfield: it'll be a nice challenge to write a log appender in clojure for use with log4j :)

20:10 or i might just write a custom LogFactory and wrap log4j so i can still delegate to it for all the things it can do...

20:11 ataggart: how is the db appender currently configured?

20:16 seancorfield: not thru log4j

20:16 the current logging implementation mimics a lot of log4j it seems

20:16 it's a 3rd party logging library

20:17 looks like i can do most / all of what i want with standard log4j as long as i don't mind writing a custom appender for some of our more esoteric stuff...

20:17 it'll be a long weekend of research i suspect :(

20:19 ugh! now i dig into this third party code, it does not actually use log4j, it pretty much replicates the entire thing :(

20:20 good grief... it's a near-complete port of log4j... why oh why would they do that :(

20:21 oh well, dinner and a few beers and then i'll start to tackle that...

20:22 ataggart: heh have fun

20:22 ,(doc with-meta)

20:22 clojurebot: "([obj m]); Returns an object of the same type and value as obj, with map m as its metadata."

20:23 amalloy: ataggart: the only with-* in clojure.core that doesn't establish dynamic scope

20:28 ataggart: amalloy: elaborate please

20:28 amalloy: ataggart: with-open, with-bindings, etc, all deal with dynamic vars

20:29 ataggart: hmm, yeah, some form of "set" seems appropriate

20:30 amalloy: &(->> (ns-map *ns*) (map (comp name first)) (filter #(.startsWith % "with-")))

20:30 sexpbot: java.lang.SecurityException: You tripped the alarm! ns-map is bad!

20:30 amalloy: ,(->> (ns-map *ns*) (map (comp name first)) (filter #(.startsWith % "with-")))

20:30 clojurebot: ("with-open" "with-in-str" "with-meta" "with-out-str" "with-loading-context" "with-bindings*" "with-precision" "with-local-vars" "with-bindings")

20:31 amalloy: ataggart: this is not my own insight; chouser posed it as a puzzle some time ago

20:43 hiredman: you could argue that the meta data create with with-meta has dynamic extent, even more dynamic than bindings created with binding, while the metadata created with-meta has no scope limitations

20:44 but that would be a ridiculous argument

21:54 hugod: seancorfield: you might also want to look at logback http://logback.qos.ch/, which has an slf4j api - it has a sifting appender, and allows multiple contexts for a log message (MDC)

22:01 davidplumpton: Anybody got a couple of minutes to give me some feedback on how to make this code more idiomatic? https://github.com/davidplumpton/alert-sim/blob/master/sa.clj

22:20 seancorfield: thanx hugod

22:27 jweiss: is there a way to 'flatten' that also will flatten sets?

22:27 i want to flatten a sexp to get all the symbols out of it, including those used in list/map/set literals.

23:19 seancorfield: quick java interop Q: i have an abstract class (in java) that I want to complete in clojure - possible? how? (a pointer to an example or the appropriate bit of docs is fine)

23:19 i thought reify would work but that requires an interface

23:20 is it proxy?

23:22 this seems to work: (def test-logger (proxy [AppenderSkeleton] [] (append [event] (println (.getMessage event)))))

23:22 now i just need to figure out how to get log4j to use my clojure appender :)

23:42 mprentice: i added clojure-contrib to the classpath in ~/.lein/bin/swank-clojure, so i could develop one-off scripts with lein oneoff but still have contrib in my repl

23:42 seancorfield: w00t!!! log4j is now using my clojure "class"

23:42 mprentice: is there a plugin like swank-clojure that includes contrib already?

Logging service provided by n01se.net