#clojure log - Feb 01 2012

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

0:53 aphyr: Out of curiosity, how expensive is deref in clojure?

0:53 Safe to call, say, 250K/sec?

0:54 G0SUB: aphyr, vars are getting deref-ed all the time.

0:54 aphyr, in 1.2 all vars are dynamic, for example. so I guess it should be pretty fast.

0:55 ibdknox: it depends entirely on what you're derefing

0:56 aphyr: ibdknox: (ref (NonBlockingHashMap.)) in this case.

0:57 I've been using it to allow an aleph server to change its underlying configuration after being started

0:57 But now I'm wondering if I should build some kind of reload functionality instead

0:57 ibdknox: ,(time (loop [i 0] (when (< i 250000) @x (recur (inc i)))))

0:57 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: x in this context, compiling:(NO_SOURCE_PATH:0)>

0:57 ibdknox: ,(let [x (atom 1)] (time (loop [i 0] (when (< i 250000) @x (recur (inc i))))))

0:57 clojurebot: "Elapsed time: 75.945 msecs"

0:57 ibdknox: ,(let [x (ref 1)] (time (loop [i 0] (when (< i 250000) @x (recur (inc i))))))

0:57 clojurebot: "Elapsed time: 100.592 msecs"

0:58 ibdknox: it appears that will not be an issue

0:58 :)

0:58 G0SUB: ibdknox, :-)

0:58 aphyr: Haha, apparently not. :)

0:59 ,(time (loop [i 0] (when (< i 250000) (recur (inc i)))))

0:59 clojurebot: "Elapsed time: 21.745 msecs"

0:59 aphyr: ,(time (loop [i 0] (when (< i 250000) (recur (inc i)))))

0:59 clojurebot: "Elapsed time: 20.966 msecs"

0:59 aphyr: So ~80ms for the var deref

1:00 out of a 1-second timeslice, 8%... hmm. Might be worth investigating actually.

2:33 pyr: hi

2:33 G0SUB: pyr

2:34 pyr: does read-string "intern" strings on the jvm, thus making use of permgen space

2:34 G0SUB: pyr, literal strings are interned.

2:35 pyr: as well as keywords

2:35 i have a permanent process that reads of a queue

2:36 and does read-string on the input

2:36 i see constant permgen space growth

2:36 which i don't understand

2:42 G0SUB: pyr, -XX:MaxPermSize=128m -XX:PermSize=128m might be the only option.

2:42 * aphyr perks up

2:43 aphyr: Wait, so any string created with read-string is on permgen?

2:43 raek: keywords are always interned (by Clojure), but strings are not always

2:43 G0SUB: pyr, apparently interned strings are GCs as expected - http://stackoverflow.com/questions/1091045/is-it-good-practice-to-use-java-lang-string-intern/2012661#2012661

2:44 raek: string literals in function bodies tend to be identical

2:45 anyway, the Clojure reader does not call .intern on the strings, IIRC

2:45 ,(identical? (read-string "\"foo\"") (read-string "\"foo\""))

2:45 clojurebot: false

2:46 raek: ,(identical? (name (read-string "foo")) (name (read-string "foo")))

2:46 clojurebot: true

2:47 raek: the names of keywords and symbols are, though

2:47 aphyr: ,(.get (System/getenv) "PWD")

2:47 clojurebot: #<AccessControlException java.security.AccessControlException: access denied (java.lang.RuntimePermission getenv.*)>

2:47 aphyr: ha

2:48 I actually could use some sandbox code right now... good to know

2:48 pyr: raek: yup, but i clearly don't have enough keyword read in

2:48 raek: to justify the growth i'm seeing

2:58 Jachy: Is there a way I can do (def (symbol ...) val) outside a macro?

3:15 raek: Jachy: not with 'def', no.

3:16 there is intern though

3:18 Jachy: raek: That looks useful, thanks.

4:04 clj_newb: is it possible to ahve two separate instances of clojure share the same jvm?

4:04 for example, I have a simle digital led clock writen in clojure -- I think ti's a bit overkill to have it have its own jvm instance

4:05 simonj: Hi all. Confused as to the non-laziness of the returned Seq from this function. https://gist.github.com/1716056

4:22 pyr: alright, so given a huge list of strings containing pr-str'd maps

