#clojure log - Apr 02 2011

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

0:08 sritchie: hey guys, why does ##(. "face" (substring 1)) work?

0:08 sexpbot: ⟹ "ace"

0:08 sritchie: I'm not sure what's going on here

0:13 amalloy: sritchie: because that's the . syntax?

0:13 &(macroexpand '(.substring "face" 1))

0:13 sexpbot: ⟹ (. "face" substring 1)

0:14 amalloy: wrapping the method call in parens is optional when there are more args; for no-arg methods it's needed to distinguish between a method and a field

0:14 sritchie: okay, that's what was confusing me

0:16 thanks, I see this now on a closer reading about the dot special form -- (. instance-expr (method-symbol args*)) or (. instance-expr method-symbol args*)

0:17 amalloy: it tends to be easier to write macros that expand directly into (. obj method args) rather than the intermediate (.method obj args), if you don't know what method you'll be using ahead of time

0:17 technomancy: TimMc: bleh; I tested it with a project that was already requiring robert.hooke

0:18 TimMc: technomancy: Off to bed, will see any highlights.

0:22 amalloy: TimMc: sounds worryingly as if you are offering a highlights reel of your bed

0:29 technomancy: TimMc: just pushed th efix

0:32 mec: for some reason (map #(.fillRect g (first %) (second %) 100 100) points) inside a paint isnt working, but if I get rid of the map and just do (first points) it works fine

0:33 tomoj: I blindly recommend doseq

0:33 mec: bah of course

0:34 curse you laziness

0:34 tomoj: mapping side-effects seems more evil to me, I think, than to many others

0:47 amalloy: mec: (map #(...)) should almost always be either a for or a doseq

0:47 eg here (doseq [[a b] points] (.fillRect g a b 100 100))

0:50 it must still be april first. adblock is asking if i'd like to try out their new augmented-reality billboard blocker

0:52 mec: amalloy: yes, it looks much nicer that way

0:55 amalloy: mec: destructuring is king. if i type "first" or "second" i usually stop and check myself for a fever. sometimes it's right, but...

0:57 mec: deffinitly beats (map (fn [..] too, it just never really occurred to me to use for in that place :x

0:58 amalloy: haha. i just started typing (map #(...)) in my code. hard habit to break

0:59 mec: still have to use it instead of for if you're threading a collection, which I do all the time

0:59 amalloy: yes, i think it's tomoj who does some abominable things with threading for

1:00 mec: (->> coll #(for [x %] ...)) ;p

1:00 amalloy: &(->> (inc x) (for [x (range 10)]))

1:00 sexpbot: java.lang.IllegalArgumentException: Wrong number of args (3) passed to: core$for

1:00 mec: weird

1:00 amalloy: ,(->> (inc x) (for [x (range 10)]))

1:00 clojurebot: (1 2 3 4 5 6 7 8 9 10)

1:01 amalloy: *sigh* someone please fix his macroexpansion facilities

1:01 (that is my job)

1:01 mec: how does that even happen

1:01 amalloy: he has to macroexpand some stuff himself to confirm you're not doing sneaky things

1:02 mec: ah

1:02 amalloy: at some point i broke some part of it but it is hell to debug

1:02 mec: I thought its running in a sandbox?

1:02 amalloy: mec: yes, but so what

1:02 &(def + -)

1:02 sexpbot: java.lang.SecurityException: You tripped the alarm! def is bad!

1:02 amalloy: the jvm sandbox wouldn't catch that but it would make sexpbot unusable

1:03 mec: I thought there was also a clojure side sandbox, like for findfn

1:04 amalloy: yes, that's what's broken

1:05 mec: ah

1:06 tomoj: amalloy: s/does/did/ I suggest :)

1:07 amalloy: tomoj: sorry, it's on your permanent record now

1:08 tomoj: shucks

1:08 amalloy: $learn tomoj is a horrible threading abuser

1:08 sexpbot: My memory is more powerful than M-x butterfly. I won't forget it.

1:09 tomoj: actually I wrote (->> bar foo-in-bar count / (for [bar bars]) (reduce +)) today, though as a douchey explanation, not actual code

1:09 amalloy: man, his learning syntax sucks. he put two is's on that

1:09 $forget tomoj

1:09 sexpbot: If tomoj was there before, it isn't anymore. R.I.P.

1:09 amalloy: you're off the hook

1:09 tomoj: :D

1:10 do I abuse horrible threading or abuse threading horribly? or both?

1:10 amalloy: you perform horrible thread abuse

1:10 mec: lol this is what I just found in my code: (->> (range..) (map #(->>)))

1:11 tomoj: I don't think I abuse horrible threads, so, I'll take that as an answer

1:11 wat

1:11 amalloy: ew what

1:11 tomoj: #(->>) isn't even anything?

1:11 .. is it?

1:11 amalloy: i think he missed a ...

1:12 oh

1:12 mec: (defn note [hz sample-rate ms] (let [period (/ hz sample-rate)] (->> (range (* sample-rate ms 1/1000)) (map #(->> (* 2 Math/PI % period) Math/sin (* 127 ,) byte) ,))))

1:12 well that didnt work right

1:12 tomoj: note? overtone?

1:12 amalloy: $learn gist http://gist.github.com

1:12 sexpbot: My memory is more powerful than M-x butterfly. I won't forget it.

1:14 tomoj: only now do I realize "note" and "tone" are anagrams

1:14 amalloy: tomoj: clearly you don't play enough word games

1:14 check out stop. has like a hundred anagrams

1:14 tomoj: if 0 is not enough, yeah

1:15 mec: i start making silly sound combinations when i try to figure out anagrams, it never goes well

1:15 amalloy: my favorite is AELPST (alphabetical so as to not give anything away). it has six anagrams!

1:16 tomoj: thank you wordsmith.org for saving me from thinking

1:16 * amalloy curses the internet

1:16 mec: lepast tepsal spelta

1:16 tomoj: ditto

1:17 amalloy: mec: don't tell me any of those are words

1:17 mec: nope, i havnt come up with a single real word yet :x

1:17 amalloy: haha k. i thought wordsmith had given them to you

1:17 mec: i suck something fierce at anagrams

1:17 tomoj: wordsmith came up with exactly six, which was bizarrely satisfyig

1:18 amalloy: tomoj: oh good. i've never actually asked a computer

1:18 just came up with six and was pretty sure there weren't any more

1:19 tomoj: are you telling me you knew CNYRFG ?

1:19 mec: i wonder how many words there are whose every permutation is a word

1:19 tomoj: (rot13'd)

1:20 amalloy: mec: pot

1:20 tomoj: oh, now that I parse that correctly it seems pretty common

1:20 amalloy: has everything but otp i think

1:20 tomoj: "tpo"?

1:20 amalloy: okay and that

1:20 so uh

1:20 not very many

1:20 tomoj: "a" and "I"...

1:20 :(

1:20 mec: no and on ;p

1:20 amalloy: am

1:21 $dict epe

1:21 sexpbot: amalloy: Word not found.

1:21 tomoj: scrabble dictionary has many unfamiliar short words

1:21 amalloy: tomoj: qat and qi. very important

1:21 tomoj: so might be more if you take that as your standard of wordness

1:22 amalloy: well, a three-letter word almost has to have two vowels to fit the bill

1:23 i can't even find a three-letter word that has five anagrams, let alone all six

1:29 so i just wrote an "alternates" function: (alternates 3 (range 9)) is ((0 3 6) (1 4 7) (2 5 8)). probably it's a mistake to call (alternates 3 (range 10)); should i (a) throw an exception, (b) silently drop the 9, or (c) include the 9, making the first seq longer than the others?

1:30 mec: $43200000l

1:32 you could do like core and make alternates and alternates-all to do (b) and (c) respectively

1:34 amalloy: &(interleave [0 3 6 9] [1 4 7] [2 5 8])

1:34 sexpbot: ⟹ (0 1 2 3 4 5 6 7 8)

1:35 amalloy: cool. i'm happy with being the exact opposite of interleave, and leaving the 9 on is the easiest way to handle the error anyway

1:38 mec: whats your code for alternates?

1:39 amalloy: mec: https://gist.github.com/899263

1:41 i'm currently using it for my lazy-loop, which needs to turn (lazy-loop [coll c] ... (lazy-recur (rest coll)) into ((fn lazy-recur [coll] ... (lazy-recur (rest coll))) c)

1:48 anthony_: I'm working on my first macro. I found that I was often doing this: (let [a (delay ...) b (delay ...) c (delay ...)] ... ), so I want to create a macro that automatically makes the bindings into delays. I have that part working, but I still have to manually deref the variables within the body. Is there a way to do that within a macro (so I can just refer to it as a/b/c instead of @a/@b/@c)?

1:49 amalloy: anthony_: short answer: you can probably convince clojure.contrib.macro-utils/symbol-macrolet to do this for you

1:50 long answer: i don't think you want to. isn't the whole point of working with delays that you can pass them around without having to evaluate them until later?

1:50 if you always deref them the moment you touch them, what have you gained?

1:59 anthony_: amalloy: Sorry, was AFK. I probably don't want to do that -- I was in the process of rethinking it when I figured I could use this as an excuse to learn macros. But, I didn't always immediately evaluate them. I would often only need the first few, depending on some conditions -- using delays were easier than a bunch of nested forms, or creating a lot of one-time functions.

1:59 Wow, there's a lot of pronouns in that. It probably doesn't make much sense. :-)

2:00 amalloy: interesting usage

2:01 anthony_: Yeah, it's a little strange. But a and b might be validations (or something), and c is an expensive operation (something with a database), so I only want to evaluate c if a and b are true. Of course, that's not a very good example, but maybe it makes some sense.

2:01 amalloy: sure, i understand the idea

2:02 anthony_: I think there are much better ways to do that, though. Now that I know some more about macros, I'm going to give those macro-utils a closer look. Thanks for your help.

2:02 amalloy: anthony_: yeah, it seems easiest to just do some when-lets or something

5:04 ace0x2a: jey

5:05 hey* whats a good guide for getting started with clojure

5:05 I havent experience in functional programming, i just done a little bit ruby

6:53 G0SUB: I need to transform something like [:a :x :b :c :d :x :x :x :e :x] to {:e [:x], :d [:x :x :x], :c [], :b [], :a [:x]}. Any good ideas?

6:56 angerman: G0SUB: so you have [:s :x*]+

6:56 G0SUB: angerman: yeah

6:56 angerman: where :s is a symbol unlike :x

6:56 G0SUB: angerman: right.

6:57 angerman: not any "good" idea. I guess it's just looking and associng.

6:57 G0SUB: angerman: sure. this is a use-case for `reduce`

7:02 ,(reduce

7:02 clojurebot: EOF while reading

7:02 G0SUB: (fn [[sym m] obj]

7:02 (if (= obj :x)

7:02 [sym (merge-with conj m {sym obj})]

7:02 [obj (assoc m obj [])]))

7:02 [nil {}]

7:02 [:a :x :x :x :b :x :x :c :d :x])

7:02 argh

7:03 angerman: here's another idea: 1. scan the vector for non :x symbols; split. 2. each of the sublist now is (:s :x : x :x …)

7:03 a little like dna is replicated.

7:04 raek: maybe group-by or partition-by could be used

7:05 ,(partition-by #{:x} [:a :x :b :c :d :x :x :x :e :x])

7:05 clojurebot: ((:a) (:x) (:b :c :d) (:x :x :x) (:e) (:x))

7:06 raek: ,(partition-by (fn [v] (when (not= v :x) v)) [:a :x :b :c :d :x :x :x :e :x])

7:07 clojurebot: ((:a) (:x) (:b) (:c) (:d) (:x :x :x) (:e) (:x))

7:07 raek: ,(partition-by identity [:a :x :b :c :d :x :x :x :e :x])

7:07 clojurebot: ((:a) (:x) (:b) (:c) (:d) (:x :x :x) (:e) (:x))

7:07 G0SUB: ,(partition-by identity [:a :x :b :c :d :x :x :x :e :x])

7:07 clojurebot: ((:a) (:x) (:b) (:c) (:d) (:x :x :x) (:e) (:x))

7:26 hsuh: is there a shorter way to write (doseq [x coll] (side-effect-only-fun x))?

7:29 ampleyfly: maybe (map side-effect-only-fun x)

7:31 mduerksen: hsuh, ampleyfly: you can use map, but you'll have to force evaluation then: (doall (map f coll))

7:31 hsuh: doseq is cleaner then .. tks!

7:33 mduerksen: hsuh: i use that idiom rather often, so i made my own function for it: (def domap (comp doll map)).

7:34 correction: (def domap (comp doall map))

7:37 hsuh: nice.. and how do you reuse that function across projects?

7:42 mduerksen: i have my own small utility project, its in there. but i had second thoughts about that recently, because i'm not sure if domap is really better than doseq. 1. doseq is a core function, and 2. i like the order of arguments. with domap, you say "i want to do <this> with all of <these>". with doseq, the order is switched. you say "with <these>, i want to do <this>", which is often more natural IMHO

7:43 and typically i first determine the values that i want to process, and then i want to specify what to do with them. that's something i like about doseq

7:45 the reason i use domap often in my projects is simply that i discovered doall before i stumbled upon doseq :)

7:53 hsuh: mduerksen: i asked because i'm not sure how i can reuse an "util.clj" between projects ..

8:37 TimMc: Is there a shorthand in leiningen to say you want version 1.x.x of something? [1.0.0,2.0.0) is kind of verbose and hard to interpret.

9:05 technomancy: Yeah, that works -- only the file with the failing test was run on retest.

9:23 Cool! This works well, thanks.

9:24 I notice it only reruns at the file level -- any plans on going down to the deftest level?

10:45 malkomalko: because I don't want to re-invent the wheel.. does anybody know of any functions in clojure-contrib for aggregating of positional based tuples? Like if I wanted to sum up every nth element in a vector?

10:47 jkkramer: ,(reduce + (take-nth 2 [1 2 3 4 5]))

10:47 clojurebot: 9

10:49 __name__: oh, that is nice.

10:49 TimMc: jkkramer: Why not apply?

10:49 jkkramer: no reason

10:49 TimMc: k

10:51 mrBliss: TimMc: (apply + ..) will put the arguments in a list and then reduce with +, so calling (reduce + ..) directly is faster.

10:52 malkomalko: what if the input was [[x y 1] [x y 2] [x y 3]]

10:52 and I wanted to get 6

10:52 so sum up the 3rd position in each of those tuples?

10:53 mrBliss: ,(reduce + (map #(nth % 2) '[[x y 1] [x y 2] [x y 3]]))

10:53 clojurebot: 6

10:53 malkomalko: cool

10:58 hsuh: so, suppose i my webapp has logging by inserting the log synchronously on a db, i then noticed this slows my response time a lot. so i was thinking of using an agent to send the log to, and have another thread (using add-watch?) picking up those logs and adding to my db independent from the ring requests code and solving the response delay problem...is this thinking straight?

10:58 TimMc: mrBliss: Ah, and I suppose + can't do any optimizations on a list of inputs anyway.

10:58 malkomalko: why the need for the quote there on that tuple mrBliss ? it seems to work fine without the quote no?

10:59 mrBliss: malkomalko: the xs and ys will be unbound

10:59 ,[[x y 1] [x y 2] [x y 3]]

10:59 clojurebot: java.lang.Exception: Unable to resolve symbol: x in this context

10:59 malkomalko: ah yes, got it

11:00 duh

11:00 thanks

11:00 mrBliss: $source +

11:00 sexpbot: + is http://is.gd/zh9ARG

11:00 mrBliss: TimMc: ^^

11:01 TimMc: also note the ":inline-arities #{2}"

11:01 TimMc: mrBliss: Ah, makes sense.

11:01 mrBliss: TimMc: That's also why (+ (+ a b) (+ c d)) is faster than (+ a b c d) :-)

11:02 TimMc: silly

11:03 malkomalko: mrBliss: what do you think the best clojure doc site is right now? having trouble learning the api

11:04 Raynes: clojuredocs.org has examples with a lot of it's documentation.

11:04 mrBliss: I would also suggest clojuredocs.org

11:04 malkomalko: sweet

11:05 mrBliss: http://learn-clojure.com/ is also nice for beginners

11:06 malkomalko: just bought the joy of clojure, really digging that

11:07 mrBliss: malkomalko: have you got the paper edition?

11:07 malkomalko: no, final ebook version

11:18 pdk: (meta +)

11:18 ,(meta +)

11:18 clojurebot: {:ns #<Namespace clojure.core>, :name +, :file "clojure/core.clj", :line 809, :arglists ([] [x] [x y] [x y & more]), :added "1.0", :inline-arities #{2}, :inline #<core$_PLUS___inliner clojure.core$_PLUS___inliner@1a05c93>, :doc "Returns the sum of nums. (+) returns 0."}

11:18 pdk: ,(meta -)

11:19 clojurebot: {:ns #<Namespace clojure.core>, :name -, :file "clojure/core.clj", :line 842, :arglists ([x] [x y] [x y & more]), :added "1.0", :inline-arities #{1 2}, :inline #<core$___inliner clojure.core$___inliner@727249>, :doc "If no ys are supplied, returns the negation of x, else subtracts\n the ys from x and returns the result."}

11:24 hsuh: how can i insert logs into a database without affecting my http response delay too much? (async i mean)

11:28 mrBliss: hsuh: use a future or an agent

11:29 TimMc: hsuh: Shouldn't you be logging to disk?

11:30 hsuh: timme: perhaps, but i'd like to know how to solve these problems anyway...

11:30 TimMc: I've never done logging before, but I usually hear about logs being written to disk or a queue.

11:31 hsuh: ok its the same, suppose disk writing is slow, so i the main request/response code i rather just add the log to a queue, which another thread consumes and really writes to the slow io... avoiding the delay in the request/response

11:31 if i'm thinking correctly

11:36 TimMc: I think that's the approach the big sites take, yeah.

11:37 hsuh: if I use a future to encapsule the "db insert", but nobody actually dereferences this future object, does the code ever get executed?

11:39 theBlackDragon: /S 1

11:53 malkomalko: another quick question.. min takes this form (min 1 2 3) how can I turn (1 2 3) into something that min can handle?

11:56 mids: (apply min '(1 2 3))

11:59 malkomalko: ok

11:59 http://clojuredocs.org/clojure_core/clojure.core/apply awesome

12:37 jaley: hey guys! does anyone know if there's much of an active clojure-android community around? googling around mostly finds me 1-year+ articles to the tune, "it'll work but it's slow and big".

12:47 TimMc: jaley: There has been almost no discussion of Android in this channel, other than to say that Android's GC is slow as hell.

12:50 kephale00: I haven't had any luck in the Java HotSpot spec, but does anyone know if there is a way of capping the number of threads clojure/java uses within a process (if it makes a difference the code is being launched with java -jar myuberjar.jar)

12:50 jaley: TimMc: hmm ok thanks. I noticed a comment from rich encouraging support for android a while back, and the core team certainly seem to fix android-related bugs (looking at JIRA). So I just kind of wondered how people are using clojure on android is all :p

12:53 TimMc: I don't think Clojure is usable enough yet (performance-wise) on Android for there to be a community to speak of. :-/

12:53 jaley: TimMc: this is what I was referring to (just found it in my history...) http://dev.clojure.org/display/design/Android+Support

13:04 KirinDave: Finally got some email asking about Clothesline.

13:04 Maybe a few people are using it.

13:21 kephale00: Wow, yeah, the best I've found is -Xsinglecpu which doesn't seem to be a commonly supported JVM arg, and it isn't available on the machines i'm working on in particular

13:59 TimMc: https://gist.github.com/899696 <-- java.lang.ClassCastException: foo.core.Person cannot be cast to foo.core.Person

14:01 I can't seem to reduce this any further.

14:04 ataggart: integer math question: is it true for all math ops that ((int) (longA op longB)) == ((int)longA) op ((int)longB)

14:05 TimMc: ataggart: Doubt it.

14:06 ,(int (- (long 0x80000000) (long 0x80000000)))

14:06 clojurebot: java.lang.ExceptionInInitializerError

14:06 ataggart: TimMc: me too but I was hoping someone had a rigorous answer. Google is failing me.

14:06 note that (int) is java's truncating int cast

14:06 so the analogue would be unchecked-int

14:06 TimMc: Oh, you are asking about Java code?

14:07 ataggart: I'm asking about truncating a 64-bit integer to a 32-bit integer

14:07 this came about due to me wondering why 1.3 has a bunch of unchecked-FOO-int functions

14:08 TimMc: &(int (- (long 0x80000000) (long 0x80000000)))

14:08 sexpbot: java.lang.Exception: EvalReader not allowed when *read-eval* is false.

14:08 TimMc: What are the bots complaining about?

14:09 ataggart: dunno, but 1.2 doesn't have unchecked-int, so you can't test it out the truncation op here

14:09 TimMc: ANyway, do you see what I'm getting at?

14:09 longA and longB can both be out of int range, but the difference could be inside int range.

14:10 ataggart: the question is whether the result will be different once truncation happens. I haven't seen an example where the result is different.

14:12 TimMc: ataggart: If you have a 1.3 repl, could you see what happens with (/ 0x1000000000 0x10000000000) ?

14:12 ataggart: ya one sec

14:13 returns 1/16. using quot returns 0.

14:15 malkomalko: is it possible to have a system wide default project.clj for leiningen so that when you create a new project you always get swank/contrib? I hate adding those lines everytime

14:16 TimMc: ataggart: And you get 1/16 with both longs and ints?

14:16 pdk: you could say

14:16 that'd be pretty swanky

14:17 ataggart: TimMc: ah, no. divide by zero exception. Though that would seem to argue against the -int math ops.

14:23 TimMc: found one. If the math op has args outside of int range, but its result falls within int range, it behaves differently. E.g. (unchecked-int (- 2147483648 2)) => 2147483646 but (- (unchecked-int 2147483648) 2) => -2147483650

14:24 though I just realized that unchecked-OP-int still does a checked cast to int, so I'm really baffled by their inclusion in 1.3.

14:32 fliebel: What is the difference between assure and locking? I want to pour some Swing events into an atom or ref, but maintain a persistent view of it during a certain action. I do no write to it. Should I use an agent, wrap the actions in a dosync, and assure the agent, or go for a simple atom, and lock it during the actions?

14:34 TimMc: What is assure? Do you men ensure?

14:35 fliebel: oh, yes

14:35 TimMc: And you just want to make sure that you have a consistent view of a set of refs during a transaction, not that their values are consistent in some manner afterwards?

14:36 fliebel: no, just make sure some state stays the same during a set of actions.

14:36 TimMc: The reads you do inside a transaction represent a stable snapshot of the world, modulo any writes you do inside the transaction.

14:38 fliebel: TimMc: Okay, so I don't even need to ensure it? Then what is ensure used for?

14:45 TimMc: fliebel: It's for preventing write skew.

14:46 fliebel: Okay, and what about the locking? Is that considered hacking, or bad practice? I don't want to lock up the Swing thread, but refs feel heavy, esp since I don't need so much managed stuff.

14:47 TimMc: Sometimes you have several refs that need to be in a consistent state whenever they're read together (in some transaction.) Any other transaction that wants to write to some *but not all* of them must call ensure on the others to make sure nothing else writes to them in the meantime.

14:50 fliebel: TimMc: Sot it's for refs you're not going to use in any other way?

14:51 TimMc: It's for the refs that need to be held constant during your transaction.

14:53 fliebel: &(let [at (atom 1) get-twice (fn [a] [@a (Thread/sleep 1000) @a]) fut (future (locking at (get-twice at)))] (Thread/sleep 500) (swap! at inc) @fut)

14:53 sexpbot: ⟹ [1 nil 2]

14:53 fliebel: It completely ignores the lock, or I;m doing something wrong.

14:53 TimMc: fliebel: http://clojure.higher-order.net/?p=50 <-- an example of ensure

14:54 I'm not familiar with locking.

14:55 Ah, I see -- it's basically `synchronized`.

14:55 fliebel: meaning?

14:56 TimMc: Java has a "synchronized" keyword.

14:57 fliebel: &(let [at (ref 1) get-twice (fn [a] [@a (Thread/sleep 1000) @a]) fut (future (dosync (get-twice at)))] (Thread/sleep 500) (dosync (alter at inc)) @fut)

14:57 sexpbot: ⟹ [2 nil 2]

14:57 fliebel: TimMc: My Java is to dusty to remember what that means.

15:00 TimMc: &(let [at (atom 1) get-twice (fn [a] [@a (Thread/sleep 1000) @a]) fut (future (locking at (get-twice at)))] (Thread/sleep 500) (locking at (swap! at inc)) @fut)

15:00 sexpbot: ⟹ [1 nil 1]

15:00 TimMc: (Your first example, but with locking around the swap.)

15:00 fliebel: Do you know what it means to hold the monitor of an object?

15:00 fliebel: TimMc: Huh? Can you explain why that is needed?

15:00 oh, uhm, let me think..

15:01 no, not exactly at least.

15:01 TimMc: fliebel: You're spoiled by Clojure. :-P With locking, I think you have to lock *all places* where modification might take place.

15:01 Locking can also be done on arbitrary Objects, not just reference types.

15:03 fliebel: ah, okay :) So it's not that a place with a lock can be accessed only from one place, but rather, 2 lockings can not access the same object.

15:03 TimMc: Basically, yeah.

15:03 fliebel: &(let [at (ref 1) get-twice (fn [a] [@a (Thread/sleep 1000) @a]) fut (future (dosync (println "getting") (get-twice at)))] (Thread/sleep 500) (dosync (println "updating") (alter at inc)) @fut)

15:03 sexpbot: ⟹ updating [2 nil 2]

15:04 fliebel: mine prints getting updating getting

15:04 TimMc: In the case of dosync, transactions can be retried.

15:04 fliebel: I know, but I;m not sure I want that.

15:04 TimMc: With locking, first-in wins, and everyone else blocks.

15:05 Also, at least one thing I've said about locking is probably not true, or at least is misleading -- locks are *hard*.

15:05 fliebel: TimMc: That would be desirable, except that I don't know what Swing will do. I assume events are called on the Swing thread, so that'd freeze the UI I think. :(

15:06 chouser: refs may not be as heavy as you think

15:07 ataggart: locking grabs the monitor of the arg. it's lower-level, but less concurrent than using refs. It's really only useful when you need to synchronize with stuff in javaland.

15:07 fliebel: chouser: I'd take your word for that. A bigger problem is that the dosync would be quite big, so if that retries to often, it's not good.

15:07 TimMc: fliebel: Try it with the dosync first and see if it's really a problem.

15:07 If it is, you can export some of the work to an agent.

15:08 chouser: fliebel: can you capture all the values you need in a persistent collection, then send that off to another thread (agent or future) to do the work?

15:10 Havvy: fliebel: Is it possible to memoize some of the work done in the (dosync)?

15:11 fliebel: chouser: I'd have to think about that for a bit. The use case is that I have Swing fire events, and when I render a frame, I want to to see all the buttons pressed and such in a consistent manner during the frame. So I was thinking I could pour these events into a ref or atom, and make sure I 'lock' that during the frame.

15:11 TimMc: fliebel: You probably don't want to do your rendering in the event loop anyway.

15:12 fliebel: Havvy: Probably, but at what cost?

15:12 chouser: fliebel: all interaction with Swing should happen in the swing thread, in which case the state of the swing widgets and events will not change.

15:13 fliebel: so what I'm suggesting is when you know you want to render, go into the swing thread, collect the data you need as quickly as possible (to prevent the GUI appearing to hang), then send that (immutable) data out to some other thread to do the real work.

15:13 when the work is done (creating an offscreen bitmap or something? whatever you're doing), go back into the swing thread to display your results.

15:14 Havvy: I'm new to Clojure, so I don't exactly know the cost of memoization. chouser seems to have an equivalent solution in which you only send the results.

15:14 chouser: the state of the gui widgets might have changed in the meantime of course, but that just reality. You can choose to detect that situation and not display the now-outdated data, or whatever.

15:15 fliebel: hmmm...

15:15 Havvy: My own question: Is there a better IRC script than http://nakkaya.com/2010/02/10/a-simple-clojure-irc-client/ ?

15:15 chouser: Havvy: I think memoization usually refers to avoiding work when the input data is identical to previously calculated results. What I'm describing is more of a snapshot + pipeline or something. :-)

15:16 fliebel: That would force me into some kind of asynchronous model, because Swing events are callbacks.

15:16 TimMc: fliebel: That's pretty standard.

15:17 chouser: fliebel: yes. you can choose asynchronous, or "lock up" the gui until you're done rendering.

15:20 fliebel: I want neither. What I was describing with the ref works, except that the retries are killing… maybe.

15:20 TimMc: fliebel: You don't know that.

15:20 fliebel: I don;t know that.

15:21 TimMc: You're trying to preoptimize, and you also want a unicorn.

15:21 fliebel: yea, I love them :)

15:22 Okay, refs first, optimization later

15:22 TimMc: Havvy: The channel bots are written in Clojure but use existing Java IRC libs.

15:22 sexpbot: source?

15:22 clojurebot: source?

15:22 clojurebot: source is http://github.com/hiredman/clojurebot/tree/master

15:23 fliebel: https://github.com/cognitivedissonance/sexpbot

15:25 Havvy: So nobody has yet made IRC libs in pure Clojure?

15:26 pdk: i don't think sexpbot has any java code in it

15:26 er

15:26 irclj

15:26 hell i'll go look

15:26 yea irclj is all clojure

15:27 fliebel: hah! Using ensure, the events retry, instead of the frame :) That is just as bad as locking though. Maybe some queue trickery will work, btu that is worry for later.

15:29 Havvy: Yeah, that looks pretty good.

15:43 thorwil: i'm trying to write a simple-as possible test to learn more about a problem. a required part is a macro provided my a library, that defines a java class.

15:44 i run into "NoClassDefFoundError", no matter where i call the macro. no such problem in the real project, but there all that stuff is in another file, not core

15:46 KirinDave: thorwil: I seem to recall running into that problem myself when I was dealing with some scala integration issues.

15:47 thorwil: Referencing java classes from macros and/or making sure to properly handle symbols on the way in was unexpectedly difficult, iirc.

15:52 Havvy: Include the "lein" directory in PATH. << This is the system path that cmd searches, right?

15:52 pdk: yes

15:54 Havvy: The folder is C:/clojure/lein. Do I make C:/clojure the path or C:/clojure/lein ?

16:00 TimMc: The former.

16:02 Havvy: Wait... is lein a folder?

16:04 Havvy: TimMc: Yes, it is. (I ended up not caring about overloading the path and added both.)

16:13 TimMc: Pare it down to just the folder that the shell script is in.

16:14 Havvy: That would be C:\clojure\lein then, though I had C:\clojure in there already...not sure why though.

16:29 amalloy: TimMc: just catching up on backlog. ##(long 0x80000000) is not the same as ##(0x80000000L), i think

16:29 sexpbot: java.lang.Exception: EvalReader not allowed when *read-eval* is false.

16:29 amalloy: &(0x80000000L)

16:29 sexpbot: java.lang.NumberFormatException: Invalid number: 0x80000000L

16:29 amalloy: sexpbot, clojurebot: i hate you all

16:30 Havvy: ,(0x80000000L)

16:30 clojurebot: Invalid number: 0x80000000L

16:30 amalloy: &0x80000000

16:30 sexpbot: ⟹ 2147483648

16:31 amalloy: does clojure default to reading longs? i thought it took the same type decorators as the java compiler

16:33 ataggart: amalloy: not sure about 1.2, but the only suffixes for numbers are M and N

16:33 TimMc: amalloy: You can't do 800L or 800F in Clojure like you can in Java -- just 800M

16:33 ataggart: in 1.3

16:33 TimMc: I think N is new in 1.3

16:33 ataggart: correct

16:34 amalloy: what's N?

16:34 ataggart: BitInt

16:34 amalloy: int?

16:34 ataggart: BigInt

16:34 clojurebot: kind of interesting if unfold is the intermediate steps of a fold

16:34 amalloy: oh right

16:35 ataggart: iirc, in 1.2 the integer number is read in as a BigInteger, then placed into the smallest type that will contain it.

16:35 erm, not smallest, but either an Integer or Long

16:35 amalloy: wow, really?

16:36 ataggart: but in 1.3 it's always a long

16:36 unless it's >= 64-bits then it's a BigInt

16:37 TimMc: &2r101010101M

16:37 sexpbot: java.lang.NumberFormatException: For input string: "101010101M"

16:39 ataggart: you can only specify radix with integers

16:39 TimMc: Apparently. :-)

16:40 ataggart: I just happen to be messing with number reads in LispReader

16:40 though the cool thing that I didn't now until today was that the number before 'r' can be any integer

16:40 &3r11

16:40 sexpbot: ⟹ 4

16:41 opqdonut: &26rzz

16:41 sexpbot: java.lang.NumberFormatException: For input string: "zz"

16:41 opqdonut: &26rJJ

16:41 sexpbot: ⟹ 513

16:41 TimMc: &36rzzzz

16:41 sexpbot: ⟹ 1679615

16:41 opqdonut: yeah

16:41 10+26 to get to z

16:42 TimMc: &37r1

16:42 sexpbot: java.lang.NumberFormatException: Radix out of range

16:42 TimMc: Not *any* integer. :-)

16:43 ataggart: true, any radix that can be expressed in [0-9a-z]

16:43 any radix whose value...

16:43 TimMc: &0r00000

16:43 sexpbot: java.lang.NumberFormatException: Invalid number: 0r00000

16:43 ataggart: dammit

16:44 opqdonut: &-2r13

16:44 sexpbot: java.lang.NumberFormatException: For input string: "13"

16:44 ataggart: any positive integer...

16:44 opqdonut: :/

16:44 ataggart: I need a beer

16:44 TimMc: ataggart: You need *fewer* beers. :-P

16:45 ataggart: Yeah, I may have passed Ballmer Peak

16:46 pdk: you gonna kill google on the way down?

16:48 TimMc: ataggart: Well, at least you can still write Java.

16:49 ataggart: trained monkeys...

16:49 TimMc: "Smarter than a monkey, cheaper than a robot!"

16:50 ataggart: I for one welcome our Robot Monkey overlords

17:38 Havvy: What exactly is Swank?

17:38 My search-fu leaves me with blanks.

17:42 (or SLIME)

17:42 TimMc: It's a communication protocol to allow you to develop in a REPL from Emacs.

17:42 You keep sending definitions down to it as you edit, until they do what you want.

17:44 I think SLIME is the Emacs side of things, and Swank is the REPL side. THere's some kind of client/server model involved.

17:44 raek: slime is what you use in emacs to connect to swank-clojue, which is a clojure library

17:44 and there are other swank servers for other lisps

17:45 (swank-clojure should not be confused with the deprecated swank-clojure.el emacs frontend, use lein/cake for that instead)

17:45 ...or Durendal or elein

17:46 Havvy: Right, I have swank running via lein

17:47 But I have no clue how to use it

17:48 raek: ah, you have "lein swank" running? then just run M-x slime-connect in emacs

17:48 it might warn about version differences, but you can ignore that

17:49 Havvy: brb keyboard is freaking out: a and q are switched; among others

17:51 raek: a and q? tough... :)

17:51 Havvy: And every punctuation mark.

17:58 So the bonus of using SLIME is that if I close the session and reopen it, I still have all my definitions?

17:58 raek: yup

17:58 as long as the swank server is still running

17:59 and you can do this remotely with a ssh tunnel, too

17:59 slime offers auto-completion (C-c tab) and other useful features

18:05 Havvy: How do you close an open swank connection?

18:06 raek: Havvy: from the slime side or from the swank side?

18:06 Havvy: I can close the slime side via slime-abort-connection, so from the swank side.

18:08 I doubt killing the buffer in emacs would do it.

18:11 raek: the obvious way is to kill the lein swank process

18:11 I have looked for a way to stop the server for listening for new connections too

18:14 hrm, maybe swank.swank/start-repl returns the server socket

18:15 amalloy: a and q sounds like it's in french mode

18:16 AZERTY instead of QWERTY, though i imagine there are other swapped keys

18:16 raek: ah, yeah. that layout is really weird...

18:18 Havvy: amalloy: z, m, and some other key flipped also.

18:18 Derander: is there a way to dump function definitions from slime into a regular buffer?

18:18 I'm not really sure what I'm asking, but it'd be nice to have a quick way to develop something in the repl and then pop it over when it's done

18:18 amalloy: Havvy: well of course Z flipped, because the W key was emitting Z

18:19 but i don't ever actually type in french; i just know their layout is called azerty

18:32 raek: Derander: when you evaluate a defn, the source code for it will not be stored in the runtime of clojure. so you can't go from function object to source code

18:32 Derander: that's unfortunate

18:33 raek: clojure code gets compiled to JVM bytecode

18:34 Derander: you might find this interesting: http://bc.tech.coop/blog/070424.html

18:34 it's a bit like the reverse: you can take expression from the source file and send them to the repl

18:35 Derander: yeah.

18:35 my workaround has typically been to write in the buffer and C-M-x over to the repl

18:36 raek: I usually edit the defn, C-M-x it, and then try it in the repl

18:36 Derander: yeah.

19:06 simard: what flag should I use with format so that it can accept to print both numbers and ratios ?

19:13 kephale00: Does anyone know how a way to cap the CPU usage of a clojure program thats written to use agents? I have a shared machine that pauses my job if I exceed a threshold of CPU usage.

19:15 Errr… and please ignore the fact that I rephrased that question a few times and apparently didn't read it over

19:16 ataggart: simard: %s

19:39 chouser: kephale00: insert some thread sleeps?

19:40 & (format "<<%s>>" (pr-str 2/3))

19:40 sexpbot: ⟹ "<<2/3>>"

19:40 chouser: & (format "<<%s>>" (pr-str 4.5))

19:40 sexpbot: ⟹ "<<4.5>>"

19:40 chouser: simard: ^^

19:47 kephale00: chouser: well, its a nuisance as I am running the same code on some machines that I don't share, some that I do… right now it is looking like the best option is to call the code with cpulimit (a sf.net prog)

19:54 chouser: kephale00: that sounds better

19:55 kephale00: chouser: still doesn't sound as good as not sharing nodes though ; )

20:29 TimMc: Having trouble with leiningen's "checkout dependencies".

20:30 I've symlinked ~/repos/feedback as ./checkouts/feedback, and I'm using dependency line [org.timmc/feedback "0.4.0-SNAPSHOT"] -- but lein deps says the dep is missing.

20:32 yayitswei: hello, newbie here. I'd like to sort a map by value, and then insert new values in the correct place. what's the appropriate data structure to use?

20:32 kephale00: chouser: incidentally, cpulimit isn't strict enough… so the problem is still unsolved

20:32 TimMc: Is there somethin I need to do to makelein look in checkouts?

20:36 (lein install works)

20:49 yayitswei: So, you want to keep a map sorted by values?

20:49 yayitswei: yes, i'm looking at sorted-map-by now

20:50 TimMc: I think that will only let you sort by keys.

20:50 yayitswei: so that works for creating a map (looks like it returns a clojure.lang.PersistentTreeMap). but I don't know how to insert a key-value pair into a sorted map

20:50 TimMc: yayitswei: You just use assoc as usual.

20:50 amalloy: didn't i just recently see something about priority queus in clojure?

20:51 that's basically a map sorted by value

20:54 yayitswei: ah, priority queue might work. here's how I'm currently creating the sorted map: (let [m { "e" 5 "b" 2 "a" 1} sm (into (sorted-map-by #(< (m %1) (m %2))) m)] sm)

20:55 TimMc: Clever, but it won't help with insertions.

20:55 yayitswei: but (assoc sm "d" 4) gives me a nullpointerexception

20:55 * TimMc imagines something horrible with refs

20:56 TimMc: Nvm, that wouldn't even work.

20:58 yayitswei: @amalloy, is this what you are referring to?

20:58 http://clojure.github.com/clojure-contrib/branch-master/priority-map-api.html

20:58 amalloy: yeah

20:59 yayitswei: is there a way to use it now or is it currently unimplemented?

20:59 TimMc: How do I change the logging level with clojure.contrib.logging?

21:00 ataggart: TimMc: the same way you do with whatever does the actual logging

21:01 amalloy: TimMc: it involves prayer and ritual sacrifice. logging is a pain

21:02 ataggart: it's easy to change logging level, it's just not easy to do at the repl

21:02 since none of the java libs were written with a repl in mind

21:02 yayitswei: nvm, I found the source! thanks for the help

21:02 TimMc: Oh! So... do I put a log4j.properties file somewhere?

21:02 ataggart: if you're using log4j, then yes

21:03 c.c.logging just delegates to whatever lib it finds

21:03 TimMc: Ah, so I need to include one or more deps.

21:04 ataggart: read the docs

21:04 http://clojure.github.com/clojure-contrib/logging-api.html

21:05 somewhat better doc in the master branch http://clojure.github.com/clojure-contrib/branch-master/logging-api.html

21:05 amalloy: TimMc: sexpbot changes log levels on the go with https://github.com/cognitivedissonance/sexpbot/blob/master/src/sexpbot/plugins/log.clj#L23 and https://github.com/cognitivedissonance/sexpbot/blob/master/src/sexpbot/utilities.clj#L83

21:05 and he uses log4j

21:06 ataggart: that doesn't always work

21:06 hierarchical loggers are more complex than that

21:06 amalloy: yes, and i avoid dealing with them. just set up a root logger and hope for the best

21:06 TimMc: ataggart: Thanks, the log4j example in the 1.3 docs is helpful.

21:08 ataggart: TimMc: note that the api in 1.3 is different from 1.2

21:08 TimMc: OK, thanks.

21:11 ataggart: amalloy: are properties files that hard?

21:11 TimMc: I can't figure out where to put the properties file now.

21:11 amalloy: ataggart: changing log levels on the fly is a desired feature

21:11 $login

21:11 sexpbot: You've been logged in.

21:11 amalloy: $log debug clojure

21:11 etc

21:11 $log info clojure

21:11 $logout

21:11 sexpbot: You've been logged out.

21:12 amalloy: if i had to restart sexpbot to get debug info he wouldn't be very reliable as an always-on daemon

21:13 ataggart: amalloy: who said anything about restarting?

21:14 iirc lo4j reloads the config upon change

21:15 granted, it's nice to have an interactive api, but the solution sexpbot uses isn't sufficient for common use.

21:15 amalloy: ataggart: i don't have (easy) write access to the file system sexpbot is running on. sending him a message over irc is a zillion times easier

21:16 ataggart: agreed, so long as no one thinks it's trivial to implement on top of j.u.logging, log4j, etc. in a consistent and understandable manner

21:17 amalloy: where does the logging output go?

21:17 amalloy: ataggart: ugh, nowhere good. probably the console; it's been a while since i messed with his logging

21:28 ataggart: amalloy: ah yeah that was the other problem, with some log libs a given category/package can have multiple handlers, each with a different level.

21:28 so (set-level *ns* :debug) isn't really specific enough

21:42 Havvy: My classpath is:

21:42 (#<URL file:/C:/clojure/lein/converter/src/> #<URL file:/C:/clojure/lein/converter/test/> #<URL file:/C:/clojure/lein/converter/classes/> #<URL file:/C:/clojure/lein/converter/lib/clojure-1.2.1.jar> #<URL file:/C:/clojure/lein/plugins/swank-clojure-1.3.0.jar>)

21:43 I'm trying to use the file at C:/clojure/lein/converter/src/converter.clj via (use 'converter) and getting java.lang.ClassNotFoundException

21:44 tomoj: which class isn't found?

21:44 Havvy: Wait, found the error. (I hate dependencies...)

21:45 tomoj: what's the plugins thing? new lein feature?

21:45 amalloy: pretty old lein feature

21:45 Havvy: As far as I can tell, it allows me to open Swank from the Dos shell.

21:47 tomoj: the word for "new" in lojban has a parameter for "to whom" :)

21:47 amalloy: oh, lojban

21:48 tomoj: what is it, global plugins?

21:48 amalloy: yeah

21:53 Havvy: What the plugin does, I do not know.

21:54 tomoj: do I just drop a jar into ~/.lein/plugins?

21:55 oh I see there's a plugin task

21:55 amalloy: tomoj: lein also has a plugin command

22:21 chett: (defn up [] run-jetty my-app {:port 8080}))

22:21 When I call this my repl hangs

22:23 Any tips to fix this or at least bring back the repl?

22:23 brehaut: chett: add :join? false to your options

22:23 chett: and if you use #'my-app

22:24 then the var for my-app is captured and you can redefine it without having to restart jetty

22:24 (without the #' [var quote] the var is resolved and the value at that var is bound)

22:25 chett: brehaut: trying this now, thanks

23:19 technomancy: TimMc: glad I could get retest sorted out. I don't have plans to make it work on a per-deftest level, but if anyone else wants to implement that I'd be happy to merge it.

Logging service provided by n01se.net