#clojure log - Jun 28 2010

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

0:00 somnium: is this just wrong?

0:00 http://paste.pocoo.org/show/230792/

0:03 lots and lots of one-line (def x y) started to feel so noisy

0:04 tomoj: you are hereby excommunicated from the church of the holy parenthesis

0:04 somnium: O_o

0:04 thats what I was afeard of

0:07 hmm, I guess it shouldnt be too hard to parse it back into (def ...) expressions so I dont have to subject my paren-brothers to this private heresy in any shared code

0:08 tomoj: hehe

1:04 arrummzen: I notice a lot of functions in the clojure library seem to support named parameters. How do I use these in my clojure functions?

1:06 (by named I mean optional named parameters).

1:06 tomoj: what's an example? you mean in contrib or core?

1:06 arrummzen: For example, with use you can give :only

1:07 somnium: arrummzen: usually its (fn [x y & options] (let [{:keys [this that]} (apply hash-map options)] ...))

1:07 arrummzen: if youre on 1.2 you can do (fn [x y & {:keys [this that]}] ...) now too

1:08 Im still scared of 1.2 though

1:08 arrummzen: Hmm... but isn't that just passing in a map of options? with use you aren't giving a dictionary...

1:09 somnium: arrumzen youre passing in an unrolled alist I guess

1:09 tomoj: was that release date for 1.2 for real?

1:09 somnium: theres a release date?

1:10 tomoj: I saw it on planet clojure

1:10 it was somewhat speculative, not official

1:10 http://coldbox.assembla.com/spaces/clojure/milestones/149827-release-1-2

1:10 somnium: I was experimenting with in november last year, and it was 'right around the corner' :/

1:10 tomoj: the milestone is set for 3 days from now

1:10 somnium: ooh

