#clojure log - Mar 15 2010

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

0:04 psykotic: does map ever automagically call sorted-map like it calls hash-map and array-map? or is it only ever used when you call it explicitly?

0:12 JonSmith: map is for mapping, and produces seqs

0:12 as far as i know anyway

0:19 dcnstrct: what's the most simple way to get a random element from a vector ?

0:24 rfg_: dcnstrct: (nth coll (rand-int (count coll)))?

0:24 dcnstrct: ahh rand-int thnx

0:25 rfg_: :)

0:27 psykotic: JonSmith: sorry, bad formulation. i really meant (into {} ...), conjing onto a map, and so on

0:28 for example, up to size 9, it uses an array map, and then it uses a hash map

0:28 hiredman: if you into a sorted-map you will get a mp

0:28 psykotic: actually that is not something into does

0:28 psykotic: conj presumably?

0:28 hiredman: array map promotes under the covers

0:29 psykotic: right

0:29 i'm looking at the code actually

0:29 hiredman: the clojure or the java?

0:29 psykotic: java

0:29 anyway, regardless of mechanism, is there a case in which something is promoted/demoted/whatever to a sorted map if it isn't already?

0:30 or is it opt-in only?

0:30 hiredman: into goes into the specified container type

0:31 ,(type (into (sorted-map) {:a 1 :b 2}))

0:31 clojurebot: clojure.lang.PersistentTreeMap

0:31 psykotic: yes, clearly

0:31 anyway. i think i've answered my question.

0:38 maxhodak: it says I can't "send to channel"?

0:39 hmm. that seems to have gone through

0:44 dcnstrct: you have to verify your nick with chanserv first

2:04 sproust: Quick question: my clj script won't exit.

2:04 I run a clj script I built, which invokes clojure.main with the text.clj script I wrote.

2:04 UNIX style.

2:04 clojurebot: style is http://paste.lisp.org/display/81021

2:04 sproust: clojure.main does not exit.

2:04 Is there anything special I need to do?

2:05 Do I need to exit explicitly?

2:05 (I'm guessing this is a common problem.)

2:06 Aaah, oops never mind. It seems related to lazy-xml parsing.

2:07 It's strange, when I invoke parse-seq, it won't exit.

2:56 nipra: Hi

2:57 tomoj: hello

3:02 nipra: M-. (slime-edit-definition) is failing with following error: ``Search failed: " clojure/core.clj$"''. It was working fine I was using Emacs starter kit. Some info here: http://pastebin.com/xMmuH9jj

4:57 mauritslamers: hi all, is it known behaviour that fields in an SC.Query condition are camelcased?

4:57 that is: camelcased automatically?

5:17 Does anyone have problems regarding SC.Query.local? It just does not seem to work...

5:22 hoeck: mauritslamers: can you please give some context?

5:22 mauritslamers: with pleasure :)

5:22 hoeck: great!

5:22 :)

5:22 mauritslamers: I have a set of records loaded from my db backend

5:22 (I'll gist some stuff)

5:23 ehhh hoeck... wrong channel :-)

5:23 Oops :)

5:23 hoeck: ahhhh :)

5:23 mauritslamers: Weird Program Colluquy

5:24 hoeck: sorry about that :)

5:24 hoeck: never mind

5:29 Licenser_: aloa

5:29 morning my lispy friends

5:31 hoeck: Good Morning Licenser_

5:41 nipra: How can I apply a function to all keys of a map recursively?

5:45 esj: what do you mean recursively ?

5:45 (map #(...) (keys my-map)) not gonna work ?

5:47 nipra: esj: map may contain map(s) at any level. function should apply to all keys.

5:47 esj: aah, i get you now

5:53 noidi: nipra, do you want to apply the function to all the values that are not maps themselves?

5:56 nipra: noidi, I want apply function to keys of a map at any level inside the map. So value may be a map or seq of map(s).

5:57 esj: something like

5:57 (defn t [x]

5:57 (if (map? (second x))

5:57 (map t (second x))

5:57 (first x)))

5:57 ?

5:59 call it with (may t my-nested-map) and it will spit out the keys, nested

5:59 s/may/map/

6:06 hoeck: nipra: http://paste.lisp.org/display/96405 ?

6:06 noidi: heh, here's my version with another interpretation of the spec :) http://gist.github.com/332691

6:06 fun puzzle!

6:07 esj: a nice sedge into Monday

6:09 noidi: yup, writing that was a fun way to get back into coding mode after lunch break :)

6:09 esj: hahah, I'm still winding up (only one coffee down)

6:10 bobo_: http://gist.github.com/332692 any clue why the values dont get stored in the session? even if i print them in the line below they are nil

6:14 nipra: noidi, (map-keys keyword {"a" 1 "b" [{"c" 1}]}) => {:a 1, :b [{"c" 1}]} ;; "c" doesn't get keyfied :-(

6:15 noidi: ah, so you want to recurse into seqs, too

6:15 nipra: noidi, yes

6:18 noidi: nipra, I updated the gist http://gist.github.com/332691

6:21 nipra: noidi, (map-keys keyword {"a" 1 "b" [{"c" 1}]}) => {:a 1, :b [{"c" 1}]} ;; Same as earlier

6:22 noidi: are you sure you're not using the older version of the function?

6:22 I copied that example out of my REPL

6:25 nipra: noidi, opps.. my bad. Thanks a lot! That works. :-)

6:33 noidi: nipra, great!

6:50 nipra: noidi, I think that function should be included in clojure.contrib.map-utils as deep-apply-to-keys. And there should be deep-apply-to-vals too. :-)

6:52 psykotic: i'm watching the interview with stuart on infoq and want to stab the interviewer in the neck.

6:52 nipra: psykotic, why?

6:52 psykotic: he's a horrible interviewer.

6:52 nipra: It's a nice interview.

6:52 psykotic: stuart is great

6:53 all the infoq interviews by this guy have the same problem.

