#clojure log - Oct 22 2009

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

0:58 technomancy: jlilly: I've never noticed any difference between openjdk and sun's.

0:58 I think the only difference is in some desktop-app font rendering

0:59 jlilly: $CLASSPATH and -cp are mutually exclusive IIRC

0:59 generally the env var is discouraged

1:01 mikehinchey: I found one problem with openjdk, something about clojure.contrib.jmx, I posted to clojure-dev. But I've used openjdk a lot with clojure.

1:23 jlilly: technomancy: I got it all sorted out.

1:24 thx though.

2:00 hiredman: hah!

2:01 I can run ant, and the first time clojure will build using LispReader, then run ant again and clojure will build using my reader written in clojure

2:02 now I just need to get rid of all the calls to LispReader/* in my reader written in clojure

2:05 http://github.com/hiredman/clojure/tree/readerII

2:35 mikehinchey: hiredman: that's a good way way of putting it :)

3:32 angerman: how would I turn (a b c d) -> (d a b c) ?

3:36 hiredman: ,((fn [x] (conj (butlast x) (last x))) '(a b c d))

3:36 clojurebot: (d a b c)

3:38 angerman: ahh, butlast

5:26 G0SUB: I was just wondering, what is the problem in introducing optional (and/or) keyword arguments to Clojure?

5:29 They are quite useful sometimes.

5:31 cgrand: GOSUB: perfs and interop

5:31 G0SUB i mean

5:32 G0SUB: cgrand: interop with what?

5:32 cgrand: java

5:32 G0SUB: cgrand: and is perf a real issue?

5:33 cgrand: on each call? I think but I haven't thought too far about how it could be implented.

5:34 G0SUB: hmm

5:34 cgrand: G0SUB: but you could mimick them with maps and/or macros

5:36 (fn [{:keys [opt1 opt2 opt3] :or {:opt3 42}}] ...)

5:36 arbscht: G0SUB: you have optional arguments with arity overloading, and something like keywords with hash destructuring (or c.c.def/defnk). that covers a lot of cases

5:37 G0SUB: cgrand: as far as mimicking keyword args, I don't like that fact that I have to call a fn like (myfn {:a 1 :b 2}) and not (myfn :a 1 :b 2)

5:37 arbscht: hmm, let me look again.

5:38 AWizzArd: Strange... I am using htmlunit and do (.asText #^HtmlPage (.getPage webclient url)) and this results in a reflection warning "reference to field asText can't be resolved". But when I do (let [p (.getPage webclient url)] (.asText #^HtmlPage p)) then I get no reflection warning.

5:38 cgrand: maybe you have an idea why it is that way?

5:43 cgrand: G0SUB: (fn [& args] (let [{:keys [opt1 opt2 opt3] :or {:opt3 42}} (apply hash-map args)] ...)) ; and I think that's more or less what defnk macroexpands to

5:44 G0SUB: cgrand: OK. thanks. I will take a look at defnk.

5:47 cgrand: AWizzArd: yes I see what's the problem is. macro and inline expansion make type hints disappear

5:49 (meta '#^HtmlPage (.getPage webclient url))

5:49 ,(meta '#^HtmlPage (.getPage webclient url))

5:49 clojurebot: {:tag HtmlPage}

5:49 cgrand: ,(meta (macroexpand-1 '#^HtmlPage (.getPage webclient url)))

5:49 clojurebot: nil

5:49 cgrand: ,(macroexpand-1 '#^HtmlPage (.getPage webclient url))

5:49 clojurebot: (. webclient getPage url)

5:50 cgrand: AWizzArd: can't you just hint webclient?

5:51 AWizzArd: I will try that

5:51 cgrand: I guess if webclient (and maybe url) are propely hinted the return type of .getPage will be inferred to HtmlPage

5:51 AWizzArd: Although funnily getpage doesn't produce a complaint

5:52 I have a (let [webclient (WebClient.)] ...) so I thought webclient is implicitly hinted.

5:52 cgrand: can you paste with more context?

5:53 AWizzArd: Do you have htmlunit installed and setup in your classpath?

5:54 If yes I could hack up a minimal example for pasting into a .clj file which will demonstrate it.

5:55 But what I basically have is: (let [webclient (WebClient.), url (java.net.URL. "http://clojure.org/")] ... (.asText (.getPage webclient url)))

6:18 cgrand: AWizzArd: ok, looked at the javadocs .getPage returns a Page object so you must "downhint" it to HtmlPage

6:19 right now your let is the best workaround I can think of

6:22 AWizzArd: Yes, .getPage returns a Page. So in those cases, where a method returns an "instance of an Interface" (such as Page) the type hint info can get lost?

6:26 cgrand: rhickey: would you accept a patch to preserve (merge) metadata on macro (and inline) expansion? It would make some hinting headaches go away.

6:27 rhickey: cgrand: preserve which metadata?

6:28 on the form as a whole?

6:30 cgrand: yes actually type hints are lost when put on something that is expanded (macro, inline, .method), so I was thinking about merging metadata of the original form into the expanded form's metadata

6:32 AWizzArd: Currently it seems a work around is needed, such as (let [p (.getPage webclient url)] (.asText #^HtmlPage p)) ==> no reflection warning, vs (.asText #^HtmlPage (.getPage webclient url)) ==> can't resolve the call to .asText

6:34 rhickey: cgrand: you can't do that, but it would be nice to have a way to communicate it to the macro itself, so it could if it wanted. Right now there is no &whole-like thing

6:35 AWizzArd: cgrand: btw, if metadata would be preserved, would that also mean that there won't be reflection warnings anymore for things as (.replaceAll (with-out-str ...) ...)? Currently i need to (let [xyz (with-out-str ..)] (.replaceAll #^String xyz ...)) to prevent reflection.

6:39 esj: Hi everybody, please excuse a very naive question, but can anybody provide an explanation, or link to such, of the -> macro ? I'm struggling to find anything beyond (doc ->), which has, sadly, not enlightened me.

6:40 G0SUB: esj: (-> {} (assoc :a 1) (assoc :b 2))

6:40 esj: that expands to (assoc (assoc {} :a 1) :b 2)

6:40 esj: aha !

6:41 I get it, much obliged indeed.

6:41 AWizzArd: ,(macroexpand-1 '(-> 5 (+ 3)))

6:41 clojurebot: (+ 5 3)

6:41 G0SUB: esj: :)

6:42 arsatiki: esj: I think it's a sort of a enhanced reverse function composition

6:43 arbscht: -> it is not function composition

6:43 it simply rearranges code

6:43 arsatiki: yeah, that's why it's "sort of"

6:44 rhickey: (-> x a b c) => (c (b (a x)))

6:44 (-> x (a 1) (b 2) (c 3)) => (c (b (a x 1) 2) 3)

6:44 it just reduces nesting and lets you write things in the order in which they will occur, when that's convenient

6:45 G0SUB: woohoo! rhickey

6:45 * G0SUB bows

6:48 rhickey: -> threads the expr as first arg, ->> threads the expr as last arg: (->> x (a 1) (b 2) (c 3)) => (c 3 (b 2 (a 1 x)))

6:48 AWizzArd: rhickey: it would be so nice to have a function "pipe" that is like comp, but follows the sequence like -> does.

6:51 esj: Thanks very much everybody.

6:52 AWizzArd: Using comp often means to write "(comp fn1" then using the arrow keys to go left, editing it to become "(comp #(fn2 1 % 3) fn1", then again the arrow keys, etc.

6:55 rhickey: AWizzArd: since it's not a nesting issue, only arg order, not very compelling

6:57 AWizzArd: I see

6:58 Just found myself often using comp, which is not soo nice for editing and reading.

6:58 arsatiki: oh

6:58 I had the impression that comp use was pretty rare

7:03 AWizzArd: Maybe not soo often, but for example if your webserver was writing log files readably, containing json strings you maybe want to analyze them (map (comp read-json :text first read-string #(slurp % "UTF-8")) log-files)

7:04 liwp: it's very nice for things like that. it get's a bit messy if you have to use partial when your functions take more than one argument

7:04 AWizzArd: liwp: or using %1 %2 %3 or %*

7:04 Typically I don't use partial and instead the nice reader macro #(...)

7:05 liwp: AWizzArd: yep. I tend to prefer #() rather than partial

7:21 arsatiki: re: comp, partial -- I'm often impressed by the ease Haskell handles them (http://www.haskell.org/haskellwiki/Pointfree)

7:21 but honestly, sometimes pointfree is really pointless :)

7:23 G0SUB: What's the best way to unzip a file in Clojure?

7:33 AWizzArd: G0SUB: http://java.sun.com/javase/6/docs/api/java/util/zip/ZipFile.html

7:33 G0SUB: AWizzArd: yeah, looking at that itself :)

7:35 AWizzArd: you can do: (enumeration-seq (.entries (java.util.zip.ZipFile. (java.io.File. "c:/clojure/clojure.zip"))))

7:38 cgrand: rhickey: sorry, I have been called away. Why can't I do that?

7:46 G0SUB: AWizzArd: how do I handle directories and all?

7:46 AWizzArd: I want to use as much code from c.c as possible.

7:50 kunley: Hi.

7:51 Do we have Long literals in Clojure?

7:54 AWizzArd: kunley: (long 123456789)

7:54 rhickey: cgrand: because you don't know what the macro wants/needs - it may be creating something non-meta-supporting, or setting meta explicitly, expecting that to be the only meta on the expansion

7:55 kunley: doh.. likely need more coffee ;] thx!

7:56 AWizzArd: G0SUB: What do you mean, how do you handle directories?

7:57 The ZipEntries that .entries returns will list all files in all directories

7:57 G0SUB: AWizzArd: well, if the zip file has directories, how will the unzipping maintain the same dir structure?

7:58 AWizzArd: The java.io.File class has a (.mkdirs ...) method.

8:00 G0SUB: and you have a (.isDirectory some-entry)

8:01 G0SUB: hmm

8:01 AWizzArd: So if that returns true, then call (.mkdirs (File. (str some-entry))) and you will have the directory

8:02 I'm not sure if .entries *must* return the enumeration of ZipEntry's in such a way that a directory entry D will always come before entries that live in D.

8:03 G0SUB: AWizzArd: OK, got it. by the way, how do I figure out in which dir a file exists? Does File have a method for that?

8:03 AWizzArd: I would suggest you to filter all entries that are true for .isDirectory, then mkdirs those, and only then begin storing files in there.

8:03 G0SUB: AWizzArd: thanks for the tip.

8:04 AWizzArd: G0SUB: the (str your-entry) will return a string of the directory

8:04 plus file name

8:04 just play with it in the repl

8:04 cgrand: rhickey: don't you find surprising for the user to see his type hints ignored/discarded?

8:04 Concerning your two points: if the macro returns something non-meta supporting, a warning can inform the user his metadata is discarded. And for a macro setting meta explicitely (and expecting it to be the only meta) there would be a problem only when the user adds his own metadata.

8:05 AWizzArd: G0SUB: in Contrib there is a filter function "separate" which you could use to separate the directory ZipEntry's from the non-directory ones.

8:05 G0SUB: AWizzArd: will look. thanks.

8:05 cgrand: I think the new problem would be less frequent than the current one

8:06 AWizzArd: cgrand: I was surprised today when working with htmlunit, and I also thought that .replaceAll would know that a (with-out-str ...) will return a String.

8:06 rhickey: cgrand: discarded how? no macro can promise to use any metadata placed on it's invocation. You are presuming some semantics for metadata (that it is destined for the expansion) that's simply not there

8:06 G0SUB: AWizzArd: where in c.c is separate?

8:07 AWizzArd: clojure.contrib.seq-utils/separate

8:07 G0SUB: ok

8:09 cgrand: rhickey: I think I failed to explain what I want

8:09 rhickey: #^meta (a-macro-call) ==> #^meta (its-expansion), right?

8:10 cgrand: right :-(

8:11 rhickey: so the question is, who should 'own' the metadata on the macro call, the enclosing scope or the macro itself

8:12 if a macro were to be passed &whole (http://www.lispworks.com/documentation/HyperSpec/Body/03_dd.htm) one would presume it could act on the metadata

8:12 cgrand: currently the macro can't see it (no &whole)

8:13 rhickey: but there's nothing in the definition of macros that says they can't become richer than they are (macros are just functions is an implementation detail of the current mechanism)

8:13 &whole and environments would be logical extensions

8:14 at which point this ownership issue would arise

8:15 cgrand: ok, so I may try to restrict what I'd like: can we have #^meta (.method obj) ==> #^meta (. obj method) and #^meta (inlined-fn obj) ==> #^meta (inline-expansion)

8:16 rhickey: in the - a macro call provides its replacement - world, I would give ownership to the macro

8:17 cgrand: I'm wondering in those cases that the meta isn't better place on obj, then return type should flow through

8:18 cgrand: rhickey: I agree except when the .method says to return an interface and you want to "downhint" to something more specific

8:18 rhickey: but yes, those expansions are compiler controlled so could do

8:19 I would accept a patch limited to that

8:19 AWizzArd: would be helpful

8:20 cgrand: rhickey: ok thanks!

8:20 rhickey: cgrand: thank you!

8:21 * AWizzArd cheers

8:27 AWizzArd: rhickey: would a datatype made via deftype be GCable?

8:27 rhickey: AWizzArd: the class itself or instances?

8:27 AWizzArd: the class itself I mean

8:27 rhickey: subject to same issues as all classes

8:28 AWizzArd: ok

8:29 rhickey: I'm working on making protocols hold classes weakly, not there yet

8:29 and not sure it would matter, since their caches must hold strongly

8:29 AWizzArd: sounds very promising

8:30 rhickey: once implementing a protocol and called, class would be embedded in cache until un-implemented

8:30 so not so promising

8:42 G0SUB: AWizzArd: This is what I wrote just now. Works well. http://paste.lisp.org/display/89087

8:43 AWizzArd: many thanks for the tips. I am a Java n00b :)

8:43 AWizzArd: Anyway, it would still be enormously helpful to have deftype. We have a lot of structs that contain a :type slot, but this is convention. Having a default way for marking a type (deftype ...) would make things easier. But mostly the speedup will be very nice.

8:44 G0SUB: grats! You have a nice zip app now :)

8:44 G0SUB: you can download the SDK from http://www.7-zip.org/sdk.html and extend your program to handle .7z files as well.

8:46 G0SUB: AWizzArd: well, right now, I just need to handle the Zip algo. May be some other time :)

10:11 saml: i installed clojure box. i can type stuff in REPL. where do I learn to actually use it to program? like editing files, loading some defn from files.. debugging, printing doc of a symbol, jumping to definition of the symbol...etc?

10:17 RomanRoe: Is it possible to get namespace/function code completion in Emacs/Slime? (Just like in Enclojure and CCW)

10:18 liwp: RomanRoe: you should get it out of the box on the repl, just hit tab

10:18 I'm not sure what the keybinding would be for a clojure-mode buffer, try M-tab

10:19 RomanRoe: liwp: thx. will try that

10:20 liwp: RomanRoe: looks like M-tab is bound to slime-complete-symbol if your clojure buffer has the slime-minor-mode enabled (as it should)

10:22 RomanRoe: liwp: unfort. I cant check it right now (different machine right now). But I doubt that M-tab work since it cycles the windows

10:22 liwp: saml: try googling for some clojure / slime blog posts. But the basic steps are something like this: open a new buffer (e.g. test.clj), write some code in it, and hit C-c C-k to compile and load the file to the repl

10:22 RomanRoe: liwp: I will try M-x slime-complete-symbol and remap if it works

10:22 liwp: RomanRoe: you can hit M-tab by hitting Esc and Tab

10:23 RomanRoe: liwp: ah thx! I am a emacs newbie... ;-)

10:23 liwp: annoying, I know, but you can rebind it

10:23 I only found out about M-tab maybe a week ago ;-)

10:50 Kjellski: Hi there =)

10:53 Can someone tell me how I can call a constructor of a native java class with more than one argument? I saw that in the book but can´t find it again...

10:54 rhickey: Kjellski: (TheClass. a b c)

10:55 Kjellski: *homerlike* doh... thanks!

10:55 rhickey: np

11:08 Soulster: hello everyone, whats up with "gen-and-load-class" when i am using it i get "Unable to resolve symbol: gen-and-load-class in this context"

11:08 with a java.lang.Exception

11:12 Chousuke: Soulster: gen-and-load-class went away ages ago :)

11:12 Soulster: outch..^^

11:14 chouser: Soulster: you may use gen-class, but that requires you use 'compile' to actually generate the class.

12:01 ambient: i can't quite get this to work: (defmacro foo [num] `(do ~(for [i# (range 5)] `(+ 1 1))))

12:01 it's supposed to expand into (do (+ 1 1) (+ 1 1)) etc..

12:01 chouser: try ~@ instead of ~

12:02 ambient: cool! thanks

12:05 cgrand: ambient: and no need for the # in i#: you aren't in the syntax quote

12:06 ambient: i just started doing macros 30 minutes ago :p

12:06 so what you mean by syntax quote, i dont know

12:07 chouser: ` is read "syntax quote"

12:07 ambient: ok

12:07 well, i will be so it might as well be i#

12:08 (defmacro foo [num] `(do ~@(for [i# (range num)] `(+ ~i# ~i#))))

12:09 chouser: still no need for the #

12:09 ambient: ok

12:09 chouser: don't worry -- if you forget the # somewhere that you should have it, Clojure will yell at you.

12:10 cgrand: as soon as you cross a ~ (unquote) you escape from the syntax-quote

12:10 Chousuke: I think I managed to compile a clojure with my reader

12:10 the repl still uses lispreader though.

12:11 presumably because of read... hm

12:14 ambient: my first working macro, that's actually useful: (defmacro mdaset [a vals] `(do ~@(for [i (range (count vals))] `(aset #^doubles ~a ~i ~(vals i))))) :)

12:15 sets values to an array

12:20 Chousuke: \o/ it works

12:20 well, as far as I can tell, anyway

12:20 except for a small bug

12:21 for some reason, if my input ends with a symbol I need to press enter twice.

12:22 cgrand: ambient: you can't hint an unquote, you should change the do in a let [#^doubles a# ~a]

12:23 and replace all other ~a by a#

12:23 Chousuke: or ~(with-meta a {:tag 'doubles})

12:38 ambient: type hints dont seem to macro-expand :/

12:38 cgrand answered my question :P

12:39 Chousuke: type hints are read-time. you're actually attaching the hints to the macro code :P

12:41 ambient: my problem is that if the macro breaks, the execution time of the program goes from 0.2 sec to 16

12:45 (defmacro daset [a vals] `(let [#^doubles b# ~a] ~@(for [[idx val] (partition 2 vals)] `(aset b# ~idx ~val)))) ==> "unable to resolve symbol: b__16325__auto__ in this context"

12:47 cgrand: ambient: sorry didn't notice that you were going in an uout of syntax-quote so the two b# are different. Try Chousuke's solution or

12:49 ambient: thanks, it works now :)

12:49 *fist pump*

12:49 cgrand: (defmacro daset [a vals] (let [b (with-meta (gensym "b") {:tag 'doubles})] `(let [~b ~a] ~@(for [[idx val] (partition 2 vals)] `(aset ~b ~idx ~val)))) ; not worth it here

12:52 ambient: pretty cool, now i can just write (daset oscm2 [0 (+ car-f os1-o), 2 car-v]) instead of painfully doing it piece by piece

12:52 and the performance doesn't suffer at all

12:52 cgrand: no i'm wrong: this last one is worth the pain because it doesn't cause multiple evaluations of a (which is important when a is not a symbol but a function call)

12:52 ambient: here's mine: (defmacro daset [a vals] `(do ~@(for [[idx val] (partition 2 vals)] `(aset ~(with-meta a {:tag 'doubles}) ~idx ~val))))

12:54 cgrand: try (macroexpand-1 '(daset (foo bar) [0 1 2 3]))

12:54 ambient: it's not supposed to be used like that

12:55 cgrand: ok, I just wanted to make you aware of potential shortcomings

12:55 ambient: (foo bar) would be evaluated at each iteration?

12:57 cgrand: yes because your macro would expand to (do (aset (foo bar) 0 1) (aset (foo bar) 2 3))

12:58 my last (untested) one should expand to (let [b457 (foo bar)] (aset b457 0 1) (aset b457 2 3))

13:01 ambient: if i would be making more general purpose array handling operations, that might be a problem. for my case every array's lifetime is programs lifetime and there are no intermediate arrays

13:38 cemerick: since it's macro workshop day: how do people deal with using private fns in public macros? I've always just used the corresponding var, but that feels wrong.

13:42 Chousuke: just make them public and document that the only supported way of using them is via the macro

13:43 hmm, pretty good.

13:44 hiredman: Chousuke: hows the reader coming?

13:44 Chousuke: running the clojure tests with my reader, I got one test failure and two errors

13:44 hiredman: :/

13:45 Chousuke: the failure tests compiler metadata which I omit on purpose :P

13:45 the errors are... something. need to investigate

13:45 hiredman: can you build clojure with it?

13:45 Chousuke: hm

13:45 didn't try.

13:46 hiredman: really?

13:46 cgrand: cemerick: by "used the corresponding var" you mean @#'ns/private-fn? I agree with Chousuke, make them public but documented as unsupported

13:48 cemerick: cgrand: yes. Just making the fns public seems worse, though. Reminds me of abstract method overrides on Java APIs that aren't meant to be called that have javadoc that reads "Public as an implementation detail, do not use." Uk.

13:50 hiredman: how do you know if rhickey got your ca?

13:50 ask him?

13:50 cgrand: hiredman: check the cotributors page

13:50 contributors even

13:50 hiredman: w00t

13:51 Chousuke: hm, I get a nullpointer exception :-(

13:51 hiredman: I can build clojure, but the reader is not complete yet, the missing parts are stubbed out to LispReader

13:51 cgrand: cemerick: can't you make your macro shallow? and backed by a public (supported) function

13:53 djork: This might be more of a Java issue than a Clojure one, but if build a MUD-style game using a thread per-player, will I have problems with high player counts?

13:53 this is just based on some (probably bad) advice from a friend who said that threaded servers don't scale

13:53 i.e. in terms of memory usage etc.

13:54 cemerick: cgrand: yeah, I could support it, but the macro helps to ensure proper usage. I suppose I should put the unsupported stuff in a secondary ns.

13:54 Knekk: maybe thread-per-connection servers don't scale.... threaded servers scale

13:54 hiredman: I doubt you will have any trouble with a mud

13:54 cemerick: djork: use an *agent* per player, and you can have thousands, millions perhaps.

13:54 djork: hmm

13:55 hiredman: cemerick: ahem

13:55 djork: I'm still not quite clear on agents. Is there a good example on their usage? The docs don't quite "click" yet.

13:55 cemerick: hiredman: hrm?

13:56 Chousuke: hmm, interesting

13:56 hiredman: agents sit on top of threads, so picking agents because you don't want threads doesn't seem like a good idea

13:57 djork: yeah

13:57 that's what I thought

13:57 Chousuke: I suspect there's something wrong with my syntax-quote :/

13:57 technomancy: agents use a thread pool

13:57 hiredman: djork: with the amount of users you will get for a mud, a thread per user should not be a problem

13:57 djork: heh :)

13:57 hiredman: technomancy: yes

13:57 cemerick: hiredman: my point is that agents are lightweight; you could service a very, very large number of agents with a very small number of threads.

13:57 djork: the idea is to scale up to a graphical client on iPhone eventually

13:57 hiredman: but the send-off threadpool is unbounded

13:58 djork: which could see a lot more users

13:58 hiredman: cemerick: ah

13:58 djork: hmm, so agents join threads in the pool as needed? or something like that?

13:58 cemerick: I see no reason why you couldn't use send for a MUD (and maybe snapshot state every now and then or something).

13:58 hiredman: right, for re-use of threads that happen to be laying around :P

13:59 cemerick: djork: agents use threads as needed, when they have an action to service.

13:59 djork: OK that makes sense. Now if only I understood their general use :P

13:59 hiredman: Chousuke: it's statements like that that make me want a line by line port of the java reader :P

14:00 djork: By the way, is there any work towards tracebacks for Clojure code?

14:00 Knekk: you'll still run into problems when your number of agents and actions saturate and exceed the threadpool

14:00 maybe think about queueing actions, decouple your user connections

14:02 cemerick: The real criteria is whether one's actions will saturate the send threadpool to such an extent that responsiveness is impacted. For a MUD, probably never.

14:02 Knekk: cemerick: you are assuming that a MUD won't have thousands of users.

14:02 cemerick: there's no reason why it shouldn't

14:03 cemerick: specially as he wants to port to the iPhone

14:03 cemerick: Knekk: well, it's a little bit moot one way or the other -- you can do as much decoupling as you want, but you can't do more work than what the send threadpool can schedule (e.g. you've got the cores you've got, and that's a pretty hard limit regardless of the arch.)

14:05 Knekk: I'd personally queue actions so that the impact of saturation is seen as latency across the system for all users rather than arbitrary delays/timeouts for some connections.

14:05 cemerick: right, but one can control where the pain is felt.

14:07 cemerick: Good point. I guess it's a product mgmt question, then: IMHO, better to get the thing working, and if he's so lucky to have a load problem, his massive bankroll can be put into an alternative scheduling strategy for agents. :-)

14:08 Knekk: It'd be a good problem to have, for sure

14:08 cemerick: Actually, it might be as easy as building a send* variant that uses a given threadpool that throttles as desired.

14:08 jasapp: roughly, how many users is this MUD to support?

14:08 cemerick: (this is already the most heavily-engineered MUD in history ;-) )

14:08 jasapp: heh

14:09 serp_: cemerick: how would one do that?

14:11 cemerick: serp_: in broad strokes, change Agent.dispatch and Agent$Action to take an ExecutorService, rather than a boolean controlling which of two standard threadpools are to be used. I'm sure there'd be a lot of consequences to such a change, but that's the first step.

14:19 Chousuke: aha, I think I found the bug.

14:20 I was expanding (Foo. ...) to (fully.qualified.Foo ...) :P

14:21 or wait

14:22 yeah

14:25 djork: cemerick: yes, I'd love to have too many users :)

14:26 ambient: FFFUUUUU... macros are killing my brain

14:27 djork: ambient: just be glad macros are so easy in Clojure... just try digesting the docs for building them in any other lisp

14:27 ambient: is there somewhere a whole reference for every type of macro possible in clojure?

14:27 Chousuke: type?

14:28 there's only one type of macro: one that takes in a form and produces another :P

14:28 ambient: meaning comprehensive

14:29 Chousuke: hm, cool

14:29 only one test failure for my reader now

14:30 for line metadata :P

14:31 djork: ambient: just check out the source

14:31 grep for defmacro

14:37 ambient: here's what's giving me trouble: http://paste.pocoo.org/show/146449/

14:38 grep, one of those tools that unices use

14:39 mwoelker_: quick question: is it possible to create cyclic immutable collections in clojure? e.g. two vectors that contain each other?

14:40 cgrand: mwoelker_: quick answer: no (apart from cyclic lazy-seq)

14:42 imagine you have a cyclic vector of one item (itself), what does (conj v 42) must return?

14:44 [new-self 42] or [old-self 42]? it seems easy but once you are deely nested, not so: you have to "update" all collections that are on the path to the recursive reference(s)

14:45 mwoelker_: cgrand: hmm, is it possible to put refs into collections?

14:45 cgrand: yes of course and it's one way to deal with cyclic stuff

14:46 one other being the relational way

14:46 chouser: ambient: http://paste.pocoo.org/show/146451/

14:46 mwoelker_: e.g. a list of edges (relations) for a graph?

14:47 or a map?

14:47 chouser: mwoelker_: right. like a bag of RDF triples or something.

14:48 arsatiki: chouser: it seems that body is missing in that response

14:48 chouser: arsatiki: oh! indeed.

14:48 mwoelker_: wouldn't that kill performance for larger graphs?

14:48 ambient: chouser perfect, thank you. although just a hint into the right direction would be enough :)

14:49 chouser: well then a hint for the body: ~@body

14:52 Licenser_: a very off topic question, how is the clojurebot secured against tempering? I mean how do you ensure that code that is run on it does not affect the host system it runs on?

14:53 lpetit: ,(System/exit)

14:53 clojurebot: java.lang.NoSuchFieldException: exit

14:53 djork: nice

14:53 lpetit: ,(System/exit 0)

14:53 clojurebot: java.security.AccessControlException: access denied (java.lang.RuntimePermission exitVM.0)

14:54 chouser: Licenser_: it's got a range of things -- uses the Java sandbox to prevent access to filesystem and such, uses a blacklist of words to prevent certain kinds of meddling within the sandbox, runs stuff in a separate thread so it can be timed out to prevent consuming host resources, etc.

14:54 Licenser_: hmm nice

14:55 chouser: ,(defmacro if [x y z] `(clojure.core/if x z y))

14:55 clojurebot: DENIED

14:55 Licenser_: And the JVM provides protection against flooded memory by itself due to it's memory restrictions

14:56 chouser: ,(while true)

14:56 serp_: how does clojure handle recursion between two functions?

14:56 clojurebot: Execution Timed Out

14:56 serp_: a calls b and b calls a

14:56 Licenser_: recursively

14:56 djork: is the clojurebot source available?

14:56 Licenser_: that'd be incredible nice

14:56 serp_: I understand if it's just one function you can use the recur thing

14:57 djork: ,"Hello"

14:57 clojurebot: "Hello"

14:57 hiredman: serp_: trampoline

14:57 chouser: serp_: that consumes JVM stack, just as it would in Java. In some cases you can use 'trampoline' to avoid consuming stack.

14:57 djork: ,*ns*

14:57 clojurebot: #<Namespace sandbox>

14:57 Licenser_: serp_: yes then it's optimized as tail recursion (in a kind of iterative way)

14:57 chouser: clojurebot: where are you?

14:57 clojurebot: http://github.com/hiredman/clojurebot/tree/master

14:58 Licenser_: clojurebot: what did you had for lunch?

14:58 clojurebot: for is not a loop

14:58 Licenser_: interesting diet

14:58 djork: hah hah

14:58 serp_: hiredman, chouser: thanks

14:58 Licenser_: ,(doc trampoline)

14:58 clojurebot: "([f] [f & args]); trampoline can be used to convert algorithms requiring mutual recursion without stack consumption. Calls f with supplied args, if any. If f returns a fn, calls that fn with no arguments, and continues to repeat, until the return value is not a fn, then returns that non-fn value. Note that if you want to return a fn as a final value, you must wrap it in some data structure and unpack it after trampoline

14:59 lpetit: serp_: and you (declare) the first function if you want the stuff to compile

15:00 chouser: or use letfn

15:00 serp_: I see

15:01 djork: clojurebot: 2d6

15:01 clojurebot: I don't understand.

15:01 djork: clojurebot: 2 d6

15:01 clojurebot: Pardon?

15:01 hiredman: hmmm

15:01 djork: must not be turned on :)

15:01 chouser: ,2d6

15:01 clojurebot: Invalid number: 2d6

15:02 hiredman: 2d6

15:02 clojurebot: 4

15:02 hiredman: 5d4+5

15:02 clojurebot: 18

15:02 danlarkin: In the case of nested dosyncs, are internal ones no-ops (essentially)?

15:02 chouser: danlarkin: I think that's right.

15:03 djork: huh, so no "clojurebot:" first

15:03 hiredman: yeah

15:04 Chousuke added a pluginish architecture so I wrote the dice plugin to kind of figure out the ropes

15:04 danlarkin: chouser: great, so I don't have to worry about the internal one closing the transaction before the outside one gets to finish the rest of its work

15:04 djork: I just wrote dice rolling yesterday :)

15:05 chouser: danlarkin: you certainly don't need to worry about that. Looking at the code, it's not quite a no-op -- it's still creates and calls a closure.

15:05 Licenser_: wooh let's play some Shadowrun

15:05 100d6

15:05 clojurebot: 354

15:07 danlarkin: chouser: great, that's what I got from the code too, thank you

15:08 djork: hah hah

15:12 mwoelker_: 2d6

15:12 clojurebot: 2

15:12 mwoelker_: 2d6

15:12 clojurebot: 11

15:12 mwoelker_: 2d6

15:12 clojurebot: 10

15:12 mwoelker_: 0d6

15:12 clojurebot: 0

15:13 mwoelker_: -1d6

15:13 id6

15:13 1d1e3

15:13 clojurebot: 1

15:15 Licenser_: 1d100000

15:15 clojurebot: 6196

15:17 ambient: i have no clue why this error pops up: "More than one matching method found: aset"

15:17 while trying to run a macro that uses aset outside any function

15:18 chouser: 10d1

15:18 clojurebot: 10

15:18 ambient: 6d0

15:18 Chousuke: hmmh

15:19 I don't think I'm going to solve this problem today... :P

15:19 Licenser_: Chousuke: what is your problem?

15:19 Chousuke: "clojure.lang.ArraySeq cannot be cast to clojure.lang.IFn" hooray for informative error messages

15:19 Licenser_: roll a dice to help you decide!

15:20 I think I had that yesterday - same message

15:20 problem for me was that I had a () too much around my code

15:20 I used next instead of second :P

15:20 Chousuke: the problem is, that comes from core.clj :P

15:20 Licenser_: wooh!

15:20 you broke it!

15:21 I have the feeling that is bad

15:21 Chousuke: because I'm compiling it with the version of clojure that resulted from compiling my clojure-reader-clojure with the java-reader-clojure

15:22 so it's most likely that my reader is producing something that confuses the compiler

15:22 chouser: ambient: what are your args to aset?

15:22 Licenser_: ah

15:22 hiredman: Chousuke: I have my reader plugged into build.xml, the first ant run it builds clojure.jar and reader.jar and subsequent runs it uses the reader from reader.jar instead of LispReader

15:23 Licenser_: why does everyone want a own reader?

15:24 ambient: using ~(with-meta a {:tag 'doubles}) seems to break something essential

15:24 inside a macro

15:24 Chousuke: hiredman: that's about what I'm doing, too. I guess :P

15:24 chouser: Licenser_: so we can use whitespace and indentation instead of parens.

15:24 hiredman: this is my first time metacirculating a language

15:24 Chousuke: me too. :P

15:24 hiredman: so figuring out where to put the indirection and stuff is interesting

15:24 ambient: i'm actually programming a metacircular language...

15:25 Licenser_: hiredman, Chousuke: why don't you combine your work?

15:25 Chousuke: but it'll be even more fun when clojure no longer needs java to actually compile itself

15:25 neotyk: Hi *, what is your single favorite feature of clojure?

15:25 G0SUB: Where can I find the two Wiki pages on datatypes and protocols that Rich published?

15:25 lpetit: ~datatypes

15:25 clojurebot: http://www.assembla.com/wiki/show/clojure/Datatypes

15:25 lpetit: ~protocols

15:25 clojurebot: http://www.assembla.com/wiki/show/clojure/Protocols

15:26 G0SUB: neotyk: sequences.

15:26 Chousuke: G0SUB: assembla for everything :)

15:26 G0SUB: Chousuke: heh

15:26 Licenser_: neotyk: paralelity

15:26 neotyk: I'm just learning but so far destructuring rocked me

15:26 ambient: neotyk parentheses

15:26 arsatiki: ambient :)

15:26 hiredman: I am really interested to see Chousuke's reader

15:26 chouser: ambient: this works for me: (let [ary (into-array Double/TYPE [1 2 3 4 5])] (dalet ary [a 0, b 1, c 2, d 3] [a b c d]))

15:27 hiredman: and how he is building/using it

15:27 Chousuke: hiredman: I'll push my current work on github and tell you how to build it. :P

15:28 hiredman: Chousuke: how are you getting the reader to run before clojure is loaded?

15:28 djork: neotyk: The way it takes the suck out of Java.

15:28 Licenser_: I undertand how it would work with identation but doesn't that mean I have to use a newline for everything?

15:29 ambient: chouser this doesn't for me: http://paste.pocoo.org/show/146471/

15:29 chouser: Licenser_: I was kidding about the reader, though I think there actually is one for whitespace somewhere.

15:29 Licenser_: o.o

15:29 chouser: Licenser_: I think hiredman and Chousuke are just writing readers for fun while secretly hoping rhickey ends up using them in cinc. :-)

15:30 G0SUB: Chousuke: what reader? any links?

15:30 Licenser_: muhaha

15:30 Well one thing I didn't yet found isa nice parser generator :/ I got too used to having one

15:31 ambient: well i construct domain spesific languages with lisp for solving problems so parser generator is not so critical ;)

15:31 Chousuke: http://github.com/Chousuke/clojure/tree/reader-integrated

15:32 * G0SUB looks

15:32 Chousuke: it's... quite a mess, still :P

15:32 chouser: ambient: try (double ~val) instead of just ~val in your macro

15:32 G0SUB: Chousuke: what are the features?

15:32 hiredman: my reader is a fn with all the pieces contained in a letfn, so I keep track of the classname of the enclosing Fn

15:33 Chousuke: G0SUB: features? :)

15:33 G0SUB: it's just a clojure reader written in clojure :P

15:33 G0SUB: ah, cool

15:34 Chousuke: a rather simple one, too.

15:34 hiredman: http://github.com/hiredman/clojure/tree/readerII

15:34 Licenser_: ambient: but if you want to write a interpreter a DSL isn't the way to go :P

15:34 ambient: chouser works, ty

15:35 hiredman: http://github.com/hiredman/clojure/blob/readerII/src/clj/clojure/reader.clj it's an incomplete port of LispReader

15:36 Chousuke: gen-class never worked for me

15:37 Chousuke: I don't actually use gen-class with my reader

15:37 hiredman: loading the gen-class'ed class always seem to try and load clojure

15:37 Chousuke: the ClojureReader thing is a left-over from an earlier attempt.

15:38 lpetit: Licenser_ : there's fn-parse, and also cgrand is writing parsley (both are on github)

15:39 Licenser_: I looked at fn-parse but since last time I worked with racc (something yacc related) it is really hard to understand

15:39 Chousuke: I suppose a proper parser combinator would be much better :/

15:39 hiredman: Chousuke: so you load core, then your reader, then reload core using your reader?

15:39 Chousuke: hiredman: yes.

15:41 Licenser_: Chousuke: but they are hard to understand :P

15:41 hiredman: interesting

15:44 lpetit: parsley has the interesting property of being an incremental parser

15:45 Licenser_: hmm parsley

15:45 I see it is well documented :P

15:45 lpetit: but still in inception, not really for prime use / production purpose. But interesting to keep on the radar (We intend to use it for static analysis / user code writing assistance in counterclockwise)

15:46 wait a min., I've something for ya

15:46 Licenser_: An experimental undocumented parser lib/DSL. Hah!

15:47 * Licenser_ really wants to write a java script interpreter in clojure :P

15:48 chouser: Licenser_: pretty sure that's the wrong way 'round.

15:48 lpetit: clojurebot: parsley is an incremental parser with docs at http://wiki.github.com/cgrand/parsley/design-notes and at http://cloud.github.com/downloads/cgrand/parsley/parsley.pdf

15:48 clojurebot: Roger.

15:48 lpetit: ~parsley

15:48 clojurebot: parsley is an incremental parser with docs at http://wiki.github.com/cgrand/parsley/design-notes and at http://cloud.github.com/downloads/cgrand/parsley/parsley.pdf

15:48 ambient: but what are sage, rosemary and thyme?

15:48 lpetit: note those are design notes : subject to change (if not already) :)

15:48 Licenser_: chouser: why?

15:49 I want to see if I can do it :P I wrote one in ruby - not perfect but it does a lot already

15:50 serp_: ambient: they are spices

15:51 chouser: Licenser_: because I want to write more clojure (perhaps where only JavaScript is supported), not vice versa.

15:51 somnium: the day when the DOM can be scripted in pure-clojure will be a beautiful day indeed

15:51 hiredman: Chousuke: I am going to ask rhickey about exposing LispReader has Fn bound to something like READER in clojure.core, then removing all direct calls to LispReader/read in favor of going through the Fn

15:52 Licenser_: but chouser when you implement clojure in javascript and I implement javascript in clojure we can run clojure code in javascript in clojure in javascript in clojure in javascript in safari!

15:53 G0SUB: odd, use of transients actually made the example code slower on my machine.

15:53 Licenser_: and then chouser we will rule the world!

15:54 * Licenser_ laughs evelish

15:57 cgrand: lpetit please use the future tense when talking about parsley :-)

16:02 chouser: Licenser_: heh

16:02 rlb: Is re-split probably the most efficient way to split a string at (a single) tab, or is there something simpler that might be faster?

16:02 Licenser_: Another question, is there a good way to scan a string to tokenize it?

16:02 chouser: somnium: that day already came and went. :-/

16:02 rlb: i.e find index and substr or similar...

16:02 Licenser_: I wrote a own function re-scan but I fear it's horrible ineffective

16:05 somnium: chouser: I was thinking something between clojurescript and scriptjure, 'browjure'? whatever it is it has to play nice with all the js libraries out there. Are you still working on ClojureScript?

16:05 Licenser_: http://gist.github.com/216251

16:06 chouser: somnium: ClojureScript's on hold until cinc

16:06 Licenser_: if someone want to take a look

16:07 sadly I don't think this will return a lazy seq :P

16:08 somnium: ,(doc re-seq)

16:08 clojurebot: "([re s]); Returns a lazy sequence of successive matches of pattern in string, using java.util.regex.Matcher.find(), each such match processed with re-groups."

16:11 Licenser_: somnium: I know but that only works if you have one regexp not if you've multiple

16:12 chouser: Licenser_: you've considered combining your regexs using | ?

16:12 Licenser_: yes that a) gets ugly and b) I don't know which regexp matched in the end - which isn't too good

16:13 somnium: Licenser_: if you don't like ugly best to stay away from regex altogether :-p

16:13 Licenser_: heh

16:13 chouser: well, you could combine them programmatically so you don't have to look at them all together. ...knowning which matched might to tough -- no named groupings in Java

16:14 * Licenser_ updates http://gist.github.com/216251 with the whole code

16:14 Licenser_: I think java allowed named groupings

16:16 lpetit: cgrand: Oh it's was just an easy way to place some more pressure on parsley's planning :)

16:16 Licenser_: well no it does not seem to have

16:20 somnium: Licenser_: have you looked at partition and grep in contrib.str-utils2 ?

16:20 Licenser_: nope never heared of them

16:20 ,(doc grep)

16:20 clojurebot: "clojure.contrib.str-utils2/grep;[[re coll]]; Filters elements of coll by a regular expression. The String representation (with str) of each element is tested with re-find."

16:21 Licenser_: ,(doc partition)

16:21 clojurebot: "([n coll] [n step coll] [n step pad coll]); Returns a lazy sequence of lists of n items each, at offsets step apart. If step is not supplied, defaults to n, i.e. the partitions do not overlap. If a pad collection is supplied, use its elements as necessary to complete last partition upto n items. In case there are not enough padding elements, return a partition with less than n items."

16:22 somnium: partition is in core, not sure how to get the doc from str-utils2 out of him

16:22 Licenser_: ,(doc clojure.contrib.str-utils2/partition)

16:22 clojurebot: I don't understand.

16:23 somnium: ,(doc split)

16:23 clojurebot: "clojure.contrib.str-utils2/split;[[s re] [s re limit]]; Splits string on a regular expression. Optional argument limit is the maximum number of splits."

16:25 Licenser_: I will try to just run the regexp over the stuff twice, once to tokenize it and once ti determine the kind of tiken

16:26 somnium: clojure.walk is useful if you're building ASTs

16:27 so one day you can do away with rhino and script java through clojure back to java ;)

16:36 djork: raise your hand if you're using clojure-mode and slime

16:40 The-Kenny: *raises hand*

16:40 * technomancy raises hand

16:41 Dawgmatix: *raises hand*

16:45 jasapp: I am

16:46 eyeris: Is there any CSV stuff in contrib?

16:49 djork: how do you set up your working environment so that you can load files properly

16:49 I'm not sure if that question even makes sense

16:49 jasapp: what do you mean load files?

16:49 djork: but I have classpath problems using slime and working on projects

16:50 or just what are project layout and file loading/inclusion practices in general?

16:50 Licenser_: ,(doc walk)

16:50 clojurebot: Huh?

16:50 Licenser_: ,(doc clojure.walk)

16:50 clojurebot: java.lang.ClassNotFoundException: clojure.walk

17:06 Kjellski: Can someone tell me how the regular expression escape for an uppercase character is? \u doesn´t work...

17:09 stuartsierra: [A-Z]

17:09 Licenser_: Kjellski: one so- what stuartsierra saied

17:11 Kjellski: okay... thanks... was just looking for the java doc... are there any differences?

17:11 stuartsierra: some; look up java.util.regex.Pattern

17:11 Kjellski: Thanks!

17:11 stuartsierra: welcome

17:11 rlb: In my case, I just wanted the fastest way to grab everything up to the first tab from a bunch of strings -- wonder if (subs s (.indexOf s tab)) is preferable -- have to test.

17:11 technomancy: djork: are you using M-x swank-clojure-project?

17:11 C-c C-k should just work

17:12 djork: nope, no swank-clojure-project

17:12 does that come with the whole kit?

17:12 (not working on clojure right this second...)

17:13 technomancy: djork: you'll have it if you did M-x clojure-install

17:13 djork: oh ok, cool

17:14 rlb: Hmm, so (.indexOf s "\t") works, but (.indexOf s (int \t)) doesn't, though java has a str.indexOf(int character).

17:15 Kjellski: This is going to be an stream closed error, does anyone know why?

17:15 (with-open [rdr (reader *text-file-path*)]

17:15 (filter #(re-find #"[A-Z]" %) (line-seq rdr)))

17:16 technomancy: Kjellski: filter is lazy; so the reader is closed by the time it gets consumed

17:17 either consume it inside the with-open block or wrap filter in a doall

17:17 Kjellski: *doh* ... thanks

17:18 rlb: (Oh, right *\tab*, not \t...)

17:24 rads: I'm trying out redis-clojure, and for now I've had to wrap (redis/with-server) around the forms in every function that accesses redis. is there an idiomatic way of abstracting that?

17:37 Licenser_: hmmm one problem I run into is that when using combined regexp it does not match in the right order o.O

18:01 Kjellski: I´ve got a pretty stupid question for you advanced, but I can´t get how to accumulate values in a function...

18:01 Licenser_: define accumulate :P

18:01 while I

18:01 'm not advanced I am always curiose!

18:01 and I really have trouble with the ' on the english keybard ...

18:01 Kjellski: 1 sec... I´ll post an example of my function ok?

18:01 Licenser_: YaY!

18:02 Kjellski: ,(defn read-with-filter [file regx]

18:02 (with-open [rdr (reader file)]

18:02 (let [result []]

18:02 (doseq [line (line-seq rdr)]

18:02 (doseq [line-char line]

18:02 (if (Character/isUpperCase line-char)

18:02 clojurebot: EOF while reading

18:02 Kjellski: (conj result line-char))))

18:02 result)))

18:03 jasapp: Try putting it here: http://pastebin.com/

18:04 Kjellski: *ugly*http://paste.lisp.org/display/89128

18:05 I´m trying to find the uppercase characters in a file ang conj them into a result...

18:06 That this doesn´t work is what I would aspect from immutable result, but how can I accumulate the values I need? I´ve tryed loop, but how to tailcall in nested doseqs?

18:07 chouser: Kjellski: doseq and for both do nesting for you, so you could say (for [line (line-seq rdr), line-char line] ...)

18:08 Kjellski: ups, the second argument of the function is not used anymoro...

18:08 chouser: Kjellski: both doseq and for also support :when which you could use instead of 'if'

18:08 Kjellski: okay? so the complete nesting could be removed with one for?

18:08 djork: Kjellski: (loop [coll []] (recur (conj stuff coll)))

18:09 that's what I've found to work for building collections

18:09 err, (conj coll stuff)

18:09 chouser: Kjellski: then instead of calling conj manually, the body of the 'for' could just return line-char

18:09 Kjellski: inside the if statement?

18:10 chouser: Kjellski: that'll give you a lazy seq of the uppercase chars, but since you're in a with-open you'd want to wrap your 'for' with 'vec' or 'doall'

18:11 Kjellski: Sure, but would there be a way to, just for educational purposes, "save" the state of reading in order to make it "lazy-with-open"?

18:14 chouser: Kjellski: when would you close the file?

18:15 wwood: I'm trying to setup liverepl on mac os x

18:15 http://github.com/djpowell/liverepl

18:15 Kjellski: ^^ ... I know you would ask, for easyness, after the last value is taken from the lazy-seq?

18:15 wwood: liverepl.sh is looking for tools.jar in jdk home

18:15 but /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home doesn't have tools.jar

18:16 anyone more clueful than I about that?

18:17 think I found the answer

18:17 tools.jar does not exist. Classes usually located here are instead included in classes.jar. Scripts that rely on the existence of tools.jar need to be rewritten accordingly.

18:17 from http://developer.apple.com/mac/library/documentation/Java/Conceptual/Java14Development/02-JavaDevTools/JavaDevTools.html

18:21 chouser: Kjellski: yes it's possible (contrib duck-streams has such a thing) but it's a bit dangerous since normally failing to consume a whole seq is fine, but one of these seqs will leak filehandles if you don't consume it.

18:22 wwood: found it

18:23 under Versions/1.6.0/classes/classes.jar

18:23 Kjellski: Okay, but that behaviour is necessary right? If the duckstream keeps opened, the file handles state remains open and the lazy-seq will too... hope you understand what I mean... but a more important question, how have you found that out? What have you typed in google or where have you searched? maybe clojure.org -> api -> duck-streams?

18:24 I think it´s pretty hard to find informations with examples for learning clojure on the net....

18:25 somnium: Kjellski: browsing the source code in contrib is a good way to get familiar with the libraries (there are a lot, I know)

18:27 Kjellski: somnium thanks, that is something i´ve never tryed before ^^...

18:27 -y +ie

18:27 chouser: (doc read-lines)

18:27 clojurebot: "clojure.contrib.duck-streams/read-lines;[[f]]; Like clojure.core/line-seq but opens f with reader. Automatically closes the reader AFTER YOU CONSUME THE ENTIRE SEQUENCE."

18:28 lisppaste8: foomanchoo pasted "Abtract Class" at http://paste.lisp.org/display/89129

18:28 foomanchoo: Hi All

18:28 Kjellski: Hi foomanchoo =)

18:28 foomanchoo: learning (or trying to learn clojure) and hit a snag trying to gen class an abtract class

18:28 it is in the above paste

18:29 chouser: foomanchoo: no need for genclass there -- just proxy

18:29 foomanchoo: proxy... ok, I will try that. thank you

18:30 Kjellski: thanks chouser, thats what i wanted to know... ^^

18:35 wwood: that worked!

18:35 liverepl cool!

18:36 Kjellski: Congratulations!

18:36 =)

18:38 rads: what's the simplest way to convert :foo to "foo"?

18:38 (str :foo) returns ":foo"

18:39 danlarkin: ,(name :foo)

18:39 clojurebot: "foo"

18:39 rads: thanks

18:40 hiredman: I have come to a conclusion

18:40 ant is horrible

18:40 mtm: all build systems are horrible

18:41 hiredman: make is great

18:41 mtm: does it still require hard tabs?

18:41 hiredman: who cares

18:41 mtm: it offends my delicate sensibilities :)

18:42 authentic: clj noob question: has something like GWT been made for clojure?

18:42 hiredman: I am just sick in tired of ant rerunning everything when nothing has changed

18:42 or not running anything

18:42 authentic: mtm: i'd say all imperative build systems are terrible, ant is full of do-this and do-that rather than make-me-an-X

18:43 mtm: true, true

18:48 Kjellski: Why is this(http://paste.lisp.org/display/89130) function giving me a seq over one element vectors?

18:50 hiredman: becuase you are using conj to create a new vector that contains one more element than an empty vector

18:51 Chousuke: for is not a loop

18:51 ~for

18:51 clojurebot: for is not used often enough.

18:51 djork: hah

18:51 hiredman: and conj does not mutate vectors

18:51 Chousuke: clojurebot: you were supposed to agree with me

18:51 clojurebot: It's greek to me.

18:52 hiredman: clojurebot: laugh

18:52 clojurebot: ha ha

18:52 authentic: clojurebot: cry

18:52 clojurebot: Gabh mo leithscéal?

18:53 Chousuke: Kjellski: You seem to have this silly notion that clojure allows you to *mutate* things. It does, but not until you've passed intermediate level. I suggest you prepare to rewire your brain entirely :)

18:54 djork: I was wrestling with this same thing yesterday.

18:54 cemerick: interesting, looks like transients aren't metadata-friendly

18:55 funkenblatt: authentic: there's clojurescript

18:55 wrt a GWT-like thing

18:56 dunno how complete it is though

18:56 Kjellski: Don´t tell me to rewrite my brain an forget to tell how ...^^

18:56 Chousuke: Kjellski: for generates a sequence, so you can just change the body of your for to "line-char" and you get a sequence of characters, appropriately filtered.

18:57 * djork just had his mind blown

18:57 Chousuke: Kjellski: then you can use either (into [] (for ...)) or (vec (for ...)) or (reduce conj [] (for ...)) to create a vector of those characters

18:57 Kjellski: outch... THAT hurts... btw, today is CAPSLOCK day, isn´t it? ^^

18:57 AWizzArd: rhickey: please delete ticket 197 on assembla (count in hashmaps is already fixed)

18:57 authentic: funkenblatt: thanks, i'll have a look

18:58 hiredman: clojurebot: ticket #197

18:58 clojurebot: {:url http://tinyurl.com/yh7w68h, :summary "Field 'count' not updated correctly for 'PersistentHashMap's when three hashes collide", :status :new, :priority :normal, :created-on "2009-10-15T19:41:24+00:00"}

18:59 Chousuke: AWizzArd: would just closing it do? :/

18:59 in fact, that's probably better than deleting it. just close as invalid or fixed

19:00 Kjellski: clojurebot: ticket #197

19:00 clojurebot: {:url http://tinyurl.com/yh7w68h, :summary "Field 'count' not updated correctly for 'PersistentHashMap's when three hashes collide", :status :new, :priority :normal, :created-on "2009-10-15T19:41:24+00:00"}

19:00 Kjellski: ...sorry...

19:00 lpetit: ouch what a spam on my emailbox !

19:00 AWizzArd: Chousuke: yes

19:00 Chousuke: lpetit: from assembla? :/

19:01 lpetit: yeah

19:01 AWizzArd: lpetit: what do you mean? those 70 mails within 3 minutes? ;)

19:01 lpetit: sure :)

19:01 Chousuke: AWizzArd: Are you not a clojure contributor? If you are, you could just close it yourself.

19:02 lpetit: When Rich commits, he doesn't do half the job ! :)

19:02 Chousuke: lpetit: you can reduce the spamming to bearable levels from the preferences somewhere.

19:02 AWizzArd: Chousuke: nope, not snail mailed the form yet

19:02 Chousuke: heh. should remember those "fixes #123" in the commit message

19:02 lpetit: Chousuke: oh yes, I'll have to dig in the options of assembla maybe ?

19:03 Chousuke: AWizzArd: which commit was it fixed by?

19:03 hmm, b4095306ddc59c1a992c39369f06f1315b97d377 probably

19:04 hiredman: I heard contributors get a secret decoder ring

19:04 Chousuke: well, I marked it as fixed now.

19:04 enjoy your spam

19:04 Kjellski: Chousuke: Thanks a lot... actually I´ve saved the that above to my notes ...

19:05 Chousuke: Kjellski: the key to functional programming is recursion

19:06 instead of looping and mutating the value, you create a new value within the function, and then call the function again on the new value (and possibly other modified parameters) to generate the next value, until you hit the base case

19:07 the "loop" form, while not a function, is recursive like this too; you always need to "restart" the loop by calling recur with the new values.

19:10 AWizzArd: hiredman: when one wears the ring... is one visible?

19:14 hiredman: it is a metacircular ring

19:15 Raynes: The key to functional programming is a functional key. It fits in the lock upside down and right side up. I hear you can even insert it sideways.

19:23 djork: I read the Little Schemer last Summer, but I have a hard time applying it to Clojure for some reason.

19:23 Chousuke: Raynes: but curiously enough, once you turn the key, you will suddenly have two locks.

19:23 djork: I wonder why?

19:23 s/read/did/

19:24 Philosophical question: is the cosmos functional or object-oriented?

19:24 Functional would mean a multiverse.

19:24 Kjellski: Chousuke : thanks for this decription... it brings me steps forward... as i keep reading the same sentences again and again... ^^

19:25 djork: Kjellski: http://www.google.com/search?client=safari&rls=en&q=define:recursion&ie=UTF-8&oe=UTF-8 (notice the "did you mean")

19:25 jasapp: djork: http://xkcd.com/224/

19:25 hiredman: djork: have you see the slides from rhickey's jvmlang summit presentation?

19:25 djork: I think I had them on my desktop for a long time

19:25 glanced at them

19:25 jasapp: yes, hilarious :)

19:26 Chousuke: infinite recursion is not very useful though :/

19:26 The-Kenny: There is another very good one about lisp, but I don't remember the name.

19:26 hiredman: awn quotes like "the future is a function of the present" or some such

19:26 Chousuke: of the past

19:27 and present is (deref universe) :P

19:29 Kjellski: Someone knows who intentionally said the notepad irc thing?

19:30 "IRC is just multiplayer notepad..."

19:31 hiredman: clojurebot: #clojure

19:31 clojurebot: clojure is far closer to perfection then python

19:31 hiredman: bah

19:31 djork: ~clojurebot

19:31 clojurebot: clojurebot is like life: you make trade-offs

19:33 djork: clojurebot: python

19:33 clojurebot: python is ugly

19:33 djork: ouch

19:33 clojurebot: ruby

19:33 clojurebot: Chunky bacon!

19:33 djork: Hear hear!

19:33 clojurebot: Java

19:33 clojurebot:

19:33 djork: this is fun

19:34 clojurebot: c#

19:34 clojurebot: I don't understand.

19:34 djork: neither do I

19:35 jasapp: clojurebot: lisp

19:35 clojurebot: "if you never learnt Lisp, then you never learned to program" -- some rant on some blog somewhere

19:35 Kjellski: ^^

19:36 The-Kenny: clojurebot: brainfuck

19:36 clojurebot: excusez-moi

19:38 ambient: so, are there any clojure versions for the shootout? http://shootout.alioth.debian.org/

19:38 hiredman: clojurebot: #clojure

19:38 clojurebot: this is not IRC, this is #clojure. We aspire to better than that.

19:38 djork: clojurebot: IRC

19:38 clojurebot: Pardon?

19:38 * hiredman is twiddling with the new factoid code

19:39 djork: ambient: I have never seen any, but it would be interesting to see how high you can go.

19:39 ambient: well, you could write non-idiomatic clojure and make it quite fast

19:39 djork: I mean the Java steady-state stuff is pretty much a total hack... and so Clojure would never get that fast.

19:39 it would be interesting to see how idiomatic clojure fares though

19:40 ambient: i did my modular synth functionally, took about 5 seconds to render. imperically the same thing took 100 milliseconds

19:40 djork: imperically?

19:40 ambient: i dont know the word

19:40 djork: or imperatively

19:40 ambient: something like that

19:41 but the slowness might've been because of lazy sequences

19:41 djork: in Java?

19:41 ambient: in clojure

19:41 djork: oh, nice

19:41 how much audio were you producing?

19:41 (hopefully more than 100 ms)

19:41 ambient: 2 seconds

19:41 88k samples

19:42 djork: k

19:42 ambient: but the whole thing's not done yet, so it's just a semi-micro benchmark

19:43 djork: so is it better to set up clojure to run with java -sever

19:43 server

19:46 ambient: i'll tell you when i get to the point where it's actually relevant :)

19:46 performance-wise

19:52 Kjellski: is there a lazy "pi-digits" function in a lib someone knows?

19:57 mattrepl: random question, wasn't there a video posted of Rich Hickey's talk on time/concurrency at the JVML summit?

19:57 google isn't helping

19:57 Qvintvs: does anyone know of a gedit plugin for clojure editing?

19:57 Kjellski: ... enough hacker-quests for today, good night!

19:58 foomanchoo: ah... to-array and into-array.. a bit confusing but finally got it

19:58 hiredman: mattrepl: not yet

19:59 mattrepl: could've sworn I watched it.. weird =) thanks

20:02 scottj: Can you define a stored procedure in MySQL over the jdbc connecting with clojure.contrib.sql?

20:07 somnium: (use 'mongo.config)

20:12 tomoj: wow, apparently you could somewhat easily write your couchdb views in clojure

20:13 The-Kenny: tomoj: Yeah, it should be pretty easy to write a view-server in clojure.

20:13 (I remember seeing one somewhere on github)

20:15 tomoj: cool

20:15 first I must grok couchdb

20:16 The-Kenny: tomoj: http://github.com/tashafa/clutch/blob/master/src/com/ashafa/clutch/view_server.clj

20:16 (I don't know how advanced this server is, I just found it :))

20:18 somnium: http://paste.lisp.org/display/89135 <- any suggestions?

20:48 rhickey: hrm, the first graphic here puzzles me: http://fupeg.blogspot.com/2009/10/concurrency-patterns-java-scala-and.html

20:49 ambient: heh, nice graphics.

20:50 -s

20:53 rlb: I didn't realize that the jvm doesn't support tagged pointers (though it seems there's been some consideration of it).

20:57 Licenser_: I wonder how you can devide Code Correctly by Comprehend

21:00 How does scalar resolves the concurrency part task?

21:02 ambient: i parsed from the text that he meant coding correctly and comprehending are almost the same thing

21:03 so the "/" is not a division, but interchangeability

21:03 Licenser_: :P ambient I know no reason not to make fun out of it

21:08 rhickey: don't let the post draw you down, I is anything but scientific just an personal oppinion from what I can tell after reading

21:16 somnium: I saw on a mailing list that the Lift guy gave a presentation at E-Bay recently, maybe they drank the scala kool-aid while he was there

21:16 Licenser_: heh

21:20 rhickey_: Licenser_: it doesn't bother me at all, just puzzling - I think refs are a much easier thing to understand (managed variables) than switching to message passing, if you haven't been doing the latter

21:20 Licenser_: glad to hear that :)

21:29 so what surprised me most is that scalar is suppost to be faster then java?

21:31 somnium: can scala's actors be coordinated like clojure's refs? (for a consistent snapshot of the world)

21:32 chouser: not likely. actors tend to be more like Clojure agents

21:33 though with actors it usually requires a round-trip message to get their current state

21:33 I think this is true of both erlang and scala actors

21:33 Licenser_: on another note, comojure is darn fast o.O

21:33 somnium: in that case, it seems like the guy who wrote this blog is barely familiar with clojure at all, since he's comparing scala's actors with clojure's refs

21:33 rhickey_: no, he recognizes the coordination difference and notes it at the end

21:33 Licenser_: just for fun I ran apache benchmark against a simple website, it gets 180 reqs/s on my machine

21:37 scottj: Licenser_: a simple compojure website right? Have you done any similar benchmarks against simple php/apache or other apps?

21:37 Licenser_: scottj: with ruby I don't tuch PHP

21:38 not the exact same thing but a simple RoR is a good bit slower I think it was < 100

21:39 but again RoR does a lot of things like caching & stuff the compojure app is really stupid about it right now - no caching no nothing

21:43 wow after warming up its get to 250 reqs/s

21:45 devlinsf: Hey, does anyone know why there are 100 patches being applied right now?

21:45 rhickey_: devlinsf: just merging master into a branch

21:45 devlinsf: Oh, okay

21:45 Thanks :)

21:51 Licenser_: by the way, why did you people choose git over svn?

21:52 disclaimer: No I don't want to start a flame war about git vs svn I just am curiose since I often think about using git instead of svn

21:53 Raynes: Licenser_: Because Git is better than SVN. ;)

21:53 Licenser_: I heard that I just wonder what features are important for the decision ^^

21:53 The-Kenn1: Raynes: Simple answers are the best answers :)

21:53 rlb: Don't hear about too many people switching back...

21:54 The-Kenn1: Licenser_: Because it's decentral, you have the whole history of the project on your harddrive. Really cheap and easy branching is also cool.

21:54 Licenser_: that makes sense actually, I hate branching in SVN, or actually not branching but merging

21:55 The-Kenn1: Licenser_: You should try git. Then try forking a project in Github and you will never switch back to svn :)

21:56 Licenser_: heh I downloaded a few things from github via git, was nice and easy I've to admit

21:57 but I'm not sure if the 'fork everything' thing is in the end good, I mean do we really need *checks* 42 forks of clojure

21:57 while I agree that 42 is a very good number of forks

21:57 The-Kenn1: Licenser_: It's easy to merge back changes.

21:57 chouser: clojure was on google code svn for a quite a while

21:57 Licenser_: hmm so forks are like branches?

21:58 The-Kenn1: Licenser_: Yes. But a bit more than that.

21:58 Licenser_: ahhh okay, I always had the impression that forks are really forks of the project

21:58 I mean always

21:58 Usually when you read about a fork it means a copy of the project because someone thinks they can do it better :P

21:59 at least that is how I used it

21:59 The-Kenn1: They are, but git and especially github makes it very easy to merge back changes from other users.

21:59 Licenser_: Maybe they can. If the owner thinks that someone improved his project, he merges the changes back into the original :)

22:00 Licenser_: I noticed that rhickey himself had like 4 or 5 fokrs that makes 42 forks look a lot scarry

22:01 The-Kenn1: Licenser_: These are branches..

22:01 Forks are under the "networks" tab: http://github.com/richhickey/clojure/network

22:01 (They are 41+1 forks :))

22:02 Licenser_: I see 4 forks from rhickey in ther

22:02 o.O I just checked rails has over 700 good greif

22:02 chouser: github forks are just a way to manage your own set of patches against a project

22:02 The-Kenn1: rails is a popular project :p Ruby is big on Github.

22:03 rlb: Licenser_: one key is that git makes all kinds of things *possible* that just aren't possible with say svn -- then you get to decide what you actually want to do.

22:03 * Licenser_ nods

22:03 Licenser_: I'll think I'll try git out for my next project just to get a feel for it

22:03 mudphone: git == ozmm

22:03 Licenser_: the console output of git looks a lot nicer then the one of svn :P

22:04 rlb: git provides quite a bit of mechanism, and you get quite a bit of freedom wrt policy.

22:04 Licenser_: ^^

22:04 mudphone: you can get colorization of the output too

22:05 and tab-completion of commands... and set up aliases... :)

22:05 Licenser_: yea tab completion is eays I fiddled that together for svn too, it was even completeing file names depending on the action you choose ^^

22:06 then again svn up, and svn commit is what I use 95% of the time

22:06 The-Kenn1: Licenser_: git will give you completion for commands, files, branches, tags and everything :)

22:06 mudphone: I suppose the killer feature for me is branching, painlessly

22:07 jasapp: somnium: have you gotten very far with mongodb and clojure?

22:07 somnium: jasapp: yeah, already used it on two projects, right now I'

22:07 jasapp: extracting a library so I don't have to copy paste anymore

22:07 jasapp: how are you going storing objects in mongo?

22:08 somnium: jasapp: one of the maintainers fixed a bug so clojure hashmaps go right in

22:08 jasapp: a bug in mongo, or clojure?

22:09 somnium: strings and numbers, vectors and hashes go in, object-ids are a special object, but they're not hard to coerce to and from strings

22:09 in mongo, the json reader wasn't storing nested maps, but he fixed in about 5 minutes when I asked

22:09 pretty good service :)

22:09 jasapp: nice, how recently was this?

22:10 djork: is a seq generated by iterate memoized or anything?

22:10 somnium: you can also teach the java api to serialize arbitrary objects, but thankfully in clojure we don't need this too much

22:10 jasapp: a couple days ago? the latest on github has the patch, I don't think he bumped the version number

22:10 jasapp: awesome

22:10 somnium: I'll probably put my wrapper on github once its a little polished

22:10 Licenser_: hmm that sounds damn handy

22:10 somnium: but the java api is pretty easy as it is

22:11 jasapp: yeah, that's what I've been using

22:11 although, I've been using their json utils

22:12 as well as contrib.json

22:12 it's pretty ugly

22:13 Licenser_: one of the good things to hang out in the channel is that one can read up about new tech when others are talking abou it :P

22:15 jasapp: cool, thanks for the info

22:15 I'll keep an eye out for your wrapper

22:16 somnium: jasapp: you don't have to use json, if you coerce everything to a string or number, you just do (doto (BasicDBObject.) (.putAll {"some" "random" "clojure" ["data" "structure"]}))

22:17 my library is just some config helpers and some coercion utils, maybe in a day or two? (want to finish it tonight, but I should turn off irc to do that)

22:17 jasapp: that'll certainly clean things up

22:17 my code was ugly, but the queries were even worse.

22:18 somnium: I made some wrappers for those too!

22:18 right now just (fetch :mycollection :where {:foo "is bar"})

22:18 jasapp: wow

22:19 well, if you need any help, I'd be happy to

22:19 but it sounds like you've got it taken care of

22:20 somnium: my acct is somnium, 0.00001 up in a day or two? I'll be happy for contributions, I think it does really well with clojure

22:20 jasapp: ok

22:26 djork: so apparently (take 10000 (fib-seq)) runs out of memory

22:27 Licenser_: djork: give it more memory :P

22:27 djork: I actually meant to use nth not take ;)

22:27 Licenser_: teehee

22:27 djork: still trying to grok this lazy-seq generation business

22:28 Licenser_: I find it funny, I made a primes lazy seq ^^

22:28 not that I need it or it would make sense, but it was fun :P

22:28 somnium: djork: it sounds like its 'holding-the-head'

22:29 foomanchoo: a proxied class, with an overwritten method, can or can not access a protected field? (it seems it can not)

22:29 djork: this particular implementation just doesn't click with me, maybe someone could help explain it

22:29 http://www.pastie.org/666176

22:30 hmm, I think I prefer it like this now (edited)

22:33 OK so lazy-seq just takes one expr and doesn't evaluate it until a seq operation is called on it?

22:37 somnium: ,(macroexpand-1 '(lazy-seq (iterate inc 1)))

22:37 clojurebot: (new clojure.lang.LazySeq (fn* [] (iterate inc 1)))

22:37 djork: hah, nice

22:38 that helps

22:38 somnium: er, bad example, iterate is already lazy

22:38 djork: :)

22:39 ,(macroexpand-1 '(lazy-seq (cons 1 (inc 1))))

22:39 clojurebot: (new clojure.lang.LazySeq (fn* [] (cons 1 (inc 1))))

22:40 djork: ,(macroexpand-1 '((fn rfib [a b] (cons a (lazy-seq (rfib b (+ a b))))) 0 1))

22:40 clojurebot: ((fn rfib [a b] (cons a (lazy-seq (rfib b (+ a b))))) 0 1)

22:40 djork: hmm that was not what I was looking for

22:41 oh well I think I get it now

22:41 chouser: foomanchoo: proxy cannot access protected fields

22:41 somnium: ,(source iterate)

22:41 clojurebot: java.lang.Exception: Unable to resolve symbol: source in this context

22:42 foomanchoo: chouser: thanks. any ways to work around this?

22:42 chouser: foomanchoo: unfortunately. For now you'll have to use gen-class after all.

22:42 foomanchoo: ok... i can't seem to grok gen-class. any good examples?

22:43 chouser: foomanchoo: uber-proxy is coming (related to new new a.k.a. reify)

22:43 foomanchoo: cool, i might just create a plain old java class for now and move on

22:44 Licenser_: what the hell is reify doing? it sounds look food

22:45 hiredman: ~google reify

22:45 clojurebot: First, out of 23600 results is:

22:45 Reification - Wikipedia, the free encyclopedia

22:45 http://en.wikipedia.org/wiki/Reification

22:45 chouser: that's not unreasonable. gen-class can do it in a couple lines to, but if you're comfortable with a little java class you won't be bad off.

22:45 hiredman: I think reify still doesn't let you create pedal to the medal named classes, which is kind of a pain

22:46 you can instantiate and invoke Fns

22:46 Licenser_: " the consideration of an abstraction or an object as if it had living existence and abilities; at the same time it implies the thingification of social relations"

22:46 hiredman: which is how I bootstrap my reader

22:47 Licenser_: ~help

22:47 clojurebot: http://www.khanacademy.org/

22:47 Licenser_: hrm that was not what I was looking for o.O

22:49 somnium: I didn't know thingification was a word

22:52 Licenser_: well now it is!

22:52 wokipedia saied that (amongst other things) about rify

22:52 b

22:52 u

22:53 but it is right we should treat clojurebot better, he has dignity too!

22:53 or is clojurebot female?

22:54 hiredman: hmmm

22:54 I guess I should add tests to clojure.test-clojure.reader as I find things I left out of my reader that the tests don't catch

22:54 Licenser_: I think we should rename ',' to 'Good day Mr. Clojurebot, could you please be so kind and evaluate <code> for me'?

22:54 somnium: I saw something about it being a bad idea to have functions in data, but what's the problem with having a map like {:fun-a (fn [x] x) :fun-b ...} ?

22:56 Licenser_: why is it bad to have functions in data? Isn't that one of the good things that of first class functions that you can put them in data?

23:24 technomancy: somnium: nothing wrong with that

23:25 Licenser_: hmm reading p about the mongodb thing makes me really curiose to try that out

23:25 somnium: technomancy: ok, in my current case I was having trouble envisioning an alternative.

23:26 technomancy: somnium: of course the person who warned you may have more context... you shouldn't put fns in a map if another alternative like multimethods would be more appropriate.

23:29 somnium: technomancy: I saw it in an old message on a mailing list. (couldn't find it just now). In this case its a hook for users to add predicates to a library.

23:33 chouser: multimethods allow for dynamic redefinition where fns in data objects do not

23:33 on the other hand, clojure.zip is implemented with functions stored in metadata, so it can't be all bad. :-)

23:34 technomancy: chouser: not to mention clojure.test... (though the reasoning behind that one escapes me utterly)

23:35 Licenser_: fuctions stored in metadata?

23:36 somnium: do multi-methods transcend namespaces?

23:37 chouser: somnium: no, multi-methods are rooted in namespaces

23:37 hiredman: multimethods are not names

23:37 chouser: I guess defmethods transcend namespaces, but defmultis create namespaced vars

23:38 somnium: defmethods do?

23:38 then that's a more elegant alternative

23:39 Raynes: Dynamic failcat fails at runtime.

23:42 jasapp: somnium: have you had trouble with mongo serializing keywords correctly?

23:43 (doto (BasicDBObject.) (.putAll {:foo :bar}))

23:43 somnium: jasapp: it doesn't do keywords

23:43 jasapp I use clojure.walk to coerce members

23:43 jasapp: Ahh, I didn't realize

23:43 somnium: if performance is really a concern better to use strings or implement DBObject, but I like the pleasantness of using keywords

23:44 at least for the scale of what I've been doing so far

23:44 jasapp: Hmm, I'm not sure if it'll be a concern

23:44 How large are your data sets typically?

23:45 somnium: in current case 100,000 records, but small number of users

23:46 premature optimization is the root of all evil :)

23:46 jasapp: That's what I keep telling myself

23:46 I'll see how clojure.walk works for me

Logging service provided by n01se.net