1:10 arrummzen: with, for example "(use '[namespace :only (function)])" you it seems :only is somehow grouping to the list after it but I don't understand how. I'd understand something like (use '[namespace {:only (function)])

1:10 somnium: I really want to switch, but it broke once and 1.1 is plenty powerful

1:10 tomoj: and the burndown chart is lookin good

1:12 somnium: arrummzen: use probably implements a mini-parser, but there are many examples of the [& key-vals] style

1:12 defmulti, for example

1:14 clojurebot: ping

1:14 clojurebot: PONG!

1:16 somnium: ,(let [[n & options] '[namespace :only [functions]]] (assoc (apply hash-map options) :name n))

1:16 clojurebot: {:only [functions], :name namespace}

2:08 Dranik: hi all!

2:10 I do image processing using really large matricies, changing their cells in some quirky algorithms. I need multithreaading and FP, so I'd like to try clojure

2:10 but the data in clojure is immutable. How can i process those matricies avoid memory leak?

2:13 tomoj: you won't be leaking memory unless you hang on to every version

2:13 but you probably don't want to use immutable data structures for that anyway

2:14 incanter has some matrix stuff which might be helpful

2:14 though, hmm

2:14 Dranik: tomoj, so, the idea than is to use pure java collections?

2:14 tomoj: I haven't done matrix stuff yet so I'm not sure exactly

2:15 but I think it's very likely that vectors of vectors will be too slow

2:15 Dranik: yep, and also it will eat the memory badly

2:15 tomoj: are you keeping every version?

2:15 Dranik: no

2:15 tomoj: then your memory use will be bounded

2:16 Dranik: I just need a binary matrix which I process cell by cell changing the cell's value from 0 to 1 and vice versa

2:17 but as any function over a collection returns a new collection it will contain at least hashes of the cells

2:17 that's why I guess the size of the outcome will be the same as the size of the source matrix

2:18 Or I've got it wrong?

2:18 (I didn't dig into the clojre sources)

2:19 tomoj: the size of the outcome will be the same as the size of the source matrix, yes

2:19 but they share structure

2:19 and old versions will be GC'd

2:19 Dranik: how about the old version? will it be saved?

2:20 OK, then, just have a look

2:20 I've got a matrix 1Gb size. I change just one cell. How much memory it will cost?

2:21 tomoj: I couldn't tell you

2:21 less than 1Gb

2:21 Dranik: :-)

2:21 tomoj: but you're right, I hadn't been thinking in such large terms

2:21 I expect there are pathological cases in which it could cost quite a lot of memory

2:22 but I'm not sure

2:22 Dranik: Im a newbie here. Is Rich around or someone from core development?

2:22 tomoj: it looks like incanter's matrix stuff is based on cern.colt.matrix.tdouble.impl.DenseColDoubleMatrix2D

2:22 so not helpful

2:26 what are the dimensions like?

2:29 the depth of the tree behind the vector is O(log32 n)

2:30 so for an NxN matrix you need to allocate 2*log32(N) new 32-element arrays on average to change one element

2:31 so for a million by million element matrix that's like 8 32-element arrays

2:31 not much at all, I think

2:35 Dranik: I can hardly get it

2:35 how the new vector will share the old vector's data if it will not contain the links?

2:35 and one link will have the cost

2:36 tomoj: vectors are trees of arrays

2:36 Dranik: probably 8 bytes

2:36 tomoj: so you only have to replace from the leaf changed up to the root

2:36 the other arrays in the tree will never change so you can just copy pointers to them into the new arrays you make

2:37 Dranik: did I get it correctly, that one array in the vector is 32 elements size?

2:37 I mean one array in the tree?

2:37 tomoj: right

2:38 Dranik: Aha! I see....

2:38 tomoj: http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation/

2:39 Dranik: Yeah, it's very effective solution for vectors.

2:39 tomoj: but not super fast

2:40 maybe using transients would be fast enough for you, I dunno

2:40 Dranik: And when changing a bunch of elements at a time, it will cost much less memory than changing one cell at a time.

2:40 what do you mean by transients?

2:40 tomoj: http://clojure.org/transients

2:40 Dranik: (thanks, btw, for your explanations about vectors. it was very helpful!)

2:41 tomoj: safe mutable data structures

2:41 you could bundle up a bunch of changes (as you said) and do them all to a transient version before converting it back into a persistent vector

2:42 Dranik: thanks a lot! it's clear now what to grok!

2:42 tomoj: and the conversion back and forth is O(1)

2:42 but even transients may be too slow, I dunno...

2:42 what would you put in your vectors? booleans? :(

2:42 Dranik: yeah, they probably will be. Java is rather slow

2:42 I'd like to put jus one byte in a cell

2:44 sometimes it is much cheaper to use slow solutions at wait for a couple of seconds than to spend weeks on fast solutions which will produce the result immediately

2:44 tomoj: yep, working with persistent and transient vectors would be pretty pleasant

2:45 and you get the multithreading benefits from clojure

2:45 Dranik: that is my case. The basic image processing I make on CUDA -- it is extreamely mega super-duper fast!

2:45 and some processing I do on client inside the java gui

2:45 that is why I'd like to have multithreading

2:46 java's multithreading is ugly! brrr....

2:53 tgk: Does anybody know of a function like spit that expects a lazy seq instead? Or something similar to that.

2:53 My problem is that I'm building a huge string before outputting it, and that's eating all my mem...

2:55 Oh! Just found write-lines, sorry for the inconvenice

2:58 Dranik: where may I find the development version of clojure? 1.2 probably? I looked for it in git but found only 1.1

3:00 tgk: It should be the master branch

3:01 You probably want something precompiled though.

3:01 Dranik: http://github.com/richhickey/clojure.git -- is it?

3:01 tgk: Yup, should be the right one

3:02 Dranik: tgk, that is no problem, I just want to look at the new sources.

3:02 thx!

3:07 interesting... clojure 1.1 builds also 1.2 snapshot...

3:08 tomoj: huh?

3:09 Dranik: i've got the stable branch and it has built clojure.jar and clojure-1.2.0-master-SNAPSHOT.jar

3:10 tomoj: I don't see a "stable" branch

3:10 you mean 1.1.x?

3:10 Dranik: right

3:11 or it is not?

3:14 tomoj: the 1.1.x branch builds clojure-1.1.0.jar for me

3:16 Dranik: I used the http://github.com/richhickey/clojure.git, and it has built also 1.2... weird...

3:25 LuminousMonkey: Anyone know of a better, more elegant way of doing something like this? http://pastebin.com/f5iw0q9U Or if there's something that does it already that I missed?

3:27 tomoj: ,(dorun (map #(when (and %1 %2) (println %1 %2)) [1 2 3] [4 5 6]))

3:27 clojurebot: 1 4 2 5 3 6

3:28 LuminousMonkey: Awesome, thanks!

3:28 How did I miss something like that? :/

3:38 Cool, don't even need the #(when....) in there for my purposes.

3:39 tomoj: oh, I misunderstood the purpose of the when in your paste

3:40 s/when/if/

3:40 sexpbot: oh, I misunderstood the purpose of the if in your paste

3:41 LuminousMonkey: I feel a little stupid now, was looking for something to do that, and I didn't realise that's exactly what map does. :)

3:41 But, good to learn.

3:42 tomoj: just don't do this

3:43 ,(dorun (take 3 (map println (range 20))))

3:43 clojurebot: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

3:43 tomoj: oh, just realized the anonymous function is superfluous as well..

3:43 ,(dorun (map println [1 2 3] [4 5 6]))

3:43 clojurebot: 1 4 2 5 3 6

3:45 LuminousMonkey: ,(dorun (map println [1 2 3 4 5] (cycle [6 7])))

3:45 clojurebot: 1 6 2 7 3 6 4 7 5 6

3:46 LuminousMonkey: So if I wanted to replace println with my own function, I would just need to make sure it will take two args?

3:47 tomoj: yep

3:47 LuminousMonkey: Cool

3:47 tomoj: the function needs to take as many args as seq arguments you pass to map

3:48 LuminousMonkey: Brilliant, that gets rid of a few more lines of code, thanks. :)

3:54 LauJensen: Morning gentlemen

3:54 raek: gomorron

3:54 LuminousMonkey: Gentlement? I've been promoted.

3:55 Despite my typing.

3:55 LauJensen: raek: 'go moron'??? Ah the swedish language is so poetic :)

3:58 raek: heh, guess i'll have to be more careful when saying that in english speaking communities

4:26 rrc7cz: I'm curious: when was the last time you used the state monad, and what did you use it for?

4:31 Fossi: rrc7cz: ist that a haskell question or do you refer to clj-monad or such?

4:32 rrc7cz: Fossi: clojure.contrib.monads, but I don't care about even about keeping it specific to Clojure, I would be happy to know in general

4:47 LauJensen: rrc7cz: I see no purpose for monads in Clojure, as Clojure has a uniform and effective way to manage state through reference types

4:49 tomoj: no purpose for the state monad, then, you mean?

4:50 LauJensen: tomoj: There shouldnt be. We have a state monad in ClojureQL at present, but Im working on trying to get it out :)

4:57 rrc7cz: LauJensen: the only case I could think of where the state monad might be useful in Clojure is to build larger components

4:58 then again maybe not, because you just wrap them in a transaction anyway

4:59 LauJensen: To me, monads have always represented a way of hiding or wrapping state, to maintain a purely functional setting. This task is obsolete with Clojures approach to state

4:59 rrc7cz: LauJensen: what about the idea of "global, implicit" state versus local, explicit state?

5:00 LauJensen: What about it?

5:00 rrc7cz: I mean a ref makes concurrency safe, but you can still have this global, invisible state being modified from 100 places

5:00 with a state monad you're forced to handle the state explicitly on a more local level

5:00 does that make sense?

5:01 for example, I could have a ref sitting in a namespace being modified from 100 places. While safe, it's still the sort of spaghetti you get from global state. Maybe since the state monad forces you to deal with state explicitly and locally, you can prevent that sort of thing

5:02 LauJensen: Clojure revolves around pure functions (ie no pushing global state) and immutable data. I dont see any libs in Clojure land containing global state, which would benefit from monad semantics.

5:02 For the instances where you need to have some kind of state - Refs are also explicit and can be both local or global. In either case, spaghetti comes from incidental complexity, and I just dont see references adding any of that

5:04 rrc7cz: what do you mean by refs as local? you don't mean a ref within a fn, right? You mean local to a specific namespace?

5:04 somnium: Im using them (monads) left and right at the moment, state+maybe for parsing and cont a littile for making cps stype code more readable

5:05 LauJensen: rrc7cz: yes

5:05 somnium: Interesting - Got some code up somewhere to see ?

5:05 somnium: sure, several buffers to choose from atm :D

5:06 rrc7cz: somnium: sorry, what is cps?

5:06 somnium: continuation-passing-style

5:06 LauJensen: somnium: M-x gist-buffer is your new best friend :)

5:07 somnium: hmm, is it on elpa?

5:07 rrc7cz: somnium: I've only ever seen that in web frameworks (like Seaside). What else are you using that for? What is easier with cps?

5:08 LauJensen: somnium: no, I found gist.el on github somewhere

5:10 somnium: I mostly use gist-fetch, gist-region, gist-region-private

5:10 somnium: rrc7cz: compilers

5:11 tracking tail positions and embedding contexts, ah, closures

5:14 LauJensen: okay, so Im not really a fan of the c.c.monads implementation so I write a lib I can use like

5:14 http://gist.github.com/455612

5:14 (so the usage will make sense)

5:16 LauJensen: k

5:16 rrc7cz: somnium: i understand bind/return/zero/plus from Konrad's tutorials, but name/do/modules.. guess I gotta open up one of the haskell monad tutorials?

5:17 somnium: btw, I like the syntax and naming changes; they match haskell a lot better than c.c.monad

5:17 somnium: :do is the name of the do-monad macro, :modules is kind of a hack, it loads evals monad functions that depend on vars named 'bind 'return etc

5:18 IMHO its preferable to the with-monad, do-monad, and symbol-macros etc. in c.c.

5:18 rrc7cz: somnium: so modules is like with-modules, allowing you to ref existing monads

5:18 okay

5:18 LauJensen: somnium: And no way for you to model with using only Clojure data structures?

5:19 somnium: LauJensen: its just a method of composing functions thats sometimes useful

5:20 (Ive never been tempted to write an IO monad in clojure, for example)

5:20 ;)