7:07 noidi: psykotic, yeah, that interview seemed really weird to me, too

7:07 it seemed as if the interviewer was just coming up with the questions off the top of his head

7:08 while stuart had clearvoyantly anticipated his questions and prepared good answers to them :)

7:08 *clairvoyantly

7:13 psykotic: noidi: that guy is _always_ like that.

7:14 usually they have fantastic interview subjects. it's a shame to waste opportunities like that with bad questions and an interviewer who just parrots the prepared questions without engaging the interviewee.

7:38 licoresse: Looking for a smarter way to do:

7:38 ,(zipmap (range -1 -9 -1) (repeat 8 -1))

7:38 clojurebot: {-8 -1, -7 -1, -6 -1, -5 -1, -4 -1, -3 -1, -2 -1, -1 -1}

7:40 noidi: you can at least drop the "8" because the range is fixed

7:40 licoresse: ok

7:41 noidi: ,(zipmap (range -1 -9 -1) (repeat -1))

7:41 clojurebot: {-8 -1, -7 -1, -6 -1, -5 -1, -4 -1, -3 -1, -2 -1, -1 -1}

7:42 licoresse: it still feels rather thorough

7:45 would this be possible to do using the juxt function?

7:51 hoeck: licoresse: can't see how to use juxt here

7:52 licoresse: the zipmap can be a bit shorter by using (range -9 -1)

7:52 licoresse: hoeck: yes, thats even better

7:52 ulfster: ,(range -8 0)

7:52 clojurebot: (-8 -7 -6 -5 -4 -3 -2 -1)

7:54 licoresse: anyhow, it's now in reverse order

7:55 ulfster: does not matter since it is a map