4:22 if i do: (let [m (doall (map read-string huge-list)] (Thread/sleep 10000) (println "saw: " (count m)))

4:23 i see a permgen increase which doesn't get freed up

4:23 using CMSClassUnloadingEnabled and UseConcMarkSweepGC

4:23 doesn't change a thing

5:33 yawNO: i often see in clojure libs (defn ^

5:33 what is that?

5:33 *def ^

5:35 ivan: yawNO: are you asking about metadata?

5:35 yawNO: i dont know asd

5:35 i've been clojuring for like

5:35 3days?

5:35 so im really kinda noob right now :P

5:36 ivan: ^{:a 1} (fn) attaches {:a 1} as metadata to (fn)

5:36 see also with-meta and meta

5:36 yawNO: okay got it

5:36 thx :D

5:37 yeah i know with-meta and meta :D

5:37 Martijn2: I just installed lein and made anew project based on clojure 1.2.0 and clojure-contrib 1.2.0 When I do (require 'clojure.contrib.str-utils) I get this error:

5:37 java.lang.NoClassDefFoundError: clojure/lang/RT (NO_SOURCE_FILE:0)

5:37 what is going on?

5:39 sorry, problem solved

6:40 cemerick: totally OT, but: does anyone else find it totally bizarre that the 13" Macbook Pro has a lower screen resolution than the 13" Macbook Air?

6:42 ordnungswidrig: cemerick: yes, me. now as I know the fact.

6:46 Borkdude: I installed rlwrap on my mac. how is "lein repl" supposed to use it for completion?

6:48 lucian: Borkdude: rlwrap lein repl

6:48 it literally wraps your commands

6:48 Borkdude: lucian: how does it do autocompletion then?

6:48 jondot: my first hit at useful clojure code - a ring middleware: https://github.com/jondot/ring-ping/blob/master/src/ring/middleware/ping.clj ==> anyone care to take a look and point some aweful newbie pitfalls to me?

6:48 lucian: Borkdude: oh, completion? sorry

6:48 Borkdude: for that you'd need some machinery in lein i think

6:48 cemerick: Borkdude: I can't see how rlwrap would help with completion.

6:49 lucian: cemerick: it can, actually. there was a small hack i saw for the regular clj

6:49 cemerick: command history and editing, yes.

6:49 lucian: cemerick: rlwrap can search a file of completions when you press tab

6:49 Borkdude: cemerick: command history also worked without rlwrap on my mac

6:49 lucian: Borkdude: you could generate such a file with (find-doc) or something

6:49 cemerick: lucian: oh; that's not really completion tho. :-)

6:50 Borkdude: not very intelligent completion anyway ;)

6:50 lucian: https://github.com/technomancy/leiningen/pull/381

6:50 it's terrible, really

6:50 don't bother

6:50 cemerick: Borkdude: lein will be getting some baked-in completion shortly.

6:51 Borkdude: I have some students who are trying out clojure, they used a console for it, so I thought it could be handy for them

6:52 cemerick: Borkdude: this is likely to be the new frontend for lein's repl: https://github.com/trptcolin/reply/

6:56 lucian: cemerick: that reply thing is awesome

6:56 it has precisely the features i want, and nothing else

6:57 Borkdude_: cemerick: totally cool, autocompletion works

6:58 cemerick: lucian: you want more, you just don't know it yet ;-)

6:58 lucian: cemerick: heh

7:06 cemerick: G0SUB: you have a MBA, right?

7:18 G0SUB: cemerick, lol!

7:18 cemerick, not at all. I have a BS in CS, that's all.

7:18 cemerick: Macbook Air :-P

7:18 G0SUB: cemerick, haha

7:18 cemerick, yeah, 11" MBA :-)

7:19 cemerick, the same as cgrand

7:19 cemerick: G0SUB: I take it the SSD makes up for anything the CPU is lacking, then?

7:19 Fossi: lol

7:19 best ever

7:19 you should put that on your business card XD

7:20 G0SUB: Fossi, ;-)

7:20 cemerick, I agree. and the CPU isn't that bad either.

7:31 cemerick, cgrand, ninjudd & I have the same MBA.

8:01 shales: Hi, does anyone know what version of mongodb 4clojure requires?

8:06 romain_p: Hi everyone, what is the best way of turning {:a #{:foo :bar}, :b #{:baz}} into [[:a :foo] [:a :bar] [:b :baz]] ?

8:07 lucian: maybe something like (map vec your-hash)

8:08 romain_p: ,(map vec {:a #{:foo :bar}, :b #{:baz}}

8:08 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: EOF while reading>

8:08 romain_p: )

8:08 ,(map vec {:a #{:foo :bar}, :b #{:baz}})

8:08 clojurebot: ([:a #{:foo :bar}] [:b #{:baz}])

8:08 romain_p: hmmm no

8:09 lucian: close, just vec again on the set

8:13 ,(map (fn [item] [(first item) (vec (second item))]) {:a #{:foo :bar}, :b #{:baz}})

8:13 clojurebot: ([:a [:foo :bar]] [:b [:baz]])

8:14 lucian: nvm, i must've misread

8:23 romain_p: lucian: thanks!

8:24 oops no

8:24 lucian: romain_p: it's not what you asked

8:24 shales: ,(mapcat (fn [[k v]] (map vector (repeat k) v)) {:a #{:foo :bar}, :b #{:baz}})

8:24 clojurebot: ([:a :foo] [:a :bar] [:b :baz])

8:24 shales: that work?

8:24 romain_p: shales: yup that does it, cheers

8:25 babilen: How can I influence the sort order of records? I essentially want them sorted by field1 first, then field2, … What would be a good approach?

8:32 llasram: babilen: Have the records implement Comparable?

8:32 babilen: llasram: Not yet - I figured that something like this would be the best approach, but wanted to ask first.

8:35 llasram: Ok. I'm pretty sure that's the best/only way to do it

8:36 babilen: llasram: Can you, by chance, provide pointers to documentation on how to achieve this (easily)?

8:40 llasram: babilen: Just the normal way you implement interfaces for defrecords/types. Some general examples at: http://clojuredocs.org/clojure_core/clojure.core/defrecord

8:40 babilen: I am not sure how to achieve this, but figure that implementing a comparator (for e.g. sorted-set-by) is another option. (which is as far as my knowledge is concerned easier)

8:42 llasram: babilen: Here's a specific simple example: https://refheap.com/paste/527

8:43 You can also just pass a comparator (just a function returning {-1,0,1} for any argument pair) whenever you need to sort

8:43 babilen: llasram: Thanks -- Is it important that I implement in a way that allows comparison between different types or is that checked earlier?

8:44 llasram: Normal rules apply: only if you care about inter-type sorting.

8:44 babilen: llasram: I don't (at least not right now)

8:46 llasram: Ah, and the `sort' default behavior just throws an exception anyway with different types intermixed. You'll definitely need to pass in a comparator if you ever do want anything sane to happen in those cases :-)

8:50 raek: babilen: one way is to implement Comparable, and one way is to implement Comparator. one thing that's convenient is that functions of two arguments implement Comparator

8:50 babilen: llasram: Ok, that makes sense and is good news. Thanks for your kind and great help. Have a nice day!

8:52 raek: ,(sort #(> (.length %1) (.length %2)) ["a" "aaa" "aa"])

8:52 clojurebot: ("aaa" "aa" "a")

8:52 babilen: raek: Ok, great. Well -- I have collections of records and want them sorted by field1, field2 and don't really care about additional fields. (still need to be part of the comparison as sorted-set-by would, for example, remove all elements that differ only in additional fields)

8:53 raek: babilen: you can also use sort-by. it accepts a function that gives another value which is used for te comparisons

8:54 ,(sort-by (juxt length last) [[1 2 3] [1 2] [0 0 10]])

8:54 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: length in this context, compiling:(NO_SOURCE_PATH:0)>

8:54 raek: ,(sort-by (juxt count last) [[1 2 3] [1 2] [0 0 10]])

8:54 clojurebot: ([1 2] [1 2 3] [0 0 10])

8:54 raek: vectors and sequences are compared element wise

8:55 babilen: yeah -- I will try to implement a compare-by-field([:field1 :field2]) → comparator -- that will take additional (i.e. other not listed fields) into account, but sorts by field1 first, then field2, then the rest in no specific order. (alphabetically maybe)

8:55 raek: you can use (juxt :field1 :field2) as the key-fn

8:56 babilen: raek: Indeed - I am just not sure how to deal with the other fields that might be present in the record (yet).

8:56 raek: the ones with the same :field1 and :field2 value will be sorted next to each other in some order

9:00 babilen: raek: Shouldn't be hard though (use (keys rec) to get keys, remove given ones, ...) -- Thanks for your comments as well.

9:05 Kototama: hi, is there a way in SLIME to have slime-repl-previous-matching-input behavior more like the one from term-send-reverse-search-history (like C-r in the console) ?

9:24 noidi: is it not possible to implement two protocols (defined in different namespaces) with the same method name?

9:26 I get "Duplicate method name&signature" when I try to implement foo/Foo with foo/get-xyzzy, and bar/Bar with bar/get-xyzzy in the same reified protocol implementation

9:26 luckily I'm just playing around with this, so it's not a real problem that I'm facing

9:27 this kind of makes namespaces useless when using protocols

9:29 gfredericks: noidi: I don't know the reasoning behind it, but I think each method that you implement gets added as an actual java method on the type, without the namespace, so I'm not sure how that could be resolved

9:31 noidi: yeah, some sort of a name mangling scheme would be needed

9:32 gfredericks: which would be gross for anybody who intended to actually use the methods

9:33 noidi: well, now you need to do the name mangling manually to avoid this problem

9:34 gfredericks: true; I am not equipped to argue about the design choices.

9:34 noidi: or to avoid causing problems for the people who have to implement your protocol, possibly along with other protocols also out of their control

9:34 gfredericks: but hode up

9:34 the exact same problem exists with java interfaces doesn't it?

9:35 noidi: probably. I'm not that familiar with Java.

9:35 gfredericks: yeah, now that I think about it I expect this is a very general problem

9:35 cemerick: noidi: you can implement two protocols with the same signature, etc. without a problem *unless you're doing so inline*

9:36 use extend-type, extend-protocol, or extend to provide protocol impls.

9:36 gfredericks: cemerick: how does it map to method names?

9:36 noidi: cemerick, thanks, I was hoping that it could be possible via extending!

9:36 I'll give that a go

9:37 cemerick: gfredericks: extend* doesn't map to method names.

9:37 That's why it works. :-)

9:37 gfredericks: Indeed!

9:51 noidi: cemerick, brilliant, that works!

9:51 cemerick: :-)

9:52 noidi: inline implementations are really only needed for maximum perf and Java interop.

9:55 noidi: I hope that the times I'll have to implement two Java interfaces with colliding method names will be few and far between

10:08 now if only there was a way to specify contracts directly on the protocol instead of the contract block of each method implementation...

10:09 it seems that trammel doesn't do that (yet)

10:19 cmajor7: is there a "mental rule" on where to use map/reduce/filter vs. list comprehensions?

10:20 gtrak: less/clearer code wins?

10:21 raek: cmajor7: whatever shows the intent of the code the best... :-)

10:23 cmajor7: gtrak, raek: but from a "problem solution" side. besides constantly mentally substituting both approaches ( map/reduce/filter & list compr ), is there certain indicators?

10:24 e.g. list comprehensions would probably make more sense when iterating over multiple seqs where each element in one seq needs to visit each element in the other…

10:24 TimMc: cmajor7: Sure. If you want to walk through a collection one at a time and use the values to hammer on some other value, 'reduce is your friend.

10:25 especially if you are trying to maintain some invariant on that value

10:25 gtrak: reduce is aggregation

10:25 TimMc: reduce is folding

10:25 You're folding values in, one at a time.

10:26 noidi: my own mental rule is that when I use map with a lambda, it probably reads better as a list comprehension

10:26 TimMc: list comprehensions are a Swiss Army knife

10:26 gtrak: Challenge: Implement 'reduce using 'for.

10:27 gtrak: hmm :-)

10:27 TimMc: My gut says you can't.

10:27 gtrak: i can find a way

10:29 TimMc: cmajor7: Given a collection, 'map gives you 1-for-1 collection answer, 'filter gives you a subset, and 'reduce gives you a single value for the whole thing.

10:30 cmajor7: So first, ask yourself which of those results is what you want!

10:31 cmajor7: TimMc: thank you. interesting.. I do understand map vs reduce vs filter. I am on list comprehensions vs map/filter/reduce… is there a difference in performace? e.g. reduce only walks once over all the seqs given and grows the accumulator, where if multiple seqs are given to "for" e.g. for [s1 (range 1 10) s2 (range 1 10)], it will walk seq2 completely for each element in seq1…

10:31 noidi: with my rule: (map #(* 2 %) (filter #(> % 5) (range 10))) --> (for [x (rang 10) :when (> x 5)] (* 2 x))

10:32 babilen: noidi++

10:32 TimMc: cmajor7: I can't imagine the performance would be different enough to care about.

10:34 cmajor7: TimMc: { btw, I also find that in several cases reduce gives you a subset => similar to a filter. the true difference between "reduce" and "filter" in my understanding, is that "reduce" would have an accumulator, which allows a _new_ seq, rather than just a subset of the existing seq that "filter" does }

10:34 TimMc: Yes, you can certainly implement filter and reverse and so forth using reduce.

10:34 and map, for that matter

10:35 &(reduce #(conj %1 (* 3 %2)) [] (range 10))

10:35 lazybot: ⇒ [0 3 6 9 12 15 18 21 24 27]

10:36 TimMc: &(reduce #(cons %2 %1) () (range 10)) ; reverse

10:36 lazybot: ⇒ (9 8 7 6 5 4 3 2 1 0)

10:38 TimMc: gtrak: I think 'for can produce a collection with at minimum the number of elements that :when and :while let through.

10:39 Oh, and it always produces a collection, so you *can't* do it without at least some post-processing.

10:39 gtrak: I think there's no reason for not being able to reduce with a for, but i can't make my code work at the moment, I'm rusty :-), my basic idea is for x in the range of the length, swap an accumulator atom

10:39 TimMc: Ugh, that's terrible!

10:39 gtrak: reduce isn't lazy either

10:40 TimMc: Yeah, that's the kicker, I think.

10:41 cmajor7: seems that 'list comprehensions in fact is somewhat close to a noidi's idea of "map + filter" application to seq(s). :while is an interesting one.. would 'list compr actually stop a seq walk on the first "while false"?

10:41 TimMc: &(for [a [(atom 0)] x (range 6)] (swap! a (partial + x))) ;; reductions

10:41 lazybot: ⇒ (0 1 3 6 10 15)

10:43 TimMc: cmajor7: :while will stop the current iteration only, and only at that level.

10:45 shales: does anyone know what version of mongodb 4clojure requires?

10:45 cmajor7: &(dorun (for [col "ABCD" :when (not= col \B) row (range 1 4) :while (< row 3)] (println (str col row))))

10:45 lazybot: ⇒ A1 A2 C1 C2 D1 D2 nil

10:45 TimMc: &(for [l0 '[a b c], l1 '[1 2 3] :while (< l1 3), l2 '[d e f]] (str l0 l1 l2))

10:45 lazybot: ⇒ ("a1d" "a1e" "a1f" "a2d" "a2e" "a2f" "b1d" "b1e" "b1f" "b2d" "b2e" "b2f" "c1d" "c1e" "c1f" "c2d" "c2e" "c2f")

10:46 cmajor7: TimMc: so the iteration actually stopped when a row became 3?

10:46 TimMc: cmajor7: Correct.

10:47 cmajor7: cool. so it is quite "controllable".. nice

10:47 TimMc: and :let makes it even better

10:49 noidi: just think of `for` as a fancy `map` :)

10:50 cmajor7: I still feel I would need to right many more maps/reduces/filters & listcomps to get the true feeling on when the one is more applicable.. but appreciate all the thoughts.. very cool.

10:51 noidi: 'map can't really iterate over multiple collection matching each element of one collection to all elements of another ( unless there is an internal map/reduce ). while 'listcomp can and does that. or am I missing something?

10:51 *over multiple collections

10:52 noidi: it can't. you'll need something like (map (fn [x] (map f x)) xs)

10:52 TimMc: cmajor7: It can, the result is just a collection of collections.

10:52 gtrak: you can do it with map, but it'd be really awkward?

10:52 TimMc: mapcat takes care of that.

10:53 gfredericks: you could do X with just a bunch of lambdas also

10:53 TimMc: cmajor7: 'for is great for unrolling nested collections, by the way.

10:53 cmajor7: doesn't mapcat just flatten the result of mapping?

10:53 TimMc: Yeah, but it does the mapping too.

10:54 cmajor7: but not on nested collections..

10:54 e.g how would you do this

10:54 &(dorun (for [col "ABCD" :when (not= col \B) row (range 1 4) :while (< row 3)] (println (str col row))))

10:54 lazybot: ⇒ A1 A2 C1 C2 D1 D2 nil

10:54 cmajor7: with a single map/mapcat?

10:54 TimMc: without the :when and :while, of course

10:56 &(mapcat (fn [c] (map (fn [r] (str c r)) (range 1 3))) "ABC")

10:56 lazybot: ⇒ ("A1" "A2" "B1" "B2" "C1" "C2")

10:56 cmajor7: right => 2 maps

10:56 TimMc: sure

10:56 which is equivalent to a 2-level 'for

10:57 cmajor7: yep.. so another mental rule would be.. "think about 2> maps? try 'it' with for"

10:57 (thinking out loud)

10:57 TimMc: yeah, cartesian joins

10:58 cmajor7: is there an appealing case to use 'for vs 'map on a single seq?

10:59 ( I meant 'for vs. 'map/'filter/'reduce )

10:59 gfredericks: cmajor7: I like map with named functions and for with inline functions

10:59 TimMc: Sure, when the lambda is of moderate complexity and depends on a bunch of local s

10:59 cmajor7: besides the laziness of the result of course

10:59 TimMc: cmajor7: 'for is lazy

11:01 cmajor7: TimMc: "when the lambda is of moderate complexity and depends on a bunch of local s" => this would be strictly a readability advantage, right? [not saying it is not enough of an advantage though]

11:12 TimMc: cmajor7: A lamba of moderate to high complexity should generally be extracted as a separate named function, but if you'd have to pass it a crapload of locals, it *might* be better to keep it inline in a 'for.

11:13 cmajor7: TimMc: yep, makes sense. thank you.

11:13 gfredericks: (> (count locals) crapload)

13:04 muhoo: these instructions assume i have a pom.xml file. i don't. this is lein, i have a project.clj and it looks like the dependencies are there instead. http://devcenter.heroku.com/articles/local-maven-dependencies

13:05 how woudl i translate those instructions from maven into lein?

13:05 technomancy: muhoo: I recommend using this instead: https://github.com/technomancy/s3-wagon-private

13:05 should see about getting that devcenter article to mention it

13:06 TimMc: technomancy: But otherwise, you would just add a file: repo to your project.clj, right?

13:06 muhoo: technomancy: very cool, thanks!

13:08 technomancy: TimMc: yeah, but ... binaries in git; yuck.

13:08 muhoo: i don't mind having it on s3. and yes, binaries in git makes my skin crawl

13:09 in fact, i don't even need credentials, i expect i could do this over http too

13:09 this stuff isn't private or confidential, it's just not in anyone's maven repo

13:09 technomancy: oh yeah, in that case you can use http

13:18 gtrak: ha, rich hickey calls { a curly in his vid, I'm vindicated

13:31 maio: which version of Clojure is prefered for newbies?

13:32 sritchie: do you guys any recommendations on how to check equality of two regexes?

13:32 ,(= #"string" #"string")

13:32 clojurebot: false

13:32 sritchie: I guess this works:

13:32 ,(= (.pattern #"string") (.pattern #"string"))

13:32 clojurebot: true

13:32 technomancy: sritchie: yeah, that kills me

13:32 gtrak: maio: check out https://github.com/arthuredelstein/clooj

13:33 * Raynes doesn't understand why people use or recommend clooj.

13:34 sritchie: technomancy: I wonder why implementation isn't value-based

13:34 gtrak: i don't use it, i recommend it for people to play around with? remind me of drscheme

13:35 except, now that I try it, it doesn't work at all :-)

13:35 cemerick: maio: just grab leiningen, and you can get started in the REPL in a snap

13:36 alternatively, there are plugins for all the major Java IDEs and emacs

13:36 faust45: what is the best way to dispatch method for empty list and not empty list?

13:36 cemerick: maio: http://dev.clojure.org/display/doc/Clojure+Tools

13:37 faust45: so i have two cases for empty list return '() and for not empty return lazy-seq

13:37 but i wish to avoid (if code

13:37 Raynes: gtrak: I mean, clooj would be a good way to get started if it even supported syntax highlighting.

13:37 gtrak: Raynes: yea, I thought it was further along than it is

13:38 Raynes: There are Clojure plugins for generally every popular editor/IDE and it is almost certain that any given person coming to Clojure is already familiar with one of them. I just don't know where clooj fits in.

13:38 maio: <- Vim guy :) I'm asking because I every now and then I end with "Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodError: clojure.lang.KeywordLookupSite" errors

13:38 Raynes: Not to dismiss the fellow's work. It is quite admirable.

13:39 maio: I use Vim too (these days, anyways). :>

13:39 It is an excellent environment for Clojure.

13:40 raek: maio: try creating a new temp project, change the clojure version to "1.2.1", run lein deps, delete the temp project

13:41 technomancy: you're pulling in a broken plugin that declares its own version of Clojure

13:43 maio: yes. (this time) It started when I installed nailgun plugin

13:43 rlb: faust45: multiple function bodies, perhaps? (defn foo ([] 42) ([&x] 13))

13:44 maio: is there something I can do about it?

13:44 faust45: rlb: (defn foo []) not work for me if call (foo '())

13:47 cemerick: faust45: An empty seq can be a number of different concrete types. Just use a conditional. (if (seq x) y z)

13:48 faust45: cemerick: LazySeq never become EmptyList

13:49 type

13:49 cemerick: so its impossible dispatch on type

13:50 cemerick: faust45: of course it can. &(class (rest (lazy-seq [1])))

13:50 uh, lazybot?

13:50 ,(class (rest (lazy-seq [1])))

13:50 clojurebot: clojure.lang.PersistentList$EmptyList

13:51 cemerick: faust45: you can dispatch on type, it's just hardly ever a good idea. What are you actually trying to accomplish?

13:51 faust45: clojurebot: great )

13:51 clojurebot: Titim gan éirí ort.

13:51 Raynes: cemerick: ##(class (rest (lazy-seq [1])))

13:51 lazybot: ⇒ clojure.lang.PersistentList$EmptyList

13:51 * cemerick can never keep his bot activation symbols straight

13:51 Raynes: cemerick: Don't blame lazybot for your inability to understand him. He is a complex being.

13:52 cemerick: The beatings will continue until lazybot can read my mind.

13:52 Raynes: cemerick: We'd just go with &&(), but that'd blow up in our face for channels where people use languages like Ruby.

13:52 Same with &()

13:52 faust45: cemerick: thanks will try

13:53 Raynes: why you confused about ruby use case ?

13:53 cemerick: Raynes: I figured you'd set up per-channel characters.

13:54 Raynes: cemerick: Man, we've set up so much per-channel crap that our config file is like 100 line long and it's all one big map. I'm to the point where anything that requires me to have per-channel configuration, I just disable entirely and forget exists.

13:55 cemerick: I originally planned for lazybot to be an end-user bot, but I don't think any non-programmer in the world could figure it out at this point.

13:59 cemerick: Raynes: are there end user bots?

14:06 amalloy: lazybot ends users

14:08 jsabeaudry: Recommandations regarding a lein clojurescript plugin? lein-cljsbuild looks like it has a lot of features

14:10 * emezeske selfishly gives a +1 to lein-cljsbuild.

14:11 jkdufair: i've been using clojure-mode and the swank-clojure lein plugin. What do i need to use my local emacs to control swank running on a remote server? an explicit slime install? will it conflict with the slime embedded in clojure-mode?

14:12 technomancy: jkdufair: yeah, manual slime install; you can use marmalade

14:12 jkdufair: super. thx.

14:12 technomancy: or if you use an emacs instance that has already jacked in, it'll already have it.

14:12 might be nicer not to rely on that leftover copy though

14:12 jkdufair: how does that work?

14:13 technomancy: how does which work?

14:14 jkdufair: using an instance that is already jacked in? in other words, where is slime in clojure-mode? didn't see it in the sources

14:14 jsabeaudry: emezeske, Out of curiosity, why arent hooks and :jar true the default values in lein-cljsbuild?

14:14 technomancy: it's a "payload" that comes from the swank-clojure jar

14:14 jkdufair: oh fascinating. thx.

14:15 clever idea.

14:16 technomancy: it's insane. =)

14:23 emezeske: jsabeaudry: I don't think there's any way to enable the hooks by default

14:23 jsabeaudry: And the plugin began life without :jar support, so when it was added, we made it default to off for backwards compat.

14:40 jsabeaudry: Ok I got hiccup and clojurescript but what about css?

14:42 fliebel: jsabeaudry: There where some DSLs, but nothing really useful afaik.

14:47 jkdufair: how do i get swank-clojure to listen on an external interface?

14:49 pjstadig: jkdufair: according to `lein help swank` it accepts port and host arguments

14:49 so you should be able to do something like `lein swank 6666`

14:49 jkdufair: pjstadig: thank you. wasn't aware of lein help :-O

14:49 pjstadig: :)

14:56 tscheibl: jsabeaudry: cssgen from paraseba (it's on github) is quite useful

14:57 jsabeaudry: tscheibl, Thanks I'll take a look

14:59 tscheibl: jsabeaudry: i've been using it for quite some time know... for generating css on the fly in compojure routes

15:00 jsabeaudry: it's better than writing css directly because it's composable and supports inline hierarchies

15:00 jsabeaudry: tscheibl, Is that so the users can modify the "skin" of the site?

15:01 tscheibl: jsabeaudry: it renders to pure css ..

15:02 jsabeaudry: I usually create compojure routes which set the Content-Type to "text/css" and return on the fly generated css

15:03 amro: http://hastebin.com/qihujumime.lisp I get java.lang.NullPointerException after the ex[ected pit[it

15:03 expected output*

15:04 jsabeaudry: tscheibl, Yes I was curious to know in which context you would like to generate css on the fly?

15:05 tscheibl: jsabeaudry: you could parameterize it that way

15:05 jsabeaudry: using get query paramters

15:07 jsabeaudry: e.g. using hiccup: (include-css "/main.css?background=green")

15:08 jsabeaudry: in that case you would probably have to add nocache headers to the response

15:10 jsabeaudry: you could also use it to compile static css from clojure files and include these in your html

15:10 rsenior: anyone around that can talk about the build.clojure.org setup?

15:13 tscheibl: jsabeaudry: where maybe cookies would be the best way to make the skin user configurable

15:26 aphyr: tw

16:30 the-kenny: Is there a swank server for clojurescript?

16:33 technomancy: the-kenny: there's one for Javascript, but I've never used it

16:35 the swank-clojure codebase is extremely intertwingled with Java though

16:40 the-kenny: understandable. One would most likely have to write a "real" swank server in clojurescript.

16:40 Also, there's the problem of compilation

16:41 clj_newb: is it possible to define defrecords Foo, Bar, s.t. (.open foo) -> returns a Bar, (.close bar) -> returns a Foo ?

16:44 TimMc: Ah, a circular dependency?

16:44 If you use protocols... maybe?

16:44 clj_newb: yes

16:44 ah, so (.open foo) returns a BarInterface object, and (.close bar) returns a Foo interface object?

16:45 TimMc: Yes, although that might just net you a new circular dep. :-)

16:45 clj_newb: at the interface level ; hmm

16:46 TimMc: Is this part of your scheme to create TYped Clojure?

16:46 clj_newb: sssssh, that could get me lynched

16:46 tjgillies: how do i access functions is projectname.core namespace from lein repl?

16:46 clj_newb: This is part of building my WYSIWYG editor, I'm implementing functional zippers on my own

16:47 tjgillies: s/is/in/

16:47 clj_newb: so there are "closed/open" nodes

16:47 gtrak: tjgillies: use or require

16:47 the-kenny: Let's track clj_newb down and lock him behind 10^100 layers of parenthesis.

16:47 xian: Hi, just a quick question: When I create an uberjar with leiningen, how do I ensure that additional jars specified in :extra-classpath-dirs are available/included in the resulting uberjar?

16:47 clj_newb: and they need to return each other based on open/close

16:47 tjgillies: gtrak: thnx

16:47 brehaut: clj_newb: https://github.com/frenchy64/typed-clojure

16:47 technomancy: xian: only dependencies go into the uberjar

16:47 gtrak: tjgillies: and you can in-ns to switch to your desired namespace, but it won't be compiled until it's require'd i think

16:48 xian: technomancy: Okay, is there an easy way to add arbitrary jar files as dependency?

16:48 clj_newb: brehaut: certain looks interesting thanks

16:48 TimMc: Upload them to clojars

16:48 technomancy: xian: yes, you can publish them to s3, either in a public or private bucket

16:48 clojurebot: repeatability is crucial for builds, see https://github.com/technomancy/leiningen/wiki/Repeatability

16:48 tjgillies: whats the syntax? i keep getting errors

16:48 brehaut: clj_newb: im pretty sure its just experiemental

16:49 tjgillies: (require 'project/core) ?

16:49 TimMc: clojurebot is pondering your request

16:49 gtrak: something like that

16:49 TimMc: tjgillies: got, not slash

16:49 *dot

16:50 clj_newb: brehaut: yeah; but it has interesting links to read

16:50 clojurebot: Ack. Ack.

16:50 TimMc: haha

16:50 tjgillies: TimMc: thnx

16:50 TimMc: ~repeatability

16:50 clojurebot: repeatability is crucial for builds, see https://github.com/technomancy/leiningen/wiki/Repeatability

16:50 clj_newb: on a complete unrelated note, is it just me; or does anyone else have an intense urge to write cocoa apps (osx, ipad) in clojure?

16:50 technomancy: ugh; no

16:51 xian: technomancy: Hmm, I would prefer another way, actually. Uploading them to s3 requires too much work just to get some external jars included in my clojure project.

16:51 technomancy: xian: have you tried it? it's much easier than the alternatives.

16:51 unless you're ok with "works on my machine; good enough"

16:52 TimMc: xian: Do you plan on having other people use your code?

16:52 clj_newb: ah ha

16:52 I think what I need is extend-typ

16:52 e

16:53 xian: technomancy, TimMc: I just put my jars in the lib directory and building the uberjar worked fine.

16:53 TimMc: Not directly. Other people will interact with the uberjar.

16:53 TimMc: clj_newb: Yep, you'll use that after the protocols and records are defined. Have you succeeded in getting both protocols defined?

16:54 clj_newb: TimMc: yeah; there's no circular dependency at the protocal level since there arne't return-type signatures in protocols

16:54 TimMc: Ah, nice.

16:55 clj_newb: is there a book that coers all this stuff?

16:55 I don't see it in programing clojure

16:55 TimMc: clojurebot: private jars is <reply> To depend on private jars, use https://github.com/technomancy/s3-wagon-private

16:55 technomancy: xian: if you don't care about making it work on other machines you can use lein-localrepo to turn standalone jars into real dependencies

16:55 TimMc: clj_newb: It's new in 1.3, how old is the book?

16:55 clj_newb: TimMc: says copyright 2009

16:56 TimMc: Not recent enough.

16:56 clj_newb: is any book recent enough?

16:56 xian: technomancy: Ah, I see. And yes, I only want to build the uberjar on my machine. Others won't interact with the code. Thanks for your help.

16:56 clojurebot: Ik begrijp

16:56 TimMc: I don't know.

16:57 clj_newb: ah, according to amazon, there's a new edition in april 2012

16:57 TimMc: xian: Well, just make sure you leave sufficient breadcrumbs so that you or someone else can figure out how to build it in the future.

16:57 technomancy: cool

16:58 TimMc: clj_newb: Read through the sidebar links on http://clojure.org/, you'll pick up some new stuff.

17:00 tcrawley: technomancy: in lein 2.0, are you doing away with the ability to override :library-path, :resources-path, etc? The lack of defaults in leiningen.core.project leads me to believe that

17:02 technomancy: tcrawley: you can override :resources-path and :source-path and friends

17:02 :library-path is gone altogether; classpaths are constructed directly out of ~/.m2; so there's no more need to gratuitously copy dependencies around.

17:03 TimMc: No more ./lib?

17:03 tcrawley: technomancy: ah, cool - I see :resources-path now, thanks

17:04 gfredericks: how will negligent coworkers accidentally and irrevokably add 30mb of jars to the git repo?

17:04 technomancy: the lib/ directory was more of a historical accident from the days of M-x swank-clojure-project than something actually useful

17:04 gfredericks: I have no doubt their ingenuity will find a way!

17:04 gfredericks: I guess there's still the build outputs

17:04 tcrawley: technomancy: right now, in Immutant we assume lib/, and add the contents to the module class path for the app. if lib/ no longer exists, we'll need to suss the classpath from lein, but I suspect that won't be difficult

17:05 TimMc: tjgillies: `lein classpath`

17:05 tjgillies: Sorry, that was meant for tcrawley

17:05 technomancy: yup

17:05 tcrawley: TimMc: well, it will be a bit more involved that that, but I can find it from there. thanks!

17:06 technomancy: it would be easy to write a copy-deps plugin, but there's just no need to have it built-in

17:06 TimMc: whoa

17:06 I just realized that a meter is basically a baker's yard

17:07 * technomancy steps away briefly

17:07 brehaut: welcome to the future TimMc

17:07 TimMc: high on the metric system

17:08 Sorry. ANYWAY.

17:08 brehaut: the initial euphoria should pass fairly quickly. it'll seem very ordinary in no time

17:09 gfredericks: ha: TIME. When are we switching from years to kilodays?

17:09 TimMc: technomancy: I assume lein2 will be able to use the vast majority of project.clj files out of the box?

17:10 AimHere: Then it stops being fun. You're just thinking in metres, kilometres, kilogrammes, just in order to feel normal each day.

17:10 TimMc: gfredericks: I already say things like "I'll be back in about a metric hour" just to mess with people.

17:10 clj_newb: should I prefix protocols with I or P, i.e. IFoo or PFoo?

17:11 TimMc: clj_newb: From the Java side, they just look like regular interfaces, right?

17:11 I haven't worked with protocols yet.

17:12 clj_newb: I do not know enough about clojure to know.

17:17 lucian: clj_newb: i've seen them prefixed with P. i wouldn't prefix them with anything, though

17:19 jcrossley3: clj_newb: i think the context in which a protocol is used makes the prefixes superfluous. i don't even like using 'em in java, myself.

17:19 hiredman: my irc client only shows me timestamps in kiloseconds since midnight

17:20 TimMc: Which midnight, O /ignore'ant one?

17:20 (UTC would be best.)

17:21 jsabeaudry: Anyone knows how to tell cljsbuild to look into lib so it can find cljs libraries such as pinot?

17:22 clj_newb: hmm; I like my hungarian notation.

17:22 TimMc: clj_newb: As long as it's Apps Hungarian.

17:24 * TimMc uses Reverse Polish Hungarian notation

17:28 emezeske: jsabeaudry: The missing support for that is a bug (that I plan to fix this evening)

17:28 jsabeaudry: emezeske, Sweet! I'll use cljs-watch for the time being

17:30 technomancy: TimMc: yep, the main blocker will be plugins that use Leiningen functions that have moved.

17:32 jcrossley3: clj_newb: TimMc: i don't even think Simonyi uses hungarian notation any more. :)

17:59 the-kenny: emezeske: Nice to hear this. I wated to report this bug today :)

17:59 s/wated/planned/

18:44 emezeske: jsabeaudry, the-kenny: I'm trying to decide how best to fix the lib/ problem. I wonder if everything in :dependencies should be accessible to the cljs project, or if maybe I should add a new :dependencies option to the :cljsbuild config

18:44 Raynes: emezeske: http://blog.raynes.me/blog/2012/02/01/i-code-with-things-and-stuff/ I gibs vim love (and link to your copy of paredit.vim).

18:46 jsabeaudry: emezeske, I would tend to make everything in :dependencies and :dev-dependencies available

18:46 the-kenny: Yup, me too.

18:46 cljsbuilds own :dependencies would lead to a problem with hybrid jars which contain .clj and .cljs (like cljs-uuid)

18:48 emezeske: I guess my only worry is that cljsbuild depends on clojure 1.3.0

18:48 What would happen if the project used 1.2.x?

18:48 Right now, the plugin uses leiningen's eval-in-project to always use 1.3.0

18:49 I'm not a jar expert, but it seems like conflicts could arise (?)

18:49 Raynes: Awesome, I'll have to give that a read-through!

18:50 technomancy: emezeske: yeah, declaring a direct dependency on a project that requires 1.3 will cause issues. you would have to run cljsbuild code inside eval-in-project as well

18:51 emezeske: technomancy: That makes sense. I'm trying to figure out how to allow the cljs code to have jar dependencies

18:52 technomancy: right now it uses eval-in-project and does not assoc in anything from the parent

18:53 technomancy: emezeske: wouldn't it make sense to just say that projects that have clojurescript components can't use 1.2?

18:53 emezeske: technomancy: Hmm, that seems fair. I doubt anyone that uses cljs is not up to 1.3 by this point

18:54 the-kenny, jsabeaudry: Informal survey: are your projects using clojure 1.3?

18:54 TimMc: I'd liek to maintain import-static from old contrib. Any thoughts on how to do this?

18:55 (Should I just fork and delete everything else?)

18:57 the-kenny: emezeske: Yup

18:59 emezeske: the-kenny: Okay, thanks

19:04 cmajor7: what space does "loop/recur" consume? heap?

19:05 TimMc: cmajor7: constant space

19:05 Oh, you mean where does it allocate locals?

19:05 cmajor7: yep. where does it keep the "memories"

19:05 TimMc: ?

19:06 As I understand it, the JVM basically puts everything in the heap.

19:06 cmajor7: well… recursion (unless it is "tail") keeps them on the stack

19:07 ok.. so loop/recur saves the "recursion" point in heap

19:07 right?

19:08 hiredman: it doesn't consume space, that is the point

19:10 cmajor7: hiredman: I see, so it is in a way tailed..

19:10 like:

19:10 fac( N ) ->

19:10 fac ( N, 1 ).

19:10 fac ( 0, Holder ) ->

19:10 Holder;

19:10 fac ( N, Holder ) ->

19:10 gfredericks: cmajor7: that's why loop/recur exists

19:10 cmajor7: fac( N - 1, N * Holder ).

19:10 (erlang)

19:10 hiredman: ~pastebin

19:10 clojurebot: Excuse me?

19:11 hiredman: clojurebot: paste you jerk

19:11 clojurebot: No entiendo

19:11 hiredman: ~paste

19:11 clojurebot: paste is gist

19:11 gfredericks: cmajor7: because the native JVM functions won't do tail recursion

19:11 hiredman: ~gist

19:11 clojurebot: gist is forget paste

19:11 amalloy: hiredman: he can't remember "paste is gist.github.com" because the . ends the factoid

19:11 gfredericks: clojurebot: paste is gist,github,com

19:11 clojurebot: 'Sea, mhuise.

19:12 hiredman: amalloy: that is not true

19:12 ~forget paste |is| gist,github,com

19:12 clojurebot: I forgot that paste is gist,github,com

19:13 amalloy: hiredman: okay. i'd be delighted to learn the right way to teach him, then, becase at least three times i've seen someone teach him gist.github.com and he parrots back just gist

19:13 cmajor7: gfredericks: right. so loop/recur pair takes an existing state, creates a new [single] stack frame, passes the state to that stack frame, and leaves the past to GC?

19:13 hiredman: amalloy: most likely because some taught it 'paste is gist'

19:13 ~gist

19:13 clojurebot: gist is https://refheap.com/

19:13 hiredman: ~paste

19:13 clojurebot: paste is http://gist.github.com/

19:13 hiredman: ~paste

19:13 clojurebot: paste is gist

19:13 hiredman: ~paste

19:13 clojurebot: paste is gist.github.com

19:13 hiredman: ~paste

19:13 clojurebot: paste is http://gist.github.com/

19:14 hiredman: etc

19:14 amro: any idea why I'm getting a NullPointerException with this macro? http://hastebin.com/qihujumime.lisp

19:14 hiredman: amro: to start with docstrings go before arg lists

19:15 to end with, look at the macroexpansion

19:15 gfredericks: cmajor7: I don't know the GC details but it certainly doesn't accumulate space like explicit recursion does

19:16 amro: hiredman: yes, there's an extra pair of () around it

19:16 I don't know how to get rid of it

19:16 hiredman: extra how?

19:16 you have a for

19:16 amro: ((print "a")) instead of (print "a") for instance

19:16 hiredman: for is list/seq comprehension, so the result is a seq

19:17 cmajor7: gfredericks: that I see from the documentation. I was wondering the under the hood state of things.. it seems that it only keeps a single stack frame at a time..

19:17 amro: how do I flatten just the topmost seq then? and have it return (print "a") (print "b") etc

19:18 weavejester: You probably want a (do ~@(for ...))

19:18 But using a macro to do this is pretty strange

19:18 Is it just for practise?

19:19 amro: weavejester: that doesn't work, I tried it. I get Var clojure.core/unquote-splicing is unbound.

19:19 amalloy: also, drop the # in b#. it will just confuse people (mostly you)

19:19 amro: I dumbed down the macro so I can figure out what's wrong

19:19 weavejester: You probably forgot the beginning backtick

19:19 In total it should be `(do ~@(for ...))

19:19 amalloy: &(let [body '(a b)] `(do ~@(for [b body] `(print ~b))))

19:19 lazybot: ⇒ (do (clojure.core/print a) (clojure.core/print b))

19:20 amro: that's it, thanks

19:20 I wasn't sure how to combine ` with ~@

19:20 weavejester: ~ and ~@ go inside `()

19:20 clojurebot: Gabh mo leithscéal?

19:21 weavejester: It's like string interpolation in Ruby, Bash or Perl

19:21 "hello $foo" is kinda equivalent to `(hello ~foo)

19:21 amro: amalloy: b# was part of the expanded macro when I first wrote it

19:21 weavejester: Except you're using data structures instead of strings

19:22 amalloy: personally i slightly prefer (cons `do (for ...)) to `(do ~@(for ...)), but i don't have a compelling argument

19:23 i guess it forces me to keep in mind that really macros are functions for building lists, not "magic templates"

19:23 weavejester: Not just lists in Clojure ;)

19:23 gfredericks: the magic rose ~@

19:25 amalloy: weavejester: yeah, i know. having a macro expand to just an integer or a string is pure magic

19:26 weavejester: amalloy: Hiccup makes does a lot with strings :)

19:27 amalloy: i feel like there must be very few cases where (html ...) expands to a string, though

19:27 weavejester: Yeah, it only expands to a string if there are no variables in the mix

19:27 Does anyone else find that search engines are surprisingly good nowadays?

19:27 I mean, I take them for granted

19:28 amalloy: i guess that's only half-true, because (html [:div foo bar]) expands recursively to something like (str "<div>" (html foo) (html bar)], and then foo and bar might be literal strings

19:28 weavejester: But even using them everyday sometimes they manage to match queries to the right page with very little info

20:05 amalloy: technomancy: make is pretty good. i'd definitely prefer it to ant, for example

20:06 technomancy: high praise

20:07 amalloy: yeah yeah

20:07 technomancy: I guess in my mind make is tainted by autotools

20:07 guilt by assosiation

20:07 amalloy: yeah, autotools are something i cannot fathom at all. maybe it's great, but it is so bewildering

20:07 brehaut: i can only presume that once upon a time, it didnt seem like a bad idea

20:08 and then it metastasized

20:08 technomancy: the fact that people who seem otherwise intelligent put up with them makes me think that the alternative of doing that kind of stuff by hand is just too horrible to comprehend?

20:08 it is beyond my feeble imagination

20:36 TimMc: Any tips on testing namespace-manipulating functions?

20:37 I don't want to contaminate my test namespace. Currently trying to write a macro that will evaluate its contents inside a temporary namespace.

20:39 technomancy: TimMc: copy what slamhound does

20:39 each run generates a throwaway ns named after a gensym

20:41 TimMc: I think I finally have it, thanks.

20:41 But I'll look at slamhound for sure.

20:42 I ran a test in my REPL that worked differently line-by-line vs. as a single 'let form.

20:59 jcromartie: so I'm digging the REST vibe right now

20:59 and I am getting this idea that you could actually build a perfectly RESTful API without actually setting up routes for resources

21:00 i.e. by leveraging hypermedia and continuation-style callbacks of some sort

21:01 like, in your server-side API, you return a resource where the actions called by verbs are just closures tied to unique URLs

21:01 I hope that's not too ASP.NET

21:09 seancorfield: jcromartie: do you have example code somewhere? how do you map the urls to actions?

21:10 jcromartie: I'm working on it :P

21:10 let me whip up an example

21:10 brehaut: jcromartie: i dont see any reason why that couldnt be restful; nothing about rest requires you to have stable URLs

21:11 (stable in terms of the app configutarion)

21:11 jcromartie: brehaut: yes, that's the point

21:11 well there do need to be stable entry points

21:11 brehaut: sure

21:11 jcromartie: I think I basically just came up with Seaside for APIs

21:11 but not so fancy in the use of continuations

21:12 brehaut: jcromartie: yeah

21:13 jcromartie: as long as you keep the old URL callbacks around in case the client passes you an older version of the state, then it should be fine

21:14 jcromartie: but deleting the non-idempotent verbs when they are executed

21:14 that has the added benefit of not eve being able to accidentally DELETE something twice

21:17 martinklepsch: what is the reason behind "acc" as loop binding name?

21:17 brehaut: accumulator

21:19 which i guess is following on from the registers of the same name

21:19 martinklepsch: ok

21:22 I don't get how acc is being bound to the new value in the (recur) example here http://clojure.org/special_forms

21:22 could anyone explain me that?

21:23 gfredericks: martinklepsch: the loop contains two bindings, so in the call to recur the second argument gets bound to acc

21:24 martinklepsch: okay so when i have 3 bindings I'd have 3 arguments to recur etc?

21:24 brehaut: yes

21:24 gfredericks: exactly

21:25 martinklepsch: makes sense...

21:42 wiseen: is there a library for serializing things to clojure Data that's more flexible than (prn-str x) ... eg. I would like java.util.Date to be serialized and some other primitives (URI)

21:43 gfredericks: wiseen: print-dup might be what you want?

21:46 wiseen: clojurebot ,(doc print-dup)

21:47 ibdknox: hola

21:48 Raynes: ibdknox: stfugoaway

21:48 ibdknox: Raynes: h8.

21:51 TimMc: wiseen: print-dup is a multimethod you extend.

21:57 blakesmith: Can anyone recommend a good clojure memcache library?

22:05 jcromartie: why did I just write a JSON library

22:05 gfredericks: there's nothing funner

22:05 jcromartie: this sort of thing happens

22:06 TimMc: It really does.

22:06 jcromartie: https://gist.github.com/3872b7bfd382ef706bd9

22:07 I think it was because I didn't feel like opening project.clj

22:07 and adding the dependency

22:07 ibdknox: that's so much slower :p

22:08 jcromartie: nerds will go to great lengths to be lazy

22:08 brehaut: that sums up haskell

22:11 TimMc: pffft

22:12 I can't remember why I ended up dropping clj-json in favor of cheshire...

22:15 ibdknox: TimMc: everyone's doing it :p Raynes made me change it in Noir

22:15 something to do with "more features" and "just as fast"

22:21 TimMc: Oh! clj-json gave me string keys, I wanted keyword keys

22:23 No, it was *coercions* not being marked :dynamic, that was it.

22:23 Looks like that one is fixed.

22:55 Raynes: ibdknox: The bad part is that a coworker seems to be the maintainer now.

22:55 ibdknox: Raynes: of clj-json?

22:55 Raynes: Making everybody switch to cheshire is probably not a good career move.

22:55 ibdknox: lol

23:00 seancorfield: how many json libraries do we have? and what's wrong with clojure.data.json?

23:00 TimMc: seancorfield: What's wrong with it is that I didn't know it existed. :-P

23:04 seancorfield: formerly clojure.contrib.json

23:05 ibdknox: seancorfield: it's not very fast I thought

23:05 at least not compared to something using jackson

23:06 seancorfield: i guess it depends whether it's "fast enough"

23:07 ibdknox: format conversions are one of those things that should just be as fast as possible

23:07 seancorfield: but i'd prefer we all worked to improve the standard clojure.* whatever libraries than proliferate incompatible alternatives :)

23:07 brehaut: ibdknox: unless its xml-rpc

23:07 ibdknox: that might encourage someone to want to use it

23:07 ibdknox: lol

23:09 TimMc: seancorfield: Speaking of which, I'm trying to adopt import-static right now.

23:10 It currently works by making macros, so you can't do (import-static '(java.lang.Math sqrt)) (map sqrt (range 10))

23:10 ...but I don't know what my chances are of getting my version blessed.

23:11 seancorfield: :)

23:11 well, after that drive-by pot-stirring, i'm off to watch TV and drink wine... or whisky perhaps?

23:12 TimMc: heh

23:12 What is the beverage of choice of trolls? :-P

23:14 Raynes: seancorfield: I see no real point in improving clojure.* if a non-contrib library is better and significantly faster. You can't clean shit.

23:15 And that came out a lot more rude to whoever the original author of that library is than I meant it to be.

23:15 brehaut: Raynes: but you can dunk it in varnish

23:15 Raynes: My point is, if the library can't be fast, why support it in the first place?

23:15 The only reason cheshire can't be a contrib library (or clj-json for that matter) is because it relies on a fast Java library.

23:16 TimMc: The official libs also have the stigma (deserved or not) of not being able to move quickly.

23:16 Raynes: But really, I hate the distinction between 'contrib' libraries and libraries that people make.

23:16 seancorfield: the guys on mythbusters proved that you _can_ polish a turd, btw

23:16 TimMc: Raynes: The contribs are just the officially blessed libs, yeah?

23:17 Raynes: It seems to me that contrib is only useful for political purposes and for people who really like XML and terrible JIRA issue managers.

23:17 brehaut: Raynes: i dunno, i think contrib as a 'this project has proven to be great, lets promote it into a more visible tier' is valuable; eg core.logic

23:17 Raynes: That's kind of my point.

23:17 The JSON lib *isn't* great. It's slower than ever other library.

23:18 But we should work on it because… it's officially sanctioned and written in pure Clojure?

23:18 inb4 itisn'tpureclojurebecauseitcallsouttojava

23:19 jeremyheiler: If a project is blessed, doesn't that immediately raise the barrier of entry to support it, as opposed to just being a popular project that doesn't have the same contributor rules as clojure porper?

23:19 seancorf: there are discussions around using external dependences in some contrib libs... it might happen...

23:19 jeremyheiler: proper*

23:19 seancorf: and the new process is meant to be a lot more streamlined and faster to evolve code

23:20 Raynes: No, because being officially blessed means you have to go through hell to actually contribute.

23:20 Not that they don't have excellent reasons for the hellish procedure.

23:20 seancorf: but the important distinction is a legal one: contrib libraries are protected under the same license / IP as clojure itself - which is of concerns to a lot of companies

23:20 Raynes: Some of them, anyways.

23:20 Yeah yeah yeah, I know.

23:21 Not a lawyer.

23:21 Thankfully.

23:21 seancorf: and to be honest Raynes the process really isn't hellish :)

23:21 Raynes: If we're talking about barrier to entry, I'd be happy to hear of a single point in the favor of non-hellish.

23:21 seancorf: i ended up maintaining java.jdbc without much fuss, because i needed contrib.sql running on 1.3

23:23 there are a LOT of people with signed CA's on file which means a large pool of people who can submit patches

23:24 Raynes: But we were talking about barrier to entry, right?

23:24 seancorf: all the open source projects i know have a similar barrier to entry

23:24 you have to sign a CA and follow the patch process

23:24 cmajor7: "recur special form can also be used as the last call in a function to return to the beginning of that function with new arguments" => would this be a common use? or the one to avoid? ##(defn recursive ([number] (recursive number 1)) ([number factorial] (if (zero? number) factorial (recur (- number 1) (* factorial number)))))

23:24 lazybot: java.lang.SecurityException: You tripped the alarm! def is bad!

23:24 Raynes: I sure don't know of a lot of them.

23:25 But I wasn't arguing against the CA.

23:25 Like I said, I'm not a lawyer.

23:25 jeremyheiler: seancorf: Is a maintianer of a contrib allowed to process patches at their own pace? So, for example if a popular library with an active community is blessed, that shouldn't hurt the project in anway, right?

23:25 If*

23:25 sorry, Is*

23:25 Raynes: seancorf: As a lib maintainer, are you allowed to accept patches and issues on Github?

23:25 jeremyheiler: (sans a CA agreement form all)

23:26 seancorf: no pull requests allowed

23:26 Raynes: I consider JIRA a massive barrier to entry, dismissing all the CA stuff.

23:26 jeremyheiler: ^agreed.

23:26 TimMc: seancorf: Ouch.

23:26 Raynes: I consider JIRA a massive barrier to *anything*.

23:26 seancorf: patches via JIRA are the acceptable way

23:26 it's because of legal traceability of copyright

23:26 TimMc: I'm not going to even bother trying to get this contrib I'm maintaining blessed.

23:26 Raynes: Well, at least they've got their asses covered. *shrug*

23:27 Really, really well.

23:27 seancorf: like i say, just like all the other open source projects that corporations feel comfortable using

23:28 jeremyheiler: For core, I think the CA and legal stuff works really well. That's important. But I think it really makes it undesirable to have a library blessed into contrib if it wasn't specificlly written to be there in the first place.

23:28 seancorf: when i worked at macromedia / adobe i had the "pleasure" of going thru a license audit on a large project

23:28 TimMc: seancorf: Ah, you're saying that this is effectively due to pressure from corp.s that want to use these projects?

23:28 Raynes: I'm fine with companies not using my projects if I get to maintain them in a sane was a resut.

23:28 result*

23:28 seancorf: yeah, without that stuff, many corporations cannot use an open source project

23:28 i want clojure to be usable by such companies so i'm happy to comply with the process

23:29 Raynes: The way I feel at this point is that I just hope nobody puts any libraries I like into contrib so that, if I ever have to contribute to them, I don't have to go through all the nutty crap involved. That's just me though.

23:29 TimMc: seancorf: I don't see why you can't get the same traceability via Github permissions.

23:29 nuclearsandwich: Raynes: agreed

23:29 Raynes: TimMc: Apparently if you delete your account, your name disappears.

23:30 TimMc: >_<

23:30 seancorf: TimMc: because you have to go back thru the entire repo history and ensure that all committers have signed CAs on file

23:30 TimMc: But the commits are still there!

23:30 seancorf: Not hard. There is rarely a ton of committers.

23:30 Raynes: It's probably only a matter of time before they have the code in git repos hosted on their server, just in case. :p

23:31 TimMc: seancorf: Although I guess someone could lie and submit under someone else's name?

23:31 Raynes: You could probably send in a fake CA and submit a patch under that. Not sure what would happen. Damn not-being-a-lawyerness.

23:32 Tcepsa: cmajor7: I believe that is a common use

23:32 seancorf: the CA is a legally binding document - so it protects the project

23:32 jeremyheiler: I don't see why accepting a pull request can't involve a core committer checking the user for a CA first. I Imagine that is done in JIRA anyway?

23:32 Raynes: You can only get a Jira account if you've been sanctioned by a team member.

23:32 seancorf: jeremyheiler: because then the burden is on core which isn't fair to the project

23:32 Raynes: It's admittedly different.

23:32 jeremyheiler: Ah, ok.

23:32 Raynes: But...

23:33 * Raynes sighs and climbs out of his hole.

23:33 seancorf: having been thru the other side of this at a corporation, i can only say that this is necessary for corporation adoption of clojure and its set of sanctioned contrib libraries

23:33 arohner: seancorf: "this" being CAs. JIRA + patches seems to be more of an implementation detail, IMO

23:34 I can imagine Github having a permissions model that would make this painless

23:34 Raynes: Let the record stand that it is not the CA that I have a problem with.

23:34 seancorf: yeah, we know you don't like JIRA :)

23:34 Raynes: It is the fact that we're only allowed to use a small subset of what Github offers.

23:34 You might as well host these repositories with gitweb.

23:35 TimMc: Oh, fun with macros: actual: (not (number? (. java.lang.Math (sqrt 3.141592653589793))))

23:35 cmajor7: Tcepsa: thank you. you mean it is used commonly even though it can be accomplished with "loop/recur"?

23:36 seancorf: *you* can use the full range of github - you can fork clojure, work on it any way you want...

23:36 emezeske: jsabeaudry: I just released lein-cljsbuild 0.0.10, which pulls in the host project's :dependencies and :dev-dependencies. Let me know if it works for you!

23:36 Raynes: seancorf: I'm making sure I'm clear on this. You know I don't like Jira, right?

23:36 seancorf: but if you want a patch accepted, you have to put it in a JIRA ticket as a patch :)

23:36 Raynes: You can pull from a gitweb repository and work on it anyway you want.

23:36 And it is the exact same thing.

23:36 TimMc: It's not JIRA that bothers me, it's patch-formatted contributions.

23:37 seancorf: i agree github's "free-for-all" workflow is more convenient

23:37 Raynes: seancorf: All a Github fork is is a copy of a repo under your name. It isn't anything special that you need Github for. If that was the full range of Github, I'd probably just use bitbucket and hg.

23:37 seancorf: but i also understand that corporate concerns mean a tighter control on IP and contributions

23:37 Raynes: ;)

23:38 Yeah, we know you're worried about corporate concerns. :)

23:38 seancorf: i maintain clj-time and work on congomongo too and it's nice to be able to accept random pull requests but that also means those libraries can't be used by corporations that have license audits :)

23:39 jeremyheiler: All I'm saying is that "the process" might just make it less desirable to want a useful lib be blessed into contrib. Wether tha tis important or not, i don't know.

23:39 (from a maintainer's and community perspective)

23:40 Raynes: That's where I'm at right now.

23:40 seancorf: jeremyheiler: understood - and several folks have raised that issue on clojure and clojure-dev MLs over the last year or so (i'm sure it came up before then too but i wasn't around then :)

23:40 Raynes: But like I said, that's just how I feel. I understand the justifications and I know that my bitching wont change anything. Doesn't mean I have to like it.

23:40 seancorf: it's ok, we don't mind being a "shoulder to cry on" about it :)

23:41 Raynes: You mean you. :p

23:41 seancorf: and, yeah, for the record, i wish we could accept pull requests but it is what it is

23:42 Tcepsa: cmajor7: Yes; I believe that's the intent of providing a mechanism to return to the beginning of the current function; it prevents you from having to put in a redundant loop statement if you're essentially doing a tail-call.

23:42 Raynes: The important thing is that we're all free to do whatever we want because Clojure *is* open source. If we don't want to put our libraries in contrib then we certainly don't have to. Don't have to use the ones that are there either, but the contrib process wouldn't stop me from using a good contrib library. clojure.data.json doesn't seem to be one of them though.

23:42 jeremyheiler: I should probably cancel mine then. (I submitted a patch as well, though)

23:42 TimMc: jeremyheiler: Cancel which?

23:42 jeremyheiler: the pull request.

23:42 TimMc: heh

23:43 jeremyheiler: yeah

23:43 Tcepsa: cmajor7: Put another way, that's how you can approximate tail-call optimization even though the JVM doesn't support it directly.

23:43 jeremyheiler: Raynes: compeletely agree. And it's simple to fork a contrib lib and modify it for your own needs until a patch is approved.

23:44 Tcepsa: cmajor7: Instead of calling your function again and pass it the new arguments, you call recur and pass IT the new arguments.

23:44 kilborn: Hi, new to clojure, I'm trying to figure out an idiomatic way to do the equivalent of mutating a closure bound variable? I have a function which recurs, and I need it's behavior to be controllable from outside it's scope. Global variables are not the right way... Suggestions?

23:44 Raynes: That's generally what I've been doing.

23:44 Except the sending a patch part. I have to really care to do that.

23:45 But that's pretty selfish and a habit I intend to break.

23:45 jeremyheiler: haha

23:46 cmajor7: Tcepsa: I see.. so the "loop/recur" actually equals "defn/recur"?

23:46 Tcepsa: kilborn: This is a shot in the dark, but have you looked at using an "agent"?

23:48 kilborn: Tcepsa: I thuought about it (message-passing seems to suggest itself), but I hoped there's a simpler way then going all erlang and stuff...

23:49 I'm pretty close to constructing the function by passing an atom map into it, then pinning the atom symbol on the function's metadata, but that feels too complicated as well.

23:50 dnolen: kilborn: what you're trying to do doesn't sound all that idiomatic. but you can do it.

23:50 Tcepsa: cmajor7: I am not certain what's actually happening under the hood (I wouldn't be at all surprised if there was some subtle-but-important difference between the two) but that understanding will probably serve you pretty well. I think of them as being two separate things, but as far as how you go about using them, they are very similar. (In other words, it looks like it but I'm not familiar enough with the details to say "Yes

23:50 absolutely" ~wry grin~)

23:50 dnolen: kilborn: (let [x (atom nil)] (defn foo [] ...))

23:51 flazz: i'm doing bit operations on an integer, is there a way to not have it convert to a long?

23:52 kilborn: dnolen: hey, you're the core.logic guy! *tips hat*. But then I keep everything in outer namespace, and it *feels* like it should be encapsulated inside the function...

23:52 dnolen: kilborn: it's not visible, you've create a lexical scope

23:53 created

23:53 Tcepsa: kilborn: Also, at the hazard of looking like a complete idiot, I ask "Could you use a namespaced variable?"

23:53 Nevermind, you just answered

23:53 kilborn: dnolen: well, if I do it exactly like you suggest yeah, but then how to I modify the atom from say the REPL? i need a symbol in my hand

23:53 s/todo/

23:54 arohner: cmajor7, Tcepsa : recur goes "up" to the nearest recursion point, which is either a loop, or the defn

23:54 cmajor7: Tcepsa: thanks. in clojure core source I see "loop/recur", hence I suspect it outperform "defn/recur"… the thinking is "loop" just creates a "point/address" of recursion, while "defn" might be a bit more expensive. especially a arrity matching. e.g. (defn fn ([n] (fn n 1)) ([n accum] (…)))

23:54 Tcepsa: kilborn: If you have a "starter function" (no idea what it'd really be called) that creates an atom and passes it to your recurring function and also returns the atom, then you could catch the return value and modify it in your REPL.

23:56 dnolen: kilborn: it sounds like you're doing something strange :) probably need more context

23:56 kilborn: Tcepsa: True, and that's where I was leaning, but then if my function has 2 lines in it, It feels like i'm balancing dolphins on my nose while simultaneously practicing my limbo skills

23:56 Tcepsa: kilborn: (assuming that it starts the recursive function in a separate thread, but the way you've been talking about it strongly implies that it is in a separate thread from e.g. the REPL)

23:56 kilborn: Dnolen: gladly. you've heard of overtone?

23:56 dnolen: kilborn: yep

23:57 kilborn: dnolen: great. really basic use case. I have a function which takes in a list of chords, chooses one randomly, and then reschedueles itself to play the next one in say 1000 ms

23:58 dnolen: it's all working nicely, but now I want to change the chord choices (say I move to the chorus in a piece, whatever). with closures and set! , or objects and setters, this would be very natural, but with immutable data I can't find the idiom

23:59 dnolen: kilborn: not sure why an atom at the top level your ns doesn't perfectly solve the problem.

23:59 Tcepsa: cmajor7: I'm not sure, but based on what arohner said I'm guessing that when it enters a function it also places a point/address of recursion. Arity isn't a problem--just think of functions defined with different arities as different functions. Whichever one the recur is in is the one that will be recurred to. (i.e. you can't recur from inside a function that takes two arguments to the inside of a function of the same name that

23:59 takes one argument; you'd have to use trampoline for that)

Logging service provided by n01se.net