5:20 LauJensen: or did you mean the modules?

5:21 we cant really gen namespaces programmatically so I resorted to eval

5:21 LauJensen: The whole thing. You're abstracting away your relationship to state (or the accumulation thereof) in your program, and so Im wondering if it couldnt be expressed in a simpler way which didnt relate on many macros

5:22 somnium: sure, but Ive found the resulting code can be really clean

5:22 LauJensen: thus the appeal of macros

5:22 :)

5:22 somnium: plus they never suffer from trouble with laziness, since the order of evaluation is fixed

5:23 rrc7cz: somnium: why would there be a laziness problem when clj isn't lazy?

5:23 somnium: if you mix lazy-seq and *binding* you can suffer

5:24 http://gist.github.com/455628

5:24 bartj: my initial attempt at removing stop-words - http://pastebin.org/363105

5:24 I do not want to use fancy stuff like Lucene or any libraries

5:25 somnium: random snippet, that files kinda big but thats typical of my usage I guess

5:25 bartj: comments please ?

5:27 tomoj: (remove stop-words-map (re-seq #"[^\s]+" s))

5:28 though..

5:28 rrc7cz: bartj: also consider something like: (apply str (interpose " "(filter (complement stop-words) (.split "the quick brown fox" " "))))

5:29 bartj: which works if you switch stop-words to a set, which makes sense anyway since you don't care about testing for inclusion

5:29 tomoj: https://gist.github.com/7fbff0775cf072e2efac

5:29 LauJensen: rrc7cz: that split doesnt work exactly like his regex, and (apply str (interpose )) is clojure.string/join

5:30 rrc7cz: LauJensen: you can pass split() his regex instead of the space

5:32 bartj: tomoj: your version definitely is more terse

5:32 LauJensen: and effecient, and idiomatic

5:34 The first version allocates a new seq for both re-seq, map and remove, tomojs has 2 thirds of the allocation, but ofc I dont know if this has to be performant in any way

5:36 somnium: LauJensen: you could say reduce is kind of like a poor man's state monad and its perfectly idiomatic in clojure

5:37 bartj: understanding tomoj's implementation:

5:37 LauJensen: or a rich mans, depending on how you look at it :)

5:37 somnium: I guess its more like composing a bunch of (partial reduce f ...)

5:37 bartj: , (#{"the" "a"} '("the" "blah"))

5:37 clojurebot: nil

5:38 tomoj: remove calls the function on elements of the seq, not the seq itself

5:38 bartj: when a list is passed to a map it returns the keys

5:39 LauJensen: bartj: when a element (like in remove) is passed to a set, it will return either an element or nil. Nil will cause remove to keep the item

5:39 ,(map #{\a \b} "abcdefg")

5:39 clojurebot: (\a \b nil nil nil nil nil)

5:41 bartj: LauJensen: ok, thanks!

5:41 rrc7cz: somnium: your parser looks just like Parsec. Are you porting it to Clojure?

5:42 somnium: rrc7cz: I actually dont know parsec that well

5:43 but similar I think, it can do pegs already

5:43 only a week old though, not qutie baked

5:43 http://gist.github.com/455646

5:43 LauJensen: ^^ I challenge you to offer a more appropriate abstraction for this case

5:44 LauJensen: I like challenges - are we putting some money on it? :)

5:44 somnium: what's the going rate for a cup of tea in Denmark?

5:45 LauJensen: I think right around 2kr

5:45 tomoj: somnium: better than fnparse?

5:46 LauJensen: somnium: I'd still prefer it represented in some kind of meaningful datastructure, isntead of abstraction by macros

5:46 somnium: tomoj: I dont know if its better, it started as some unit tests for my monad lib and became useful rapidly

5:47 tomoj: ah

5:47 bartj: , (dorun (#{"the"} '("the" "blah")))

5:47 clojurebot: nil

5:47 bartj: why can't expect a "blah" in the output ?

5:47 LauJensen: bartj: AFAIK sets accept arguments as elements, not seqs

5:48 somnium: LauJensen: youre not actually proposing we do ((fn [x] (+ x x)) 42) instead of (let [x 42] (+ x x)) are you :P

5:48 LauJensen: somnium: ofc not

5:48 bartj: put a map there instead of dorun

5:48 that will pass _each element_ individually as the argument

5:49 bartj: , (map #(#{"the"} %) '("the" "blah"))

5:49 clojurebot: ("the" nil)

5:49 bartj: LauJensen: thanks again!

5:50 LauJensen: ,(->> (map #{"the"} #{"the" "blah"}) (filter indentity))

5:50 clojurebot: java.lang.Exception: Unable to resolve symbol: indentity in this context

5:50 LauJensen: ,(->> (map #{"the"} #{"the" "blah"}) (filter identity))

5:50 clojurebot: ("the")

5:51 LauJensen: bartj: the anonymous #(set %) notation was redundant, as sets really are functions of their arguments

5:51 rrc7cz: LauJensen: why wouldn't you just use set/intersection?

5:52 LauJensen: rrc7cz: because I dont think he's using sets for the input

5:52 rrc7cz: aha

5:53 bartj: just as maps are functions of their keys ?

5:53 LauJensen: exactly

5:55 and vectors of their indices

5:56 ,([1 2 3] 1)

5:56 clojurebot: 2

5:56 bartj: LauJensen: thank you very very much

5:56 LauJensen: bartj: np, thats what we're here for :)

5:56 bartj: which is why the stop-words-map wasn't necessary in the first place :)

5:57 LauJensen: bartj: yes. Interestingly, a hash-map is actually using the same lowlevel implementation as a set. The set is just different in that all keys equal their values. (zipmap vals vals) is repeated what the compiler is doing, just like #(set %) is doing what the compiler is doing

6:00 bartj: LauJensen: thanks again for the explanation

6:01 LauJensen: np

6:05 somnium: Im wondering, what exactly is going on in anf and return ?

6:05 rrc7cz: return = m-result, no?

6:06 but "return" is haskell

6:06 somnium: LauJensen: actually the interface of run-cps is slightly different, so its not really one to one, but its one partial application away

6:08 LauJensen: There are too many unknowns for me to offer an alternative. But generally, I'm more interested in data designs like [:a :< (fn [] ..)] than (macro a < (fn []))

6:08 somnium: LauJensen: but its not a macro, the macro is just syntax sugar, you can ALWAYS apply a monad

6:09 sometimes the shorter form is even easier to read

6:25 LauJensen: its an ugly one-liner, but that anf fn uses closures to add 'contexts where needed, so '(foo (bar (baz zonk) zam) zow) become

6:25 ,(letfn [(f [t k] (if (symbol? t) (k t) (g t (fn [x] [:let ['v x] (k 'v)])))) (g [ts k](if-let [[x & xs] (seq ts)] (f x (fn [y] (g xs (fn [ys] (k (cons y ys)))))) (k nil)))](f '(foo (bar (baz zonk) zam) zow) identity))

6:25 clojurebot: [:let [v (baz zonk)] [:let [v (bar v zam)] [:let [v (foo v zow)] v]]]

6:26 LauJensen: ah nice. note that Clojure now support locals with names longer than 2 chars :)

6:57 Bahman: Hi again all!

6:58 ttmrichter: Hi there!

6:58 ttmrichter: Hey-o.

9:22 jcromartie: everybody has seen this, right? http://gregslepak.posterous.com/clojures-n00b-attraction-problem

9:23 My only beef with the rant is that I think Clojure's documentation is pretty good.

9:32 I'd like to write a real ground-up getting started guide

9:32 for people that know absolutely nothing about the prerequisites

9:33 like the command line, Java, version control, build systems, editors, etc.

9:33 because there are so many points to get stuck on

9:35 zmila: jcromartie - do it, it will be very usefull

10:33 jcromartie: *phew* this is going to be exhaustive :)

10:33 is there a good place to post it aside from my blog or something?

10:34 fogus: jcromartie: Why not try to get it rolled into the Assembla wiki?

10:34 jcromartie: will do

10:36 Scriptor_sleepy: jcromartie: what level is it for? are you targeting those who have virtually no experience with running scripts from the command-line?

10:37 rhickey: aargh... maybe everyone should just leave their browser window in the infinite login loop until google groups recognizes the problem...

10:38 bhenry: rhickey: i searched for ants.clj and ended up in a redirecting loop with the first hit on google.

10:41 djpowell: hmm, I have a script containing a kind of dsl thing, and I want to load-file it in the context of a certain namespace

10:41 any way of doing that?

10:43 chouser: sure. load-file

10:44 djpowell: if I call load-file from a different namespace tho, it loads it into my namespace

10:44 i always want to load into the same namespace

10:44 chouser: perhaps (binding [*ns* (find-ns 'my.special.ns)] (load-file ...))

10:44 djpowell: but I didn't really want to put an ns decl at the top of the file

10:44 yeah - i was thinking something like that

10:45 is it ok to rebind *ns* then? is that how require works?

10:45 chouser: that's one of the things 'ns' and 'in-ns' do

10:45 actually, they re-set it

10:45 but yeah, I think it's ok to rebind *ns* for this kind of situation. I certainly do it.

10:46 jcromartie: Scriptor_sleepy: I'm targeting complete and utter n00bs... let me qualify that with a list of topics

10:48 virtual machines, executables and libraries, the JVM, classes, methods, UNIX shell concepts, shell programming, running Clojure, REPL concepts, Lisp concepts, Clojure code organization

10:49 Scriptor: nice, what does shell programming entail?

10:49 jcromartie: this is the "I dabbled in PHP once" to "beginning Clojure hacker" guide

10:49 just enough to understand how to write your own clj launcher shell script

10:50 commands, variables, arguments

10:51 Scriptor: if it's not too much, do you think you could cover automated testing as well?

10:51 jcromartie: I see my ability to understand how to use Clojure *at all* as a product of the sum of my experience over the last 20 years :P

10:52 err, 15 years or so I guess

10:53 from doing Logo in the 3rd grade to learning Unix commands on my dad's Wyse terminal at home... most people don't have it so easy

10:54 Scriptor: yea, it's interesting just how much knowledge you can take for granted

10:54 something like "open a shell, cd into the download directory" is obvious to some, but could be a complete mystery to others

10:55 jcromartie: a lot of my peers hate Java because of the classpath

10:55 they won't even go near Clojure just because of bad experiences in school

10:55 LauJensen: they?

10:56 jcromartie: 3 I can think of have said "no way, that's Java, I can't get Java to work"

10:56 eevar2: they should probably stick with php

10:56 jcromartie: PHP and C#, between them

10:56 LauJensen: Yea, they sound like ideal PHP experts :)

10:56 jcromartie: Please dont show them the mailing list :D

10:57 jcromartie: well it's not that they are dumb, it's just that early on in their experience the Java environment was not very friendly

10:57 LauJensen: I wonder when this 'how far can we dumb down Clojure' race will end. I mean eventually we'll hit a level where it just doesnt make sense anymore

10:57 jcromartie: and it still isn't, really

10:57 I don't think we need to dumb it down, it just needs to be unified

10:57 djpowell: uh? is anyone dumbing down clojure?

10:57 Scriptor: people just like to poke fun at PHP programmers

10:58 LauJensen: djpowell: The continous discussion these days, is 'how can we present Clojure in a less terrifying way', and the solution seems to be less of Emacs and more of Netbeans...

10:58 djpowell: hmm, all the hip ruby programmers don't use IDEs though do they?

10:58 LauJensen: djpowell: No I dont think so

10:58 jcromartie: they all use TextMate

10:59 Scriptor: one issue I have with that is it's geared for noobs who use IDEs

10:59 jcromartie: but Emacs has some good Ruby and Rails modes

10:59 LauJensen: And I think the Ruby crowd is actually very interested in Clojure - I would imagine the Ruby/Python transition is less painful than the one from PHP

10:59 eevar2: the hip ruby programmers should be able to cope with java / classpath issues, tho

10:59 jcromartie: once the classpath is explained, it's easy

11:00 LauJensen: you need to have the classpath explained?

11:00 jcromartie: it's rarely explained

11:00 it's usually just rote

11:00 in school, at least

11:00 LauJensen: ok

11:01 jcromartie: and most "enterprisey" Java programmers don't even use it explicitly

11:01 they let Eclipse manage it

11:01 but it's practically a one-sentence explanation

11:01 LauJensen: At the recent Conj Labs session in Brussels, I put some emphasis on showing off the areas where Emacs really boosts your productivity, I think quite a few people enjoyed that

11:03 Scriptor: were you talking about modes designed for productivity stuff, or about the editor itself?

11:03 rrc7cz: I think the idea isn't to hide Emacs, but let people discover it on their own time once they move forward. I can testify that clojure + emacs was a bigger bite to chew in the beginning; if you could focus on language first, then a new IDE second, it might make it easier to digest

11:03 LauJensen: Scriptor: The editor, as well as its integration with gist, git, slime etc

11:04 rrc7cz: Right, what Im saying is that its a non-issue. Some people try to tackle Emacs along side Clojure, and many of them are succesful. Others prefer Visual IDEs. I dont think that Emacs in itself should scare anybody, because alternatives exist

11:05 bhenry: rrc7cz i found it very helpful to take a week or two focusing specifically on emacs. then i moved on to learning clojure.

11:05 Scriptor: I'm trying to force myself to learn emacs, mainly because I feel deep-down it gives the optimal experience, even if others say it's not necessary

11:05 bhenry: i was certainly no emacs pro after that week or two, but it was helpful anyway.

11:05 jcromartie: Emacs is just useful period.

11:06 Clojure integration is just icing on the cake.

11:06 I use Emacs + clojure-mode + paredit without slime and it's still great.

11:06 LauJensen: sure - except paredit :)

11:06 nachtalp: imho wanting to learn clojure is a good reason to learn some emacs as well :)

11:06 LauJensen: The more I've experienced of paredit, the more I see it only as crutches

11:07 jcromartie: nuclear-powered robot crutches with lasers

11:07 more like it

11:07 LauJensen: hehe :)

11:07 somnium: I tried to learn common lisp and emacs at the same time but only the emacs took

11:08 probably for the best

11:08 LauJensen: I also picked up Emacs while learning SBCL - No regrets

11:09 jcromartie: I learned Emacs to write Lua just because someone convinced me I'd be more awesome for it

11:09 and here I am, surrounded by women and swimming in money

11:09 * eevar2 also did the sbcl+emacs thingy. i'm crying myself to sleep every night, hto

11:09 rrc7cz: I guess I'm just thinking about pace. Chapter 1 of any programming book isn't about the STM or monads, it's about hello world. These are powerful, productive tools, but they aren't even in the vocab of many potential users, why start with the whole shebang?

11:10 LauJensen: rrc7cz: yea, you can leave out monads entirely

11:10 eevar2: mixing up vim/emacs/os x keybindings tends to get messy

11:10 rrc7cz: Like, some users might want a more powerful IDE after 1 hour, while others after 1 week. The idea though is to lower that initial barrier

11:11 LauJensen: I think I need to do another Emacs / Dev Env tutorial/screencast

11:11 rrc7cz: I would love that

11:11 jcromartie: eevar: I'm happily using C-a C-e C-b C-f C-k C-y in OS X

11:11 rrc7cz: I use clojure-mode + slime to lein swank, but I still feel the env could be improved on

11:11 jcromartie: C-p C-n... also the kill ring works

11:11 in some apps

11:12 now to really mix it up, I use Visual Studio in VMWare on OS X

11:12 that's fun

11:12 :(

11:12 LauJensen: I use Arch + Awesome + Emacs (Magit, gist, Org-Mode, Clojure-mode, Swank) and a few other helpers. But its a very specific setup which is so fast it feels like its almost reading my mind

11:13 rrc7cz: my #1 pain point is starting the whole thing up. M-x shell, then lein swank, then slime-connect, etc. I know it can be scripted, but I haven't gotten that far

11:13 jcromartie: cool http://mobileorg.ncogni.to/

11:13 LauJensen: rrc7cz: use M-x swank-clojure-project

11:13 That automatically configures classpath, starts swank/slime etc

11:13 rrc7cz: I used to, but it's deprecated now, right?

11:13 LauJensen: Who cares, still the best thing out there

11:13 rrc7cz: how do you doodle?

11:15 right now I just have a "scratch" lein project I use to set up the classpath w/contrib and such, bring up a repl, etc. but it feels like overkill

11:18 LauJensen: rrc7cz: for doodling I have a very specific set up, where a bunch of projects that I use and contrib to, are setup - I manually fetch the branch of Clojure/contrib I want

11:18 then hit M-x slime

11:19 rrc7cz: LauJensen: I think a screencast explaining your setup would be pretty sweet

11:19 I looked at your IDE comparison back in the day, but I never saw one about your Emacs config

11:19 LauJensen: rrc7cz: I think most of my setup, in terms of .emacs is already in some blogpost on my site - What I would like to show is how this setup makes me extremely effective

11:20 http://bestinclass.dk/index.clj/2009/12/clojure-101-getting-clojure-slime-installed.html

11:20 I did that one, but its a little outdated

11:21 AWizzArd: LauJensen: this howto for Clojure 1.2 with newest Slime would be very intersting (:

11:21 LauJensen: Im also tempting to do some kind of handholding. But I firmly believe that if you're coming from C#, Python etc, and you cannot figure out Emacs, I might get you through that phase, but then you'll die when trying to grasp functional programming. I might be wrong

11:22 rrc7cz: I don't think it's about "figuring out" Emacs, but getting used to it. My problem is key bindings

11:22 I think anyone can figure out Emacs if they want to, but dumping the many years of motor memory in your fingers takes time

11:23 Scriptor: try going from vi to emacs

11:23 LauJensen: Scriptor: Only then will you know how Neo felt when he woke up outside of the Matrix

11:23 chouser: depressed?

11:23 grubby?

11:24 LauJensen: free

11:24 Scriptor: weak from no muscles?

11:24 chouser: oh, right.

11:24 rrc7cz: lol

11:24 LauJensen: But look - The vi guy woke up :)

11:24 chouser: I have great news. Vim now supports a special 'insert mode', which actually lets you edit code, and not just view it! Hooray! No more copy/paste

11:26 Well.. I mean, you probably still have to paste into your repl :(

11:26 chouser: you mock what you do not know

11:27 rrc7cz: something else bothers me: in the age of iPhone, UX, Web 2.0 UIs, there is this massive push to have computers fit the human, not the other way around. Hell, that's part of Lisp! Write what you want declaratively and let the computer figure out _how_ to actually do it. Then you have this editor that literally breaks your hands and forces you to memorize 2389023 keybindings... wrong track?

11:27 * somnium uses emacs almost exclusively but thinks vim is much better designed

11:28 LauJensen: rrc7cz: Its the ideal interface

11:28 rrc7cz: On LtU there was some research IDE some kid made with "Code Bubble", basically rethinking the whole IDE experience.. that seemed nice

11:28 LauJensen: define interface. You could argue a shell is the ideal interface to any computer, but it may not be the most user friendly

11:29 LauJensen: rrc7cz: What I mean is. Emacs is making me so productive, that Im not seeing much room for improvement anymore. Maybe its my imagination that failing, but maybe not

11:29 nachtalp: not all interfaces are equally friendly to any user :)

11:29 rrc7cz: LauJensen: think of a game where you have to navigate a maze. In this case the best interface is a graphical - rather than textual - one. Who says the best interface for code editing looks like Emacs? Maybe it hasn't even been thought up yet

11:29 somnium: LauJensen: it could be hubris

11:30 LauJensen: rrc7cz: True - And if something better comes along, Im switching

11:30 Scriptor: jcromartie: just thought of something, is your tutorial oriented around windows? most utter noobs are probably using that

11:30 LauJensen: Its not like chouser and kotarak havent tried teaching me Vi

11:30 Scriptor: In fact that might be the very definition of an 'utter noob' :)


11:30 * Hodapp hits LauJensen with chair

11:30 rrc7cz: :-D

11:30 somnium: :D

11:31 jcromartie: Scriptor: yes, it caters to Windows users

11:31 * Hodapp punches somnium

11:31 jcromartie: but not exclusively

11:31 LauJensen: War? Where?

11:31 jcromartie: we get into Cygwin, as a special note for Windows users, before going on to shell scripting

11:31 rrc7cz: jcromartie: you might want to briefly mention lein.bat in that case. I actually dev clojure at work on Windows and lein.bat has worked out better for me than lein.sh in mysis

11:32 Scriptor: git for windows comes with a shell, which is pretty handy by knocking out 2 birds with one stone

11:32 jcromartie: as an aside, I got a great old shell programming book from my dad called UNIX Shell Programming by Kochan which is a great treatment of the basics that lots of more advanced tuts either miss or just skip over

11:32 rrc7cz: Scriptor: that's exactly what I had problems with, but it's very possible I did something stupid. I just didn't spend much time on it

11:32 jcromartie: rrc7cz: good tip, thanks

11:33 yeah, Cygwin + git is better than mysis

11:33 rrc7cz: jcromartie: i'll have to remember that next time i upgrade. I downloaded some msi pack and it shipped with mysis

11:34 works great w/git, but I should be switching to emacs git client anyway

11:34 LauJensen: rrc7cz: try magit, or egg if you need a soft start

11:34 rrc7cz: thanks for the tip

11:47 jcromartie: wow, org-mode is rocking my socks off

11:53 Caprica: is there a way to append to the end of a list?

11:53 chouser: appending to the end of a vector is very fast. use conj.

11:53 (conj [1 2 3 4] 5)

11:53 ,(conj [1 2 3 4] 5)

11:53 clojurebot: [1 2 3 4 5]

11:58 Caprica: is there a nice way to convert a list to vector (or more specifically a range to a vector)?

11:58 jcromartie: vec

11:58 dnolen: ,(into [] '(1 2 3))

11:58 clojurebot: [1 2 3]

11:59 jcromartie: oh that's better

11:59 chouser: ,(conj (vec (range 10)) :hi)

11:59 clojurebot: [0 1 2 3 4 5 6 7 8 9 :hi]

11:59 jcromartie: ,(vec '(1 2 3))

11:59 clojurebot: [1 2 3]

11:59 rrc7cz: why is into better than vec?

11:59 jcromartie: ah

11:59 chouser: vec is better

12:00 jcromartie: dnolen had me thinking that vec maybe made a vector with its arguments at each index

12:00 ,(vec 1 2)

12:00 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (2) passed to: core$vec

12:00 jcromartie: right

12:00 rrc7cz: ,(vector 1 2)

12:00 clojurebot: [1 2]

12:01 jcromartie: huh, didn't know about vector

12:02 Caprica: Thanks for the help

12:04 chouser: vector takes multiple args, like list, hash-set, hash-map, sorted-set, and sorted-map

12:04 vec works on an existing collection, like set and seq do.

12:07 jcromartie: right :P

12:08 alright time to focus... IRC has to go bye-bye

13:33 yacin: i have some data parsing routines that need to be done whenever a program of mine is launched

13:33 is there anyway i can have it parse the files at compile time?

13:33 so i don't have to distribute the data along with the jar?

13:35 LauJensen: yacin: If it needs to parse when start up, it needs to be in the jar or go along side the jar. I guess you could serialize it to a Clojure datatype if you wanted, and just def it

13:36 yacin: that's what i would like to do

13:37 LauJensen: So whats keeping you from doing so ?

13:42 yacin: me just being silly :P

13:53 i guess i don't understand how to do it

13:53 i'd like to be able to do:

13:53 (def-now *var-name* (funcs (to (parse "path/to/data"))))

13:53 and have this all run when it compiles

13:53 rather than at runtime

14:24 dsop: is there a form to make this simpler: http://pastebin.com/1BF2RdUf?

14:24 http://pastebin.com/1BF2RdUf

14:27 cmiles74: You could (let [repository (data "repository")...]) and remove some of the nesting.

14:29 chouser: or (let [[rname rowner rfolks] (map (data "repository") ["name" "owner" "forks"])] ...)

14:48 dsop: chouser: thanks

15:44 itistoday: for some reason when I do 'lein compile' it runs the jar file. I've defined :main in the project.clj, could that be why? Is there a way to prevent it from doing that? I don't see why "compile" is "compile+run"...

15:45 chouser: compile has to "run" all the top-level things. so (def foo (bar)) will run bar during compilation

15:46 but (defn foo [] (bar)) will not run bar until you call (foo) at runtime. so just make sure anything you *don't* want to happen at compile time is inside a function definition.

15:47 itistoday: chouser: I see... thanks!

16:02 ska2342: Hi. Is someone around, who can explain the history of Refs to someone, who didn't get it after reading the article by Volkman and the source code, i.e. me?

16:02 chouser: heh, well, someone can try.

16:03 ska2342: I'm all ears

16:03 chouser: what don't you understand?

16:04 by history you mean the set of past values each ref keeps?

16:04 ska2342: Yes, I am refering to the old values that keep hanging around in a ref during a transaction. Und which circumstances will the history grow?

16:06 chouser: when a transaction starts it has a "now" that it can use to find the correct value inside all refs

16:07 if it asks for that timestamp in a ref, and that ref doesn't have timestamps that old, the ref increases it's history size limit and the transaction retries

16:08 ska2342: is the now measured in time or in counts?

16:08 chouser: I think it's counts

16:08 anars: which contention management strategy does the stm in clojure use?

16:08 ska2342: so, every deref/read will also pass a timestamp?

16:09 chouser: I don't think so -- probably only derefs in a transaction. let me check.

16:10 yes, only when inside a transaction. flying reads just grab the latest value

16:11 timestamp is a count, an AtomicLong

16:12 ska2342: So, a read during a transaction leads to one stored value. Will another read from another transaction lead to the second value? And does the history disappear if one transaction commits?

16:13 chouser: all reads within a single transaction will use the same timestamp for all refs.

16:14 ska2342: all reads from all threads?

16:14 chouser: a transaction is within a single thread

16:15 ska2342: yes, sorry.

16:16 chouser: each ref's history is trimmed when it gets too long, based on the min/max history knobs for that ref

16:16 ska2342: so it's the other threads that may try to read a value that will cause the history to grow, right?

16:16 no, wait with the trimming. I'm still trying to understand the growing of the history, please.

16:16 chouser: any thread that tries to read a value older than a ref's oldest history will cause that ref's history to grow.

16:17 you asked about trimming. :-)

16:17 most of this is detail that you rarely have to think about, though.

16:17 ska2342: (yeah, I asked two questions in one, too fast for my old brain)

16:17 chouser: it's like asking details about the garbage collector's algorithm, when most of the time you simply don't need to care.

16:18 ska2342: I'd like to really understand this, because I'd like to list some gotchas in our book...

16:18 I need to know or at least give a hint, when incrementing the max-history may be necessary

16:19 chouser: ah, well that's a somewhat different question

16:19 ska2342: maybe a better question would be: in what situation will the history overflow?

16:20 obviously for that I need to understand how the history starts growing at all :)

16:20 chouser: the history will grow automatically based on the actual workflow fo the program

16:21 if you're getting lots of transaction retries because of insufficient history while the program is "warming up", setting the min-history can cause the warm up time to be less

16:21 ...as you'd be starting it off with more appropriately-sized histories.

16:22 ska2342: Yes, I think I understand the retrying at the lower end (min history).

16:23 chouser: I've not personally had to set :max-history, and don't remember ever hearing about someone who did.

16:23 ska2342: How can the history grow to two items? What do threads have to do to grow history?

16:24 chouser: presumably that would be in a situation where the retries had take place, the history had grown to max, and some transactions were still never succeeding (or only occasionally succeeding in "racy" conditions) because of insufficient history.

16:26 ska2342: transaction 1 (ta1) starts, reads value with timestamp T1, ta2 starts... something like that...

16:26 chouser: yeah, hang on a sec.

16:32 heh, I'm trying to make a stress test to get the history up high, and I can't get it above 6

16:32 ska2342: hm, I'm trying to understand how ref.faults get's increased in doGet in LockingTransaction.java

16:35 but I'm really interested in how you raise the history (and how you know it's size, BTW)

16:35 chouser: (.getHistoryCount my-ref)

16:38 ska2342: http://gist.github.com/456326

16:39 the future is a slow transaction, and we only ask it to run once.

16:40 But since the transaction uses the current timestamp when it's created, by the time the deref happens a second later, the current time may have changed quite a bit.

16:41 ska2342: so that's 2 threads: one slow and keeping the transaction "open" while the other one tries to alter the value rather fast

16:41 chouser: Indeed, the dotimes below keeps running fast transactions the keep bumping up the timestamp by commiting new values.

16:41 right.

16:41 bumping up the timestamp have having transactions, and filling a's history by altering it, to be more precise.

16:42 for me, when it's done, it reports a's history has maxed out at 10.

16:43 ska2342: yes, a is 1000 and history is 10 for me, too.

16:43 chouser: and all the :try's fail until the dotimes quits looping

16:43 ska2342: So, isn't it a bad thing to happen when the max history is reached? I imagined bad things happening, like the transaction will fail with an exception or sth.

16:44 chouser: I think if any one transaction fails enough times you get an exception

16:44 but like in this case, the dotimes kept doing fast transactions, but after a while it was done and slower transactions could complete

16:45 anyway, now you can add :min-history 100 :max-history 100 to the ref, and you'll the slow transaction will succeed on its first try

16:47 ska2342: which of the two transactions is causing the read fault in the ref and why?

16:47 (man, I feel so stupid)

16:48 chouser: the slow one.

16:49 the first time the future tries, let's say a's historyCount is 0 and the current timestamp is 0

16:49 ska2342: aye

16:49 chouser: thus the future's transaction "now" is 0. It sits there for a second and then does @a

16:49 because the @a is in a transaction, it asks a for it's value at time 0

16:49 clojurebot: multimethods is what separates the boys from the men.

16:50 ska2342: wait a sec..

16:51 chouser: but a's value has been getting bumped every 10 milliseconds, so it's current value is at time 100 or something. and since it has no history a all, it has no idea what it's value was at time 0.

16:51 * chouser waits

16:52 ska2342: ok, the now=0 is from getReadPoint(), right?

16:52 chouser: right

16:53 ska2342: ok, I catched up with you...

16:54 chouser: ok, so a's history is now known to be insufficient, so the amount of history it keeps is increased (I think just incremented)

16:54 ska2342: @a calls doGet

16:55 chouser: and the slow transaction retries, with now=100 or something, it waits, asks for a's value at 100, but a only has a history of 1, that is probably a value at time 199 and a value at time 200. a still doesn't know what it's value was 99 timestamps ago. So the history is bumped and we go around again.

16:56 ska2342: in which case will vals.containsKey(ref) in doGet have a value? (I think I understand the next part which does the job with the timestamps there)

16:57 chouser: hm, I'm not sure what 'vals' is there.

16:58 oh, I think that's just for uncommitted in-transaction values

16:58 which we're not talking about at all here. :-)

16:58 ska2342: OK, so I can safely ignore that.

16:59 So, @a causes a read fault in doGet and the code in run() (around line 320) from the _fast_ transaction will cause the history to grow. (slowly, very slowly, getting it, I think)

17:01 chouser: I think it's the slow transaction that would run that code and cause the history to increase

17:01 using (ref 0 :min-history 95 :max-history 100) for a is instructive

17:02 you can see that after 5 tries of the slow transaction, the history has grown to the 99 needed for the slow one to complete, even though the fast one is still cranking away.

17:03 ska2342: hm, here it just quietly returns nil

17:04 chouser: huh

17:05 ska2342: no, wait, everything is fine. the output was in *inferior-lisp*

17:06 chouser: ah, slime.

17:06 ska2342: even worse: a manually installed, partly changed Slime :)

17:06 chouser: :-)

17:07 ska2342: anyway, I now see: "a is: 391 history: 98" .. obiwan is probably ok

17:08 but I still think that the fast TA is growing the history upon commit since it detects a read-fault that happened in the meantime. No?

17:10 chouser: I think the fast TA is fat and happy. It keeps cranking away on the ref and doesn't know anything's wrong.

17:10 it's the slow one that keeps realizing the history is not yet sufficient and needs to grow

17:12 ska2342: are you sure?

17:13 chouser: well ... pretty sure, but I've been wrong before

17:13 on very rare occasions. ;-)

17:14 ska2342: doesn't the code starting around line 320 in the run()-method indicate that it's _writing_ values? It gets a commit point and the comment seems to say so, too

17:14 chouser: I'll have a better example for you in a moment.

17:14 ska2342: you are very patient.

17:15 chouser: hmmm.... ok, I think I see what's going on.

17:15 which is perhaps what you've been saying all along

17:15 ska2342: huh?

17:15 chouser: that is, the slow transaction records a fault, but the fast one actually increases the history

17:16 (and sets the fault counter back to zero)

17:16 I was noticing the history only grew as fast as the slow transaction failed, and assumed that meant it was the one increasing the history

17:17 ska2342: ok, that's enough for me. Then I think I get this. Final question: what happens when max history was exceeded? Dropping some tvals and retrying?

17:17 chouser: but of course it can't actually increase the history until there's a new value to push onto the history, so it's when the fast one writes the value that the history actually increases.

17:17 I doubt it retries

17:17 rhickey: history is just a sliding window, last N

17:18 a failed reader will mark the failure, next writer will extend history if not over max

17:19 in general, having a long running transaction fight short running ones is something to re-architect, unless you are trying to demonstrate something

17:19 ska2342: so, in the worst case readers will fail again and again if the history is too small.

17:19 anars: rhickey, ladies and gentlemen

17:19 rhickey: ska2342: until they reach the retry limit

17:20 ska2342: yes, the timing of transactions will be something that programmers will have to have in mind for concurrent programming

17:20 chouser: ska2342: http://gist.github.com/456326 is updated

17:22 ska2342: chouser: that is a very nice summary of a rather long discussion, especially the comments! Thank you very much for your patience.

17:23 May I use the source for our book?

17:23 chouser: heh. sure!

17:23 but but... I'm supposed to be writing my book, not yours!

17:23 no, it's fine.

17:24 this is the german book?

17:24 ska2342: yes. and I want to finish it this very week. Afterwards we'll only be waiting for 1.2 to come out and redo all our examples.

17:25 chouser: oh man. you're fast!

17:25 ska2342: (unless there will be things like the primitives that will enter 1.2, that is) ...?

17:26 Actually I've spent almost every single minute of my sparetime since 2009-10. Ask my kids...

17:26 chouser: ah, perhaps you started earlier than I realized.

17:26 anars: hopefully not the "The Cat's In The Cradle"-type of every single minute ;-)

17:27 ska2342: And of course Emacs, LaTeX and AUCTeX help a *lot* :-) We're at 330 pages

17:27 chouser: one thing that I hope is better about a book project than a software project is that there's a definite *end*

17:27 ska2342: anars: sorry, I don't understand that one

17:28 chouser: what about the second edition next year? ;-)

17:28 anars: ska2342: http://en.wikipedia.org/wiki/Cat's_in_the_Cradle - I was kidding, but seriously - the song is great.

17:28 chouser: ska2342: nooo! ;-)