7:55 licoresse: ,(zipmap (range -8 0) (repeat -1)

7:55 clojurebot: EOF while reading

7:55 licoresse: ,(zipmap (range -8 0) (repeat -1))

7:55 clojurebot: {-1 -1, -2 -1, -3 -1, -4 -1, -5 -1, -6 -1, -7 -1, -8 -1}

7:55 ulfster: you access it via the keys, so the order of entries should not matter

7:55 ,((zipmap (range -8 0) (repeat -1)) -3)

7:55 clojurebot: -1

7:56 licoresse: ok

7:56 I need to think this through, thanks

8:02 altering the range, the final result should look like this:

8:02 {1 [-4 -1] 2 [-3 -1] 3 [-2 -1] 4 [-1 -1] 5 [1 -1] 6 [2 -1] 7 [3 -1] 8 [4 -1] 9 [4 1] 10 [3 1] 11 [2 1] 12 [1 1] 13 [-1 1] 14 [-2 1] 15 [-3 1] 16 [-4 1]}

8:03 or something similar where I have indexed access

8:04 it's four quadrants

8:05 ulfster: ,(zipmap (range 17) (for [x (range -4 5) y '(1 -1)] [x y]))

8:05 clojurebot: {0 [-4 1], 1 [-4 -1], 2 [-3 1], 3 [-3 -1], 4 [-2 1], 5 [-2 -1], 6 [-1 1], 7 [-1 -1], 8 [0 1], 9 [0 -1], 10 [1 1], 11 [1 -1], 12 [2 1], 13 [2 -1], 14 [3 1], 15 [3 -1], 16 [4 1]}

8:05 ulfster: not quite

8:05 licoresse: :-)

8:05 ulfster: is the indexing fixed?

8:06 licoresse: yes

8:06 ulfster: left -> right, top -> bottom?

8:06 licoresse: yes

8:06 then right -> left again

8:07 clockwise

8:07 the (for construct is interesting though

8:08 ulfster: ,(for [y '(1 -1) x (range -4 5)] [(* x y) y])

8:08 clojurebot: ([-4 1] [-3 1] [-2 1] [-1 1] [0 1] [1 1] [2 1] [3 1] [4 1] [4 -1] [3 -1] [2 -1] [1 -1] [0 -1] [-1 -1] [-2 -1] [-3 -1] [-4 -1])

8:08 ulfster: wohoo ;)

8:08 licoresse: ulster: great stuff! :-)

8:08 ulfster: now just zipmap that with the indexrange

8:09 licoresse: thanks a lot

8:09 ulfster: no prob

8:09 but beware, just works because 1 and -1 are the only indices of the second coordinate

8:09 licoresse: yes, I see that

8:10 ulfster: oh, and you need to invert y as well

8:10 it is switched now

8:11 licoresse: yup

8:24 dkc: hi, vimclojure question

8:24 repl works but "el" or similar give the following error: http://pastie.org/870161

8:24 this is using "lein nailgun" to run the ngserver..

8:28 sattvik: dkc: Is the base directory of your clojure sources in your classpath? I don't know how 'lein nailgun' sets up your classpath.

8:29 dkc: yep .. it must be because the repl in vimclojure works fine, and i can run code directly in there

8:41 licoresse: seems real life is always more difficult :)

8:41 ,(let [r (filter #(not (= 0 %)) (range -4 5))] (concat (for [x r] [x -1]) (for [x (reverse r)] [x 1])))

8:41 clojurebot: ([-4 -1] [-3 -1] [-2 -1] [-1 -1] [1 -1] [2 -1] [3 -1] [4 -1] [4 1] [3 1] [2 1] [1 1] [-1 1] [-2 1] [-3 1] [-4 1])

8:41 licoresse: ulfster: ^

8:43 it's still shorter than the list it's going to produce, guess that's a good thing

8:47 chouser: ,(into {} (map #(vector %1 [%2 %3]) (iterate inc 1) (concat (range -4 5) (range 4 -5 -1)) (cycle [-1 1])))

8:47 clojurebot: {1 [-4 -1], 2 [-3 1], 3 [-2 -1], 4 [-1 1], 5 [0 -1], 6 [1 1], 7 [2 -1], 8 [3 1], 9 [4 -1], 10 [4 1], 11 [3 -1], 12 [2 1], 13 [1 -1], 14 [0 1], 15 [-1 -1], 16 [-2 1], 17 [-3 -1], 18 [-4 1]}

8:48 licoresse: hehe, nice

8:48 chouser: oh, that's not quite what you want is it.

8:48 licoresse: no

8:48 :)

8:48 hard to read those numbers

8:48 seths: sitting at the Clojure training session :-)

8:49 chouser: is it ok except for the second item of each vector?

8:49 seths: ooh!

8:49 licoresse: chouser: it has to be excactly as my version

8:49 chouser: seths: when does it start?

8:49 seths: 10 min

8:49 posting pic to twitter

8:51 licoresse: chouser: yours goes through 0, mine does not

8:52 ulfster: ,(for [y '(1 -1) x (range -4 5)] [(* x y) (* -1 y)])

8:52 clojurebot: ([-4 -1] [-3 -1] [-2 -1] [-1 -1] [0 -1] [1 -1] [2 -1] [3 -1] [4 -1] [4 1] [3 1] [2 1] [1 1] [0 1] [-1 1] [-2 1] [-3 1] [-4 1])

8:52 licoresse: ulfster: still the 0

8:52 the problem is range

8:52 ulfster: oh, now i see

8:52 licoresse: that's why I use the filter

8:53 but just replace the range, and it's cool

8:53 ulfster: ,(for [y '(1 -1) x (range -4 5) :when (not= 0 x)] [(* x y) (* -1 y)])

8:53 clojurebot: ([-4 -1] [-3 -1] [-2 -1] [-1 -1] [1 -1] [2 -1] [3 -1] [4 -1] [4 1] [3 1] [2 1] [1 1] [-1 1] [-2 1] [-3 1] [-4 1])

8:54 licoresse: ah, did'nt know you could :when....

8:54 hmm

8:54 ulfster: this should be the shortest ;)

8:54 licoresse: yeah, you win ulfster!

8:55 amazing

8:55 chouser: seths: at the day-long tutorial in Boston alomst exactly a year ago, people were mostly also in here chatting in parallel to rhickey's presentation.

8:56 ulfster: way to seek out a deeper pattern in the series!

8:58 ulfster: chouser: more like blind luck + a little intuition :)

8:58 seths: chouser: any problems with me giving a live feed of sorts?

8:59 chouser: seths: heh, I don't see how my opinion matters. You're paying good money to be there, you should do what makes sense for you.

8:59 seths: just didn't want to spam the channel

8:59 fogus asked me via twitter for a live feed

8:59 chouser: oh, I see. I doubt people here would mind.

9:00 fogus: seths: I was just joking... but also would not complain to see one. ;-)

9:01 seths: fogus: howzabout I put my comments into a lazy sequence, and you can just consume them as needed

9:02 chouser: :-)

9:02 cemerick: chouser: wow, that *was* a year ago. Yikes.

9:02 chouser: hm, but that's more of a work queue than a lazy seq.

9:03 cemerick: :-/ yeah.

9:03 fogus: "If you need a work queue, then use a work queue" --chouser

9:04 chouser: heh, that sounds lame. from the book isn't it. :-P

9:04 fogus: I'm paraphrasing -- but I think that is in there somewhere

9:04 chouser: yeah, I think you're right.

9:05 oh well. I guess it's at least hard to refute.

9:05 cemerick: that's a pretty fine line, no?

9:05 * cemerick is blathering without context as usual

9:05 chouser: cemerick: between a work queue and a lazy seq?

9:06 dkc: is there a way to figure out the cwd from a clojure repl?

9:06 cemerick: yeah. The latter is the former sometimes. It's all about how you use it, IOW.

9:06 or, abuse it, perhaps

9:07 chouser: I think the main difference is that "consuming" a seq (that is, calling 'rest') doesn't change anything visible to anyone else -- others walking the same seq will see the same items

9:08 While consuming a work queue (.take or .pop or whatever...) is meant as an atomic operation such that other threads will never see that same item and instead get their own.

9:09 fogus: Seems to me that since that line is in the book, we pretty-much have to show an example at some point.

9:10 chouser: you can indeed build a work queue out of a lazy seq plus a reference of some sort (agent? atom? cell?) but why when Java comes with perfectly good work queues already?

9:10 cemerick: chouser: Ah, sure. 'course, I just drop a (cons nil (some-lazy-seq)) into an atom, and then pound away at it with (first (swap! my-atom rest)) :-)

9:11 chouser: cemerick: that's all fine until rhickey catches wind of it starts shooting mildly disapproving looks at you.

9:11 :-)

9:11 cemerick: chouser: because having a fn that returns a lazy seq is a lot easier than bothering with producers or "manually" pushing items into a queue.

9:11 chouser: fogus: yeah, I guess you're right.

9:11 cemerick: I'm happy to be shown how that's bad, but it seems too elegant to give up lightly.

9:12 fogus: One of those images I sent to you should be accommodating to a work queue

9:12 (with some modification)

9:13 cemerick: besides, the tagline under my name should be "getting mildly disapproving looks from rhickey since 2008" :-P

9:13 chouser: hehe

9:13 fogus: cemerick: wear it like a badge of honor

9:13 cemerick: fogus: oh, I do :-D

9:14 just like I can reminisce about how there used to be < a dozen folks here

9:14 Thinking about it that way, it's pretty amazing how far things have come in just a couple years

9:15 tomoj: is putting a PersistentQueue under an atom evil?

9:15 cemerick: tomoj: encouraged, I'd say :-)

9:15 tomoj: ok

9:15 chouser: tomoj: no, but do consider the features provided by java.util.concurrent.BlockingQueues and make sure that's not closer to what you want.

9:16 tomoj: that does look pretty cool

9:18 cemerick: chouser: see, the thing about the BlockingQueues for me is that .add is a pointless operation in a multi-node/multi-vm environment. e.g. the next item is whatever the idle node can grab next from the datastore, not what has been pre-emptively reserved for it locally.

9:21 tomoj: what's a good way to represent a cursor into a cyclic linked-list ?

9:21 mattrepl: that's where having multithreads becomes a pain when fitting into the message/job queue paradigm that usually relies on multiple processes

9:21 re: local queue

9:22 chouser: cemerick: I'm wavering

9:23 dkc: hi ... are there any vimclojure / lein-nailgun users around?

9:23 chouser: a p-queue in an atom still doesn't feel quite right, because adding to the queue is a side-effecty thing, as is popping from it. If that's what you want, why not use a BlockingQueue and that hand blocking behavior?

9:23 cemerick: mattrepl: not sure I follow -- why are multiple threads an issue?

9:24 chouser: on the other hand, if your queue filler is more natural as a lazy seq ...indeed, why would you not drop that in an atom?

9:25 cemerick: chouser: yeah, that's the right balance. If I were in a single-process env, then a BQ would be the way to go.

9:25 mattrepl: cemerick: I'm thinking from the standpoint of a system where there are multiple worker processes. you'd have some external queue (rabbitmq, beanstalk, gearman)

9:25 chouser: esp if you want the fill work fully delayed until the moment of consumption -- that work then actually being done by the consuming thread.

9:26 cemerick: mattrepl: yes. We're hoping for a queue abstraction to go with the sequence abstraction eventually. :-)

9:26 mattrepl: feel free to take a crack at it, tho ;-)

9:26 mattrepl: cemerick: if each worker process is really a pool of many worker threads then the threads will need to access the external queue. using a BlockingQueue or such inside the JVM process introduces an opportunity for error and losing jobs, etc

9:27 cemerick: mattrepl: right, which is why I don't use BQs

9:27 mattrepl: cemerick: I have been. And I'm now getting back into Hadoop. =)

9:27 cemerick: sorry :-P

9:28 * cemerick feels unreasonably biased against hadoop given his early experiences with it

9:28 mattrepl: the queue abstraction would be nice

9:30 does it deal with multiple consumer processors? or any idea how one would use the queue abstraction in the manner?

9:31 cemerick: mattrepl: there is no queue abstraction yet. It's only been mentioned conceptually by rhickey AFAIK.

9:32 mattrepl: cemerick: right, sorry. I meant if that was within its scope. wasn't sure if someone had begun fleshing it out

9:32 cemerick: no idea

9:32 not AFAIK

9:47 djpowell: dkc: (.getAbsolutePath (java.io.File. ".")) - works for me

9:48 dkc: djpowell: thanks :)

9:48 djpowell: or maybe: (.getCanonicalPath (java.io.File. "."))

9:49 dkc: djpowell: i wound up using (sh "pwd") after importing the shell libs

10:03 psykotic: has anyone played with clojure/compojure on google appengine, had an app work fine with the local devserver, but get a class-not-found server when it was deployed to appengine?

10:04 server error, even

10:14 chouser: ok, it just struck me how deeply wrong it is that in normal OOP all the methods live in the same namespace.

10:15 I mean, I know this is something rhickey already identified and Clojure already solves, but I just now connected that to a kind of ugliness I've been seeing lately.

10:15 fogus: chouser: care to elaborate?

10:15 psykotic: what kind of ugliness?

10:15 i admit that aspect of oo has never been a problem for me

10:16 chouser: any time that you want to combine groups of methods from two different sources

10:16 psykotic: well, that's prevented at a more fundamental level by most OO languages, unless you are talking about insane ruby-style monkeypatching

10:17 Licenser_: if I try to make a nice and clean namespace concept I always seem to run into circle issues

10:17 chouser: for example, a remote object stub or proxy that has methods defined by some IDL but also some common API methods provided by the framework

10:18 you end up with one group or the other getting ugly method prefixes or something -- always feels like a hack.

10:18 fogus: chouser: Isn't the class itself a sort-of namespace?

10:19 psykotic: chouser: but you have the same problem here if you wanted to merge two namespaces' worth of generic functions into a single one

10:19 chouser: or if you're implementing interfaces from two different libs, maybe most of the time you're lucky that the method names don't clash, but if they *do*, then what?

10:19 psykotic: but why would you do that?

10:19 psykotic: i might as well ask why you'd use inheritance in your example

10:19 chouser: in clojure you can have a single object respond to both your-namespace/doathing and my-namespace/doathing

10:20 psykotic: sure

10:21 and you can use proxies/adapters to get a similar level of explicitness

10:21 not that i think that's nice or anything. i hate most of what passes for oo at a funamental level.

10:21 chouser: psykotic: I could provide a number of examples. :-) How about trying to build a single object that can be stored by some persistence lib over here, and also be sent across the wire by some rpc lib over there -- both want me to define "getId", but one wants a string and the other a byte array.

10:22 psykotic: like i said, a solution is always to use adapters, which is explicit

10:23 i.e. you call persistentAdapter() or whatever and it returns an instance of that persistence interface for your object

10:23 not pretty but hey :)

10:23 chouser: psykotic: sure, or for each lib to use a unique method name "persist_getId" vs "rpc_getId". Exactly, not pretty.

10:23 nobody's arguing Java's not Turing complete. :-)

10:24 But Clojure's solution is so clean. No adapters, no extra allocations, nothing required of either lib that they wouldn't already do naturally.

10:25 spariev: how could I access POST request body in Compojure ? There is :body stream in request map, but it looks like it is empty

10:25 chouser: fogus: yes, a class acts as a namespace. But that's kind of the problem -- I want to merge two namespace only because the class is *also* used to identify the methods an object implements.

10:26 noidi: chouser, that reminds me of http://threebrothers.org/brendan/blog/death-by-duck-typing/

10:26 chouser: fogus: Clojure's namespaces are just namespaces, so there's no need to merge them. For implementing functions on types, you can use multimethods or protocols.

10:28 spariev: Is that true that input stream from ServletRequest (accessed via getReader or getInputStream) could be read only once ?

10:28 noidi: tl;dr version: when the duck typed object's methods have the names you expect but different semantics, you get in trouble

10:28 cemerick: spariev: given the servlet spec, yes

10:28 noidi: clojure sidesteps that problem nicely

10:29 psykotic: chouser: generic functions are definitely awesome. i only wish clojure core wasn't so shy about them :)

10:29 but i guess you can actually rebind the vars if you want to offer something more generic

10:29 (for arithmetic say)

10:29 fogus: chouser: I understand. I suppose that my typical way to handle your original scenario has been some sort of delegate/proxy... lots of infrastructure.