17:29 ska2342: anars: not, that bad. but they had to go to bed early every day :)

17:29 So, what about the work on primitives? Will it be in 1.2?

17:34 hugod: does anyone have something to show the use/require namespace graph?

17:58 lpetit: hugod: I don't see anything like that in contrib. Maybe you'll have to roll your own via the ns-* clojure.core functions ...

18:00 hugod: lpetit: an excuse to try vijual maybe...

18:00 lpetit: hugod: sure

18:12 arohner: hugod: you might want to check out c.c.find-namespaces

18:12 hugod: it won't give you the graph, but you can get a seq of the ns declarations

18:13 hugod: arohner: thanks, I'll take a look. Together with lpetit's hints, that should work.

18:20 DuneMan: somnium`: You around?

19:12 polypus: just wrote this macro

19:12 http://gist.github.com/456523

19:13 comes in handy when you want to let a whole bunch of things differently depending on an if expression, but use the same body

19:14 as opposed to if-let where the bindings are the same but the bodies different.

19:14 is there already something like this anywhere? couldn't think of a better name. suggestions?

19:28 arohner: polypus: I've wanted something similar. Does that output [1 3] when true, and [2 4] when false?

19:30 dsop: arohner: yes

19:37 polypus: aroher: yep

19:37 arohner*

19:38 dsop: polypus: nice one, maybe something for contrib?

19:39 polypus: dsop: ty. yeah, i think it may be generally useful

19:39 but i need a better name :)

22:10 dnolen: hmm for some reason I thought you could use [:tag _] in multimethods to say you don't care about the second element in the match.

22:16 itistoday: so i saw this piece of code recently: (.start (Thread. #(println "foo")))

22:17 I didn't know that java.lang.Thread could take a function in its constructor

22:17 i'm guessing this is clojure overriding it?

22:17 hiredman: dnolen: [:tag Object[ is pretty close

22:17 itistoday: Thread takes a Runnable and Clojure Fns are Runnable

22:17 dnolen: hiredman: yeah I was just thinking that. will I need to use a prefer-method?

22:18 hiredman: I don't think so

22:18 but I am not sure

22:18 itistoday: hiredman: ah, didn't know that, thanks. is there a page somewhere that lists that info? i'm wondering what other interfaces Fns conform to

22:19 hiredman: ,(ancestors clojure.lang.IFn)

22:19 clojurebot: #{java.util.concurrent.Callable java.lang.Runnable}

22:19 hiredman: ,(supers clojure.lang.IFn)

22:19 clojurebot: #{java.util.concurrent.Callable java.lang.Runnable}

22:20 itistoday: is there a sight somewhere with javadoc for clojure's internals?

22:20 *site

22:20 hiredman: nope

22:21 itistoday: any reason for that?

22:21 hiredman: implementation detail?

22:25 Lajla: ,(apply + (range 10))

22:25 clojurebot: 45

22:25 Lajla: ,(range 10)

22:25 clojurebot: (0 1 2 3 4 5 6 7 8 9)

22:25 Lajla: ,(apply + [0 1 2 3 4])

22:25 clojurebot: 10

22:26 itistoday: ,(.start (Thread. #(println "foo")))

22:26 clojurebot: nil

22:26 itistoday: doesn't run threads...

22:32 * dnolen wishes multimethods supported wildcards

23:49 Bahman: Hi all!

23:51 lancepantz: hi Bahman

Logging service provided by n01se.net