10:30 spariev: cemerick: thanks, I couldn't remember that. so it looks like my problem is Compojure reads body before I access it

10:30 chouser: psykotic: that'll change some. multimethods were "too slow", but protocols will be used more heavily by core.

10:30 noidi: yeah, interesting.

10:30 cemerick: spariev: compojure doesn't do much of anything by default. If you're using some middleware (like the file upload middleware), then yes, that will read the body before you get the request.

10:31 chouser: actually, Clojure side-steps that with constant vigilance, not through anything automatic.

10:32 that article's actually an argument for not having a single function that does both (some #{k} coll) and (contains? coll k)

10:32 cemerick: spariev: actually, I'll bet it does always read the body on at least most POSTs in order to parse params

10:35 spariev: cemerick: yep, I found it in the sources. There is should be a way to declare routes without params parsing

10:37 noidi: chouser, also, namespace prefixes become a sort-of hungarian notation that might also help a bit

10:37 i.e. (bar/do-something (foo/update my-foo)) looks wrong

10:38 chouser: sorry, what's wrong with that?

10:38 spariev: oops, should have searched compojure group first - The (request :body) input stream only gets consumed if the content

10:38 type is "application/x-www-form-urlencoded"

10:42 noidi: chouser, ok, bad example :) if functions dealing with a data structure are in a namespace named after it, and they take the structure as their first argument, (document/print (person/set-age bob 42)) looks wrong because document/print expects a document but gets a person

10:42 chouser: ah. hm.

10:43 noidi: maybe that's too OO-like for clojure code, but that's what I've been doing

10:44 chouser: I don't know that that looks wrong. To the extent that it does, perhaps "document" is mis-named.

10:46 seths: from Rich's talk. Clojure is (overstrike) was a solo effort

10:49 noidi: on a related note, is it considered good style to have abstract data that is treated as a black box outside its accessor functions?

10:50 stuarthalloway: noidi: less often than most languages would suggest

10:50 noidi: currently I do that, but extract as many generic helpers operating on collections from the "abstraction code" as possible

10:51 I'm still having trouble adjusting to non-OO programming, but so far this style seems to hit the sweet spot between narrow interfaces and many functions operating on few data types

10:52 psykotic: stuarthalloway: i saw the infoq interview. you were great but that interviewer... :)

10:52 noidi: I agree, great interview!

10:53 stuarthalloway: thanks!

10:54 psykotic: stuarthalloway: were you there to give a talk?

10:54 noidi: but yeah, every time I try to write code with non-encapsulated domain data structures, I always get the nagging feeling that I won't be able to change the representation later without breaking all the clients

10:54 stuarthalloway: psykotic: yeah, and that is supposed to get posted online too

10:54 it was a talk about experience with clojure in production, I think lots of people would be interested

10:55 psykotic: cool

10:55 noidi: if someone can suggest something like the SOLID principles of OO but for functional programming, I'd love to read it :)

10:55 stuarthalloway: I am going to reprise it at the end of the pragmaticstudio this Wed

10:55 icey: stuarthalloway: during the studio or at the talk over at oracle?

10:55 fogus: stuarthalloway: Looking forward to that talk

10:55 stuarthalloway: icey: hmm, good question, how about both? :-)

10:55 haven't really decided what to talk about at oracle

10:55 icey: stuarthalloway: I would love it during the stuio :D

10:56 s/stuio studio

10:56 stuarthalloway: if you know someone at infoq you could ask them when they plan to post it

10:58 chouser: stuarthalloway: tea-break at the pragmaticstudio?

10:58 stuarthalloway: chouser: nah, just ignoring rich talk

10:58 :-)

10:59 I have "continuous partial attention disorder"

10:59 chouser: heh

10:59 stuarthalloway: rich is doing a cool job of interleaving fun nuggets of detail in the overview talk

11:00 fogus: has he mentioned Whitehead yet?

11:00 stuarthalloway: keeping it interesting for people who already know clojure while bringing the beginners up to speed

11:00 fogus: that's tomorrow

11:00 fogus: sweet

11:02 tjg: ,(= 0.8M 8/10)

11:02 clojurebot: false

11:02 tjg: ,(= 0.9M 9/10)

11:02 clojurebot: true

11:03 rys: mmm, floating point

11:03 tjg: Is that supposed to happen?

11:04 I thought that ratios and bigdecimals were somehow "exact".

11:05 zmila: interesting, our company has survey on what trainings the employe want: what languages/technologies are interesting. From about 300 answers there are 4 interested in FPL (scala,haskell,clojure,scheme).

11:05 tjg: I kinda thought it was just my b0rken Clojure build, or something. ;)

11:05 noidi: can anyone recommend some good, open source clojure _application_ code to study? I'd like to see how others deal with domain data instead of generic things like the built-in collections.

11:05 stuarthalloway: zmila: what were the most requested?

11:06 noidi: the current dev edge of compojure

11:06 noidi: stuarthalloway, thanks

11:07 zmila: there were questions for junior and senior developers: what direction they want to progress. the most are the languages, used in our company production: c# and java. but i was pleased that 4 people are familiar with names clojure/scala

11:08 tjg: Ah, no, sorry, didn't read BigDecimal's javadocs...

11:12 stuarthalloway: noidi: here is a fun one-off example: http://github.com/relevance/labrepl/blob/master/src/solutions/rock_paper_scissors.clj

11:14 noidi: stuarthalloway, thank you!

11:22 the main reasons why I encapsulate my domain data are that: 1) often updating one piece of data requires that others are updated so the object remains valid, 2) I want to be able to change my data's representation without breaking its users

11:23 stuarthalloway: noidi: still valid ideas in clojure, but...

11:23 (1) you could tie validations to identities (reference types) instead of data itself

11:23 (2) you could allow multiple representations and provide transformation functions

11:24 chouser: is data encapsulation in direct conflict with solving the expression problem?

11:24 noidi: chouser, expression problem?

11:24 stuarthalloway: (3) as soon as you persist or go out of process you make a long run commitment to the data as a contract

11:25 chouser: getting libraries from providers A and B to work with your code while avoiding endless adapters, conversions, etc.

11:25 I'm sure that's a bad definition of the expression problem, but that's the right general space.

11:26 stuarthalloway: chouser: I expect to see a better definition in an advanced clojure book someday :-)

11:26 chouser: :-P

11:27 noidi: stuarthalloway, regarding (3), in an encapsulated version only the import/export code needs to know how to deal with many versions of the data structure

11:27 whereas without encapsulation the whole program needs to be prepared to take an older version and convert on the fly if needed

11:28 stuarthalloway: noidi: but what about multiple processes, in multiple languages

11:28 I would rather get data from your program as json and convert it to a shape I want

11:28 than have your provide import/export code in my language

11:28 noidi: ah, now I see your point

11:30 which implies that instead of OO API's, I should look at how data-oriented APIs like REST APIs work

11:30 patrkris: how would I go about setting a property for the JVM when invoking lein? Specifically, I need to use the -D switch for java to set UTF8 encoding

11:31 noidi: stuarthalloway, thanks for the great idea -- now I have to go cook dinner, but after that I'll read a bit about web service architecture, maybe that'll lead me to the path to enlightenment :)

11:33 stuarthalloway: noidi: please it up if you find it :-)

11:33 noidi: I'm starting to sound like scratched record, but I think Clojure would really benefit from a resource like http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

11:33 stuarthalloway: ...please [write] it up ...

11:33 dnolen: patrkris: the lein shell script looks for a shell environment variable JAVA_OPTS

11:34 patrkris: dnolen: thanks!

11:34 noidi: stuarthalloway, hehe, I will :)

11:34 stuarthalloway: noidi: we are slowly convincing Uncle Bob to love clojure, maybe he'll do it

11:49 chouser: hm... I want something like a multimethod, but the bodies need to be macro expansions. ...but dispatch has to happen at runtime.

11:53 hiredman: why not a multimethod?

11:54 fogus: chouser: Can you instead use multimethods as your macro aux functions?

11:56 chouser: yes, and I think that will be sufficient, but I think it will defeat potential call-site caching

11:57 (defmethod xget* "foo" [x] (:foo x)) (defmacro xget [x] `(xget* ~x))

11:58 if the value of x there can be of different types, the call-site caching in xget* would be defeated

12:00 fogus: Seems like a natural fit for mms... that's too bad.

12:00 chouser: while if the macro were (defmacro xget [x] `(condp = (xtype ~x) "foo" (:foo ~x) ...)), I would get keep call-site caching but would lose multimethod openness

12:01 which suggests (defmethod xget* "foo" [x] `(foo: ~x)) ...but then how do I define xget? I guess I could build a condp from (methods xget*)

12:08 ordnungswidrig: re

13:07 headius: technomancy: twbray mentioned ohai in his google blog post

13:09 technomancy: headius: yeah, I'm excited to see what he does there

13:09 definitely a good thing for polyglot android!

13:09 headius: he seems pretty excited about duby lately

13:09 and we've added a lot since ohai

13:10 technomancy: yeah, I've been meaning to dive back in, but I'm still way behind on pull requests for swank-clojure and leiningen

13:21 seths: geez, Rich is giving a really great introduction to the reader

13:23 icey: haha reading through clojure core is "an interesting journey"

13:30 remleduff: seths: What were you referring to when you said Rich is giving a really great introduction to the reader?

13:30 nteon: seths: where is that happening?

13:30 heh

13:32 technomancy: http://pragmaticstudio.com/clojure <= probably here

13:32 icey: technomancy: aye that's it

13:35 remleduff: Ah yes, I was just short the 1000 bucks to attend that ;)

13:42 seths: yes, it's only been a few hours but I already highly, highly recommend this course

13:44 nteon: seths: did you have experience with clojure before this?

13:46 seths: nteon: yes, many months of playing with it. nothing really serious.

13:46 but that has made this training much more immediately absorbable

13:46 nteon: seths: cool. just wondering

13:47 icey: nteon: they started with a pretty basic level of discussion and then ramped up the detail fairly quickly

13:47 fogus: seths: Are there many questions, or mostly lecturing?

13:48 seths: fogus: @goodmike said it well that it was like the blip.tv videos, turbocharged

13:48 questions have been sporadic but at a variety of levels

13:49 fogus: seths & icey: Are there a high ratio of blown-minds?

13:50 chouser: a lot of rhickey's blip.tv stuff is getting a bit dated now

13:50 seths: fogus: not sure, the room doesn't feel uncomfortable

13:50 newbies are asking some questions, and I see people around me tinkering with the repl

13:51 fogus: but the labs have started and I need to get busy :-)

13:51 technomancy: don't forget your lab coat

13:51 fogus: seths: enjoy!

13:53 nteon: goggles are important too

14:13 Licenser: geetings my lispy friends!

14:14 esj: salute

14:19 vy: For those about to lisp, I salute you!

14:21 Licenser: :)

14:26 seths: ,10r3

14:26 clojurebot: 3

14:26 seths: zomg

14:26 ,10r16

14:26 clojurebot: 16

14:26 chouser: heh

14:30 seths: ,#(%&)

14:30 clojurebot: #<sandbox$eval__6295$fn__6297 sandbox$eval__6295$fn__6297@25951f>

14:31 chouser: ,36rXYZ

14:31 clojurebot: 44027

14:33 fogus: ,(#(apply (first %&) (rest %&)) + 1 2 3 4 5)

14:33 clojurebot: 15

14:33 hiredman: :(

14:33 chouser: whoa. you just wrote a clojure interpreter

14:33 hiredman: apply using apply

14:34 fogus: You can write a Clojure interpreter in exactly 1 line of code

14:34 :p

14:34 seths: eval

14:35 rhickey_: %& ?

14:35 seths: I started the nonsense with

14:35 ,#(%&)

14:35 clojurebot: #<sandbox$eval__6309$fn__6311 sandbox$eval__6309$fn__6311@4bfba>

14:35 chouser: I guess to be a useful claim, you'd have to specify which parts of clojure you're not allowed to use in your clojure interpreter

14:36 seths: and then fogus said:

14:36 ,(#(apply (first %&) (rest %&)) + 1 2 3 4 5)

14:36 clojurebot: 15

14:36 fogus: General IRC silliness

14:36 rhickey_: fun

14:37 brian__: Hi, does anyone know if/how stuart sierra's hadoop-clojure integrates with apache mahout? Thanks

14:52 chouser: ,(reify clojure.lang.IMeta (meta [] {:my :meta}))

14:52 clojurebot: java.lang.Exception: Unable to resolve symbol: reify in this context

14:52 chouser: Hm, I get: java.lang.ClassFormatError: Duplicate method name&signature in class file user$eval$reify__738

14:57 hiredman: chouser: maybe reify self mixes in IObj?

14:58 or, I should say, an implementation of same

14:58 hmm

15:00 chouser: yeah, (.meta (reify)) doesn't crash

15:01 hiredman: huh

15:02 rads: I put (with-ns 'leiningen.snapshot (defn snapshot [project & args] ...)) in my project.clj, but when I try to run lein snapshot I get a no namespace found error

15:02 am I doing it wrong?

15:02 chouser: with-ns is a little scary

15:03 hiredman: rads: use create-ns

15:03 chouser: (supers (reify)) just says Object though

15:04 chouser: oh, my. (show (class (reify))) shows a lot though

15:04 rads: is there a better way to create leiningen tasks?

15:05 chouser: (.meta (.withMeta (reify) {:no :way!}))

15:05 technomancy: rads: I think it's actually best not to use with-ns but just to use ns

15:06 rads: technomancy: so I'd put each task in a separate file in src/leiningen?

15:07 technomancy: rads: no, you can use ns inline in project.clj. it's a bit unorthodox, but it works for short tasks. for longer more involved tasks you should use a separate file.

15:07 if you do it in project.clj just be sure to switch back to the user ns afterwards or it won't be able to find defproject

15:07 hiredman: technomancy: I would use in-ns over the ns macro in that case

15:08 chouser: but with in-ns you don't get any of clojure.core

15:08 technomancy: yeah, in-ns means you have to refer manually

15:15 rads: hmm, the classpath isn't set in project.clj, but I have to use some functions from my project in my task. I tried moving the task to a separate file, but leiningen doesn't seem to recognize the task

15:16 chouser: bleh. dep management may be worse now than before.

15:17 I had clojure, contrib, and ring all integrated into a non-java-centric build system, with ant being to only extra requirement. Now it looks like I need ant, lein, and maven.

15:19 drewr: chouser: I had the same reaction

15:20 chouser: does lein work on Mac?

15:20 drewr: does for me

15:20 rads: yeah, I'm on a mac too

15:20 chouser: ok. hopefully it will for our Mac-based devs.

15:20 * chouser sighs and slogs on in.

15:22 danlarkin: the sooner you embrace the separate environments for each project the better off you'll be :)

15:22 drewr: danlarkin: already had that :-)

15:23 but my team moved to lein and I submitted

15:24 rads: any idea on how to use my project code in lein tasks? it seems the classpath isn't set within the project.clj file

15:24 danlarkin: I don't indent to flame, but I just don't see what the disadvantages are to everyone having a sane build system

15:24 technomancy: chouser: why are you building those deps yourself? can't you just get stuff from build.clojure.org/clojars?

15:25 danlarkin: s/indent/intend

15:25 we can see my mind's still on code :)

15:27 technomancy: oh, except you're probably working on changes to clojure itself that you want to have available without making public first, right

15:27 edge case! =)

15:28 danlarkin: symlinks might be sufficient for that case

15:29 technomancy: you'd still need ant installed

15:35 remleduff: technomancy: Do you think it would be feasible to make the shell script/bat file simpler by taking a strategy of "just try to get to clojure ASAP and do all the logic in clojure?"

15:44 chouser: hm... no, I don't need a custom-patched clojure, just something with refiy, defprotocol, etc.

15:45 reify

15:45 hiredman: chouser: lein can grab that from build.clojure.org

15:45 chouser: can I name specific non-release versions of clojure or contrib?

15:46 hiredman: hmmm

15:46 arohner: chouser: I've started building snapshots, and set their version number to the git SHA1

15:47 chouser: actually, I may not need that.

15:47 hiredman: I don't know

15:47 chouser: arohner: on build.clojure.org?

15:47 arohner: chouser: I upload them to clojars

15:47 chouser: ah

15:47 drewr: arohner: I do something similar, although I shorten the digest and put the timestamp first for sortability

15:47 arohner: [org.clojars.arohner/compojure "40083894d100d89347dad9748110fe06b9aab323"]

15:47 cemerick: chouser: yes, you can fix a maven dependency version to a particular snapshot

15:49 drewr: my zsh fn to do that: http://gist.github.com/333247

16:28 chouser: can I configure lein to use a different local repository directory?

16:29 Chousuke: I think there's an environment variable or something

16:30 chouser: Hm. $HOME :-/

16:30 Chousuke: ... or you get to write an XML configuration file ;P

16:31 http://maven.apache.org/settings.html

16:31 chouser: it still installs itself in to $HOME/.m2/...

16:32 technomancy: remleduff: I have tried to take that strategy, but things accumulate over time, and it's not always obvious _why_ some stuff is implemented in .sh. If you've got some specific ideas of things that could be moved that'd be great.

16:32 remleduff: I'm most curious about the repl task, would it work as a plugin using "eval-in-project"?

16:33 chouser: can I tell lein to operate on a project in a different directory?

16:33 or must I cd there first?

16:34 technomancy: remleduff: there are issues with *in* and *out* not getting bound correctly from an eval-in-project call. it's probably possible, but I haven't had the time to investigate.

16:34 remleduff: if you have a chance to look at the problem that would be awesome.

16:35 chouser: currently you need to cd there first, but we could add a way of specifying a non-cwd project root

16:35 chouser: I can probably work around it

16:39 remleduff: No promises, but I'll try to take a look :)

16:40 technomancy: remleduff: I think that might be more of a messy ant API issue than anything clojure-specific unfortunately

16:40 chouser: "lein deps" in ring seems to fetch a lot of SNAPSHOT libs. I assume that if others run this same command at a later date, they may get different versions of these libs?

16:41 technomancy: yeah, it's generally discouraged to add snapshot deps to stable releases unless you absolutely must

16:41 that's one of the things stuart H complained about; maintainers not pushing out actual releases often enough

16:41 * technomancy is guilty

16:41 technomancy: chouser: you can lock to specific versions though

16:42 chouser: ok, it's not as many as I thought. I saw org.clojure:clojure:1.1.0-master-SNAPSHOT go by, but it looks like 1.1.0 is explicitly named in the project.clj

17:04 LauJensen: Evening gents

17:05 dakrone: Evenin' Lau

17:17 neotyk: evening Lau

18:33 crowbar7: Good evening

18:56 dysinger: hey rberger :) I heard you guys got funded - congrats

19:01 rhickey: I need an invoice for feb - did you send me one ? I don't have it.

19:13 crowbar7: Who got funded?

19:13 dysinger: Don't you work for a company that uses clojure?

19:53 etate: ello people

19:57 Fossi: hi etate

19:57 crowbar7: Hello

23:04 rfg: Anyone played with clojure + jogl on Windows (7)? I'm getting inconsistent results.

23:06 crowbar7: nope

23:06 i'm a bag of help

23:07 rfg: This is quite frustrating :)

23:37 crowbar7: this place is sure a ghost town right now.

23:38 rfg: One problem is that when I launch my JOGL window from the repl it's fine initially, but if I close that window and relaunch from repl the rendering is all messed up. Anyone care to guess at any possible reasons why?

23:38 dnolen: crowbar7: heh it often gets like that. other times a deluge.

23:38 crowbar7: yeah, so it seems.

23:39 dnolen: rfg: have you looked at Penumbra, might save yourself some headaches.

23:39 haven't tried it on Windows, but it works great on Ubuntu and OS X

23:39 crowbar7: I mean it's not some social channel, but some life is nice here and there.

23:41 rfg: dnolen, the latest versions of penumbra use LWJGL instead of JOGL. LWJGL has some issues that mean I'm leaning towards JOGL. I'll see if I can grab an old JOGL version of penumbra from github.

23:41 replaca_: dnolen: I like the enlive tutorial! Wish I'd had it when I was writing autodoc :-)

23:43 dnolen: replaca_: thanks! Happy at response it's been getting. cgrand's Enlive has a crazy punch for only 800 LOC!

23:43 rfg: what issues do you have with LWJGL over JOGL?

23:44 technomancy: dnolen: wow, only 800 LOC? nice.

23:45 note to self: write a loc task plugin for lein

23:45 rfg: Well, and this may be due purely to my ignorance, I can't seem to set arbitrary sized windows, nor can I get a resizable window.

23:46 technomancy: (or note to anyone who's listening and is looking for a simple project that would be useful to contribute to)

23:46 dnolen: rfg: definitely in there, just a problem of documentation

23:47 rfg: you should look at this, http://github.com/swannodette/clj-nehe. As far a resizeable windows you should bring that up on the Penumbra ML, I haven't looked into that myself. but it must be there since there's "reshape".

23:48 rfg: dnolen,

23:48 Two seconds.

23:53 crowbar7: So, as soon as I did (doto (Thread. #(func arg)) (.start)) the first time in Clojure I pretty much became super fanboy because it made threading painless.

23:53 arohner: crowbar7: it gets even easier

23:54 crowbar7: arohner: as I found

23:54 hiredman: pffft

23:54 just use future

23:54 rfg: dnolen, any idea if you can mix lwjgl and swing/awt components?

23:55 technomancy: _atooooooooooooooooo!

23:55 where are you?

23:55 crowbar7: I really hope this language takes off because I could program in this for the rest of my life at a job at this point.

23:56 dnolen: rfg: haven't gotten that far. but that's come up recently on the Penumbra ML, the overtone guys want to use it.

23:56 technomancy: crowbar7: the rest of your life is a long time (hopefully)... don't go overboard. =)

23:56 crowbar7: technomancy: good point

23:58 jobs seem to be quite scarce in the clojure depaprtment.

23:58 rfg: dnolen, cheers, found it.

23:58 crowbar7: department*

23:58 rfg: crowbar7, just get a java job and don't tell them what you're really using. They'll be amazed at your productivity. :)

23:59 lancepantz: crowbar7: i used to think the same about ruby re: rest of life thing

23:59 now it annoys the hell out of me

23:59 since i started doing clojure

23:59 dnolen: crowbar7: tho perhaps better than it was for Ruby in oh, I dunno 1998 ;)

23:59 rfg: np

Logging service provided by n01se.net