#clojure log - Nov 24 2009

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

0:00 KirinDave1: I'm trying to, as a way to get a handle on compojure

0:00 write a little program to track our foosball scores.

0:01 I'm writing things like make-player, make-game, add-player, add-game.

0:02 https://gist.github.com/3d800d9dfc8c437e548d

0:02 Is there a more elegant way to do this stuff?

0:02 Am I doing something that is already being done for me?

0:04 cark: well, using struct directly does the job, or better yet struct-map

0:04 though in the long run it's good to have functions abstracting this

0:04 KirinDave1: It seems like that'd be tedious is client code

0:04 Yeah

0:04 technomancy: structs are generally used as perf operations when you've profiled to find out that just plain maps aren't fast enough.

0:04 s/operations/optimizations/

0:05 KirinDave1: technomancy: I'm mostly using them as a way of documenting the keys I expect.

0:05 cark: the one thing i don't like in your code : instead of having that many refs, you need a single one

0:05 make a single *database* ref

0:05 this will also be better for you to learn clojure

0:05 KirinDave1: cark: I've thought about that, but wouldn't I also want the internal refs?

0:05 For the player history?

0:06 technomancy: KirinDave1: that works, but it generally ends up being more verbose.

0:06 KirinDave1: There seems to be no reason to lock the entire DB if I want to update a single player.

0:06 cark: nope

0:06 _ato: cark: if you're going to have a single database ref, it may as well be an atom

0:06 KirinDave1: Right.

0:06 technomancy: KirinDave1: also: if you're not doing anything in a dosync except commuting, consider atoms

0:06 cark: KirinDave : you will mostly be reading, writing only happens once a game is played

0:06 technomancy: since you're not really taking advantage of the ACI properties of transactions

0:06 KirinDave1: technomancy: I will be doing alters for other stuff.

0:06 technomancy: KirinDave1: I mean if you're only doing a single write per transaction

0:07 _ato: presumably there will cases later on where you want to atomically change team's wins as well the games or history together

0:07 KirinDave1: Yeah

0:07 cark: _ato : right, but what if you add more stuff later and need to coordinate ?

0:07 KirinDave1: The stuff that involves adding a game and then updating the history, and the ladder, will involve multiple changes in a single transation

0:08 technomancy: that's true; I guess you are planning ahead for stuff that isn't there yet

0:08 KirinDave1: Yes

0:08 arohner: why do you guys advocate a single ref? I've always thought of using a ref for each thing with identity that can change

0:08 cark: that's a trade-off, this database is small, it doesn't need such granualirty

0:08 arohner: and IMO smaller refs are easier to manipulate than reaching N levels into a tree structure to alter one node

0:08 cark: granularity

0:09 not at all, using clojure it's easy to reach deep

0:09 arohner: it's still more work than not reaching deep

0:10 cark: allright, what if you suddenly need to keep track of some other games, say fifa for instance

0:10 KirinDave1: Well I'd probably abstract a top level databse.

0:10 But I wouldn't make that a ref, i don't think.

0:10 That structure would be immutable, it'd have keys

0:10 cark: so you need to go back in your code and change it all

0:10 KirinDave1: Its key's values would be mutable.

0:10 arohner: not at all

0:11 KirinDave1: I suppose. I was thinking maybe a database binding.

0:11 arohner: take this current code, add another ref on top of it, for the "league"

0:11 the league ref points at a set of games

0:12 KirinDave1: Well I'd have to refactor those direct refs. :)

0:12 players, teams, games, etc

0:12 technomancy: KirinDave1: the only other thing I'd note is that when you have multiple arg lists, it's more common to have the fewer-arg versions call the more-arg versions, filling in the missing args.

0:12 _ato: cark: there's no point in Clojure's STM if you're just using a single top-level database ref. You're not taking advantage of concurrency. While it's true this is a simple app so it doesn't need concurrency I think KirinDave1 is using it as an excercise to learn about Clojure's features

0:12 technomancy: minor point, but it ends up being a little more dry

0:13 KirinDave1: technomancy: Good point.

0:13 cark: ato : in a real life program you'll have more than this single database

0:13 KirinDave1: cark: wouldn't I just make the database anargument in the functions?

0:13 cark: each time you use a ref, you loose the nice characteristics of purely functional programing

0:13 KirinDave1: instead of a top ref?

0:14 cark: KirinDave : yes, that's even better

0:14 but at some point you need a ref or an atom to hold the identity of your state

0:14 KirinDave1: cark: Right, well I may go back to that.

0:14 That should be in client code tho.

0:14 Not this lib.

0:14 I should ahve a make-league function that drops a league out that you could keep.

0:15 cark: well you must stop at some point

0:15 KirinDave1: I will in my compojure client code

0:15 cark: what about adding planet mars leagues ?

0:15 KirinDave1: probably an atom

0:15 I was considering using a binding-able variable instead of a calling argument

0:15 Is that a shitty idea?

0:15 I see people use bindable vars all the time in contrib, but I hear a lot of grumbling about it here.

0:16 cark: well no it's not a bad idea, arguments are more readily readable tho

0:16 hiredman: *grumble* *grumble*

0:16 cark: this var binding stuff is good when there are many arguments that almost never change

0:16 technomancy: KirinDave1: you run into trouble when you create a lazy seq within binding that gets consumed outside the binding form

0:17 cark: like the *print-blahblah* vars for instance

0:17 _ato: the other problem with bindables is if you want to deal with two leagues in the same function you end up having to (with-league l1 ...) (with-legaue l2 ...) around every call anyway

0:17 cark: ahyes and one last recommendation : those toplevel vars should be named like this : *player* *teams*

0:18 that's a convention people use

0:21 KirinDave1: cark: I though that was a convention for things that would be bound, but sure.

0:24 cark: you'll run into another problem

0:25 you have players in teams and in players

0:25 KirinDave1: ?

0:25 What's the problem with that?

0:25 The players are a set and I intend to only use players from the players set

0:25 cark: so if you change a player, you need to update both its team and the players database

0:26 so that's where you might want to make refs of those players

0:26 KirinDave1: Does identity propagate through refs?

0:26 Seems like sets would get very irritated at that. :)

0:27 _ato: ,#{(ref 1) (ref 1)}

0:27 clojurebot: #{#<Ref@d41010: 1>}

0:27 KirinDave1: Wow, that's neat.

0:27 _ato: that's... weird

0:27 KirinDave1: I mean, the thing is.

0:27 _ato: I wonder what happens then if you change one of them

0:27 KirinDave1: Yeah

0:27 cark: well when you populate a player struct, you get a _value_

0:27 KirinDave1: that's just what I was wondering

0:27 cark: when you put this value in a ref, you get identity

0:28 ato : yes that's very weird =/

0:28 and i wouldn't rely on that

0:29 arohner: that seems like a bug

0:29 ,(ref 1)

0:29 clojurebot: #<Ref@e4bf0e: 1>

0:29 arohner: ,(ref 1)

0:29 clojurebot: #<Ref@b2d6bd: 1>

0:30 _ato: ,(let [s #{(ref 1) (ref 2)}] (dosync (ref-set (first s) 2)) s)

0:30 clojurebot: #{#<Ref@86c645: 2> #<Ref@e9ff86: 1>}

0:30 _ato: ,(let [s #{(ref 1) (ref 2)}] (dosync (ref-set (first s) 1)) s)

0:30 clojurebot: #{#<Ref@596d65: 1> #<Ref@11d1bb6: 2>}

0:30 cark: KirinDave : or you could make your player database a map, and store the key in other places

0:31 KirinDave1: So players mapped by name, you suggest?

0:31 _ato: ,(let [s #{(ref 1) (ref 2)}] (dosync (doseq [r s] (ref-set r 1))) s)

0:31 clojurebot: #{#<Ref@ed4107: 1> #<Ref@39e50f: 1>}

0:31 cark: if you're sure these are unique =)

0:31 KirinDave1: I suppose.

0:31 _ato: ,(set (let [s #{(ref 1) (ref 2)}] (dosync (doseq [r s] (ref-set r 1))) s))

0:31 clojurebot: #{#<Ref@e32bd0: 1> #<Ref@516c52: 1>}

0:31 KirinDave1: The only part of a player that can change is its history, tho

0:31 And that's what's ref'd and shared throughout all the databases.

0:31 _ato: ,[(ref 1) (ref 1)]

0:31 clojurebot: [#<Ref@1bda30a: 1> #<Ref@11b0d65: 1>]

0:31 KirinDave1: So long as I make sure to populate teams with entries from *players*

0:31 _ato: :\

0:32 arohner: _ato: that's weird

0:32 KirinDave1: Yeah I'm not sure that's so awesome

0:33 cark: well try it, you'll see a bug where you have the old value still in team once you updated the player in players

0:33 _ato: ,(apply hash-set (let [s #{(ref 1) (ref 2)}] (dosync (doseq [r s] (ref-set r 1))) s))

0:33 clojurebot: #{#<Ref@759e62: 1> #<Ref@1f16253: 1>}

0:33 _ato: ,#{(ref 1) (ref 1)}

0:33 clojurebot: #{#<Ref@1436fa7: 1>}

0:33 _ato: ,(hash-set (ref 1) (ref 1))

0:33 clojurebot: #{#<Ref@5b4583: 1> #<Ref@30ac0d: 1>}

0:33 _ato: eh...

0:33 ,(array-set (ref 1) (ref 1))

0:33 clojurebot: java.lang.Exception: Unable to resolve symbol: array-set in this context

0:34 arohner: I would model this so every player is a ref, every game is a ref

0:34 everything that wants to talk about players or games will point at that ref

0:34 so there's no possibility of having two copies of a player, and things won't get inconsistent

0:35 KirinDave1: Um, but players are immutable except for thier history.

0:35 So what could change?

0:35 cark: right tradeoffs again, it makes sense here

0:35 arohner: so?

0:35 their histories change

0:36 cark: if their history change, their value change, so that's a completely new player

0:36 arohner: that's a new player *struct*

0:36 conceptually, the ref is the player

0:37 cark: that's a new player value =) conceptually his identity is the ref =)

0:37 KirinDave1: Well, conceptually his history is the ref

0:37 I mean I could do away with history alltogether and just calculate it on the fly with games

0:38 I was just going to keep it caches

0:38 err, cached.

0:39 But I'll consider changing it.

0:40 cark: anyways you have 2 options to give your players an identity, either you give them a unique key or you put them in a ref, and i'm off to bed !

0:40 gnight

1:04 rads: is there a concise way to turn something like [["a" 1] ["b" 2] ["c" 2] ["a" 2] ["b" 3]] into {"a" 3, "b" 5, "c" 2}? (find the sums)

1:06 _ato: ,(apply merge-with + (map hash-map [["a" 1] ["b" 2] ["c" 2] ["a" 2] ["b" 3]]))

1:06 clojurebot: java.lang.RuntimeException: java.lang.IllegalArgumentException: No value supplied for key: ["a" 1]

1:06 _ato: ,(apply merge-with + (map #(apply hash-map %) [["a" 1] ["b" 2] ["c" 2] ["a" 2] ["b" 3]]))

1:06 clojurebot: {"a" 3, "b" 5, "c" 2}

1:07 _ato: rads: ^

1:07 rads: _ato: thank you. the flexibility of clojure's sequence library never ceases to impress me

1:36 how would I double each value in a hash map?

1:52 tomoj: ,(into {} (for [[k v] {:foo 3 :bar 6 :baz 9}] [k (* 2 v)]))

1:52 clojurebot: {:foo 6, :bar 12, :baz 18}

1:52 tomoj: rads: ^

2:04 rads: tomoj: thanks

2:08 _ato: ,(use 'clojure.contrib.generic.functor)

2:08 clojurebot: nil

2:08 _ato: ,(fmap #(* % 2) {:foo 3 :bar 6 :baz 9})

2:08 clojurebot: {:foo 6, :bar 12, :baz 18}

2:09 _ato: ,(fmap #(* % 2) [3 6 9])

2:09 clojurebot: [6 12 18]

2:09 tomoj: cool

2:10 is that any faster? or just prettier?

2:10 _ato: just prettier, it's implemented in terms of (into {} ...) IIRC

2:13 ~def fmap

2:14 heh, yeah: (into (empty m) (for [[k v] m] [k (f v)])))

2:14 ~def into

2:15 doing a reduce might be slightly faster as it avoids the lazyseq but probably not enough to be worth the trouble

2:18 tomoj: I wonder if a transient map could do it faster?

2:18 _ato: "into" uses a transient map

2:18 tomoj: well, I meant take the original map, make it transient, and then replace the keys

2:19 er, values

2:19 _ato: oh right

2:19 tomoj: to avoid building up the structure again, dunno if that'd help or is possible

2:20 _ato: hmm, not sure. it'd have to copy all keys and values anyway, so perhaps not, but there might some weird cache locality benefits or something

2:28 tomoj: hmm

2:28 I think it might actually be a bit faster

2:28 but not much

2:28 comparing (defn trans-map [f m] (let [t (transient m)] (doseq [k (keys m)] (assoc! t k (f (get t k)))) (persistent! t)))

2:28 and (defn trans-map2 [f m] (into {} (for [[k v] m] [k (f v)])))

2:29 I wish the 'time' macro returned the time instead of printing it :/

2:30 _ato: yeah, you should be seeing at least a slight advantage from the lack of the lazyseq that 'for' returns

2:30 oh hang on..

2:30 err... you can't use a transient that

2:31 way

2:31 it'll break

2:31 at least it's not guaranteed to work anyway

2:31 I wouldn't rely on it

2:34 tomoj: huh?

2:35 how would it break?

2:35 hiredman: tomoj: you read http://clojure.org/transients ?

2:36 "Don't bash in place"

2:36 the flow is just like with the persistent versions, you have to pass around the result of operations

2:36 tomoj: oh yes

2:36 so I should be reducing I guess

2:37 _ato: yeah

2:39 something like (persistent (reduce (fn [m [k v]] (assoc! m k (f v))) (transient! m) m))

2:39 though I suspect (persistent (reduce (fn [m [k v]] (assoc! m k (f v))) (transient! {}) m)) would be just as fast

2:39 tomoj: well that's what my initial wonder was, really

2:39 I always feel bad starting from {} and rebuilding

2:40 the hash structure stays the same since the keys aren't changing, so it seems like it would be faster to just swap out all the values

2:45 _ato: hmm, looks like you might be right, but the effect is only worth 5 or 10% at least on my PC

2:45 tomoj: not worth the bother then

2:49 yeah I just got a 5% speedup too

4:47 kzar: Is there a way to pass extra parameters to the JPanel repaint function? I want to pass the information needed to render the game's state.

4:50 scottj_: I haven't used Swing much but from the java docs it doesn't look like that's what repaint is for

4:50 liwp: kzar: huh? repain() sends an event to the Swing event handler asking for a repaint of that component. It has nothing to do with your game state

4:52 kzar: liwp: Yea, my game's running from a loop and when I call repaint it ends up calling the function I wrote to render the game. I wanted to pass details of the state through repaint, so it reached my render function. That way the code would be more functional then having a variable set outside the game loop

4:54 I'm not sure that's possible or if there's an alternative way to acheive a similar result.

4:54 liwp: kzar: your functions has to be a method of a class for it to work with swing, so I think your only option is to embed the game state in your instance of that class

4:55 tomoj: isn't repaint called when the user moves the window around?

4:55 or resizes, etc?

4:55 liwp: kzar: fundamentally swing is an OO framework, so I think you'll just run into a lot of trouble if you try to shoehorn it into FP thinking

4:55 tomoj: yes, but you can also call it yourself to force a redraw

4:55 tomoj: whatever's calling repaint when the window is resized shouldn't have to know the gamestate, though

4:55 liwp: agreed

4:56 kzar: oh that's a good point

4:56 tomoj: wouldn't you just have a proxy that uses paint to access the gamestate and draw it?

4:56 and then if someone wants to repaint it they just ask? I still don't really understand swing very well :/

4:57 liwp: kzar: what you can do it write another function that is purely functional and returns the new game state based on the old game state, and call this function from your implementation of the function that swing calls

4:57 that way you do have a nice purely functional game state updater

4:57 kzar: liwp: But where does it get the old game state from?

4:58 liwp: kzar: you must implement a class that inherits one of the swing base classes, right?

4:58 (it's been a while since I've done any swing)

4:58 so your game state would be a field of that class

4:58 tomoj: seems strange to me to update the gamestate based on what swing wants

4:59 kzar: tomoj: Yea that's not what I want

4:59 tomoj: I want my gamestate in a ref/atom and the gui component will just deref this and paint whatever's there

5:00 liwp: sure, so your function would be something like (defn my-fun [#^Graphics g] (let [s @state] <paint>))?

5:01 I gotta run, but I think tomoj's right, you should use refs

5:01 kzar: ok

6:07 krumholt_: can i make a collection from a java array?

6:10 hoeck1: krumholt_: just call seq on it

6:11 krumholt_: hoeck1 nice thanks

6:16 AWizzArd: chouser: shell-outs sh is for short running processes yes? (not like a pipe)

7:01 djpowell: hmm, you know how add-class-path doesn't work well cause it can't append to the system class path? Attach agents, like I use in my liverepl can. Wonder if you could use them to replace the interactive uses of add-class-path? <http://java.sun.com/javase/6/docs/jdk/api/attach/spec/com/sun/tools/attach/VirtualMachine.html#loadAgent(java.lang.String, java.lang.String)>

7:01 probably not. sounds flakey.

7:23 djork: djpowell: what's your liverepl?

7:28 _ato: djpowell: it's likely the agent is loaded in a subclassloader, so it would probably have the same problems as add-classpath (namely stuff loaded in higher classloaders can't see stuff in lower classloaders)

7:29 add-classpath should work okay if you load everything into Clojure's classloader (ie you put nothing but the clojure jar on the -cp command-line and add every jar you need with add-classpath)

7:31 esj: gents, is there a way to send a SIGINT (or equivalent) to a particular agent. shutdown-agents merely prevents new actions being dispatched, while I want to pull-down the running action.

7:33 krukow: esj: I don't think so, you'd have to program the agent to be interruptible

7:33 and check for interrupt status often

7:33 and still you'd need to access the thread... so probably not :-(

7:34 esj: ok thanks

7:36 _ato: yeah, not reliably anyway. Even if you can get a handle on the thread (I guess you could have the agent put it in a ref when it starts the job or something), if it blocks on IO or something catches the interrupt exception it becomes uninterruptible

7:39 mrSpec: Could you tell me how to change the value of x in let block? I cant find anything :/ like: (let ((x 0)) (setf x 1))

7:40 krukow: you cant: let bound locals are not variables

7:40 _ato: mrSpec: clojure locals are immutable

7:40 esj: hmm... will need to think.

7:41 krukow: there was one thing that came up yesterday: you can (let [x 42 x (inc x)] x)

7:41 _ato: you can however do: (let [x 0] (let [x 1] ...))

7:41 yeah

7:41 krukow: LOL :-)

7:41 ,circuitbreak

7:41 clojurebot: java.lang.Exception: Unable to resolve symbol: circuitbreak in this context

7:41 esj: yikes !

7:41 _ato: that's not changing the value though, it's creating a new binding that "shadows" the outer one

7:41 mrSpec: hehe

7:41 krukow: ,(let [x 42 x (inc x)] x)

7:41 clojurebot: 43

7:41 krukow: that is what I mean

7:42 mrSpec: but can I do it in other way? to change value?

7:42 Maddas: Why?

7:42 mrSpec: I dont want 2nd "x"

7:42 Maddas: What is the problem you're trying to solve? You can't mutate an immutable, that's kinda the point :-)

7:42 krukow: why do you want to change it: can you give an example?

7:43 mrSpec: ok, I'm rewriting C++ code

7:43 I'll paste it sec

7:43 djpowell: djork: http://github.com/djpowell/liverepl - lets you repl in to running clojure/java processes with no special pre-configuration

7:43 krukow: heh - ok here we go

7:43 djork: oh cool

7:44 mrSpec: ,paste

7:44 clojurebot: java.lang.Exception: Unable to resolve symbol: paste in this context

7:44 mrSpec: hmm

7:44 what was the url?

7:44 djork: clojurebot: paste

7:44 clojurebot: lisppaste8, url

7:44 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

7:44 mrSpec: thanks

7:44 krukow: clojurebot: help

7:44 clojurebot: http://www.khanacademy.org/

7:44 djork: mrSpec: to "change" the value of a binding in a block you would recur

7:45 either recur on the fn itself or use the loop construct

7:45 lisppaste8: mrSpec pasted "Mandelbrot " at http://paste.lisp.org/display/91009

7:46 djork: ,(loop [x 1] (if (< x 10) (recur (inc x)) x)

7:46 clojurebot: EOF while reading

7:46 djork: oops

7:46 ,(loop [x 1] (if (< x 10) (recur (inc x)) x))

7:46 clojurebot: 10

7:46 krukow: C for usually maps to loop-recur

7:46 or higher order functions

7:47 djork: mrSpec: you wouldn't "change" isInside, you would return it

7:47 mrSpec: so if it so complicated, I'm doing something wrong?

7:47 djork: ah

7:47 esj: yeah, i think recrusion

7:48 djork: your innermost for loop should be translated into one expression that evaluates to the value of is-inside

7:49 krukow: mrSpec: it is not really more complicated, just different

7:49 mrSpec: djork: ok, I'll try with loop

7:49 krukow: but don't measure performance and then come back saying that clojure is slow :-)

7:49 djork: heh

7:51 mrSpec: hah about speed... I have some memory problem. It takes a lot of memory, but first I'll make it work, then I will think about memory ;)

7:51 krukow: ;-) btw. I think that algorithm will be awkward to translate

7:52 particularly the part that sets isInside to false and then checks it later to sideeffect putpixel

7:55 mrSpec: krukow: so I should find other algorithm? ;)

7:57 krukow: I think it would be easier to rethink the algorithm than to try and port that imperative algorithm to a functional style, but just my two cents :-)

7:59 _ato: http://gist.github.com/241856

8:00 the isInside loop might look something like that I guess

8:00 I don't know what the alrogithm is doing so I've just called it "step"

8:01 djork: I'd make the algo return a seq of coords

8:04 mrSpec: _ato: thanks, I'll try it :D

8:05 _ato: I guess you'd probably need to use letfn instead of defn for step and inside? as you need to close over c-im and c-re values from the outer loops

8:06 mrSpec: i will have to read about letfn to see the difference.

8:06 _ato: oh actually inside? is okay

8:06 it's just step that uses c-im and c-re

8:10 yeah.. so actually maybe the whole thing would look something more like this: http://gist.github.com/241856 (updated)

8:10 mrSpec: ok, thanks for help, I have to go to Uni BBL

8:11 krukow: heh - uni exercise :-)

8:14 AWizzArd: rhickey: when I (send my-agent) in two threads T1 and T2, will then an await or await-for in T1 always wait for the answer it sent?

8:16 the-kenny: AWizzArd: I think t1 will wait for *all* actions in the agent to complete

8:17 AWizzArd: So then I would need to keep my current strategy to provide a (promise) and read that, ok.

8:56 rhickey: so I've just applied a contributed patch with git am, and tests fail, what's the easiest way to back it out?

8:57 chouser: you haven't pushed it?

8:57 rhickey: no

8:57 chouser: git reset --hard HEAD^ # that'll back you up one commit

8:57 the --hard means you might lose data, but of course that's what you want.

8:57 just be careful you don't have any uncommitted changes you want to keep

8:58 rhickey: I thought so, what an ugly command for such an ordinary thing

8:58 chouser: well, it's what I do. I don't know if it's "right" or best

8:58 rhickey: since git am applications are always speculative, you are not committing something you wrote yourself and understand to be correct

9:02 chouser: yes. I think another option might be to do all such commits in a local branch made for just such activity

9:03 but it's not clear to me that whole set of commands you'd end up using would be any less wordy

9:03 rhickey: chouser: I do that, but there were prior patches I wanted to keep

9:04 ok, next release punch list is down to three items

9:06 chouser: ooh

9:06 rhickey: agent errors needs tidying

9:07 sorted-set-by patch is broken, but I'd like to get the fix in

9:07 chouser: embedded constants is just about the tests.

9:07 need to make sure they're actually testing what they claim to be

9:08 rhickey: I'm unclear about embedded constants, don't we have that already?

9:08 chouser: yeah, the main patch is in but there's been some confusion about the tests.

9:09 at least in part because my experience reading tests is thin

9:11 rhickey: I've looked t every patch, and determined it's either not yet a good idea or not ready (in backlog), a good idea for next time (approved backlog), applied it, or those 3 left in Next Release

9:14 chouser: thank you. Does this feel like a sane system to repeat for future releases?

9:15 rhickey: I think so, we'll see how people do with the latest code and release candidate downloads

9:17 chouser: almost 30% so far say they're using 1.0. I'm losing my bet.

9:17 rhickey: we are going to need docs for a lot of things

9:17 chouser: yeah, I thought of that. :-/

9:17 rhickey: where are the results?

9:17 chouser: no good result charts yet

9:18 I was just using this: http://tinyurl.com/yefmz8e

9:19 rhickey: thanks

9:19 chouser: almost 10% on 'new'

9:20 rhickey: crazy people

9:20 :)

9:20 chouser: :-)

9:20 fogus_: chouser: Hey! I resemble that remark.

9:21 rhickey: so new is very new today - the direct linking stuff is in for the craz... er intrepid

9:21 the-kenny: How can I take the survey? I can't find a link in the Spreadsheet..

9:21 fogus_: I don't know what that word means, but it sounds great!

9:22 chouser: 53% don't know what chunked seqs are

9:22 the-kenny: survey: http://tinyurl.com/yeejwok

9:23 1% say chunked seqs hurt

9:26 devlinsf: ,(str "Test")

9:26 clojurebot: "Test"

9:51 cemerick: rhickey: been absent for a bit -- is this 'direct linking' written up anywhere, or are the irc logs the best spot?

10:08 jweiss: question - is it idiomatic or overkill to use a multimethod like a switch statement? I am not sure that's an intended use for multimethods

10:08 krumholt_: can i "clear" a namespace of all symbols? i am trying to compile my code and i have renamed a bunch of functions. the "old" version are still around and i need to get rid of them

10:09 chouser: jweiss: if there's a possibility someone else might want to extend your switch statement, multimethods are definitely a good option

10:09 jweiss: chouser: probably not going to need extending

10:09 chouser: jweiss: if not then I guess it's up to you whether you think it would be clearer using cond or condp, or if multimethods would be clearer.

10:11 jweiss: chouser: i'll try the multimethod and see if it looks readable. thanks

10:11 chouser: jweiss: of course anytime the cond wouldn't be at the top level of a fn, a multimethod is likely to be a poor fit.

10:12 krumholt_: you can combind ns-interns with ns-unmap to clear everything

10:13 jweiss: chouser: i'm trying to "switch" on a test result (pass/fail/skip/exception) and call a set of "listeners" which do user-defined stuff based on the results of the test

10:13 this is not any of the build in test stuff btw

10:13 built

10:14 i think multimethod will work

10:14 krumholt_: chouser, thanks

10:28 scottj_: Is there a general pattern for converting (for [a (foo) b (bar a) c (baz b)] [a b c]) into a series of maps? I'm trying to generalize p27 from ninety-nine prolog probs, here is the specific solution I came up with http://paste.lisp.org/display/91015 any suggestions? thanks

10:31 chouser: what's wrong with using 'for'?

10:34 scottj_: in part I'm curious how to do it w/ map, since I could use pmap. in part bc I thought map might be easier to write a general solution for w/o macros.

10:34 chouser: hm, maybe we need pfor. :-)

10:35 jweiss: if i'm using a multimethod that takes 3 args, and the dispatch only cares about the first arg, what do i put for the 2nd and 3rd args in the defmethods?

10:37 just use nil?

10:40 chouser: scottj_: http://paste.lisp.org/display/91015#1

10:41 scottj_: when you have :when or :while things get trickier.

10:42 scottj_: Chousuke: thanks!

10:42 (sorry about the default autocorrect)

10:42 or maybe that was tab

10:42 chouser: np

10:43 happens all the time

10:43 but we're each too stubborn to change our nicks, so there you go. :-)

10:44 rhickey: cemerick: IRC logs re: direct linking - new last weekend

10:47 cemerick: OK, thanks :-)

10:48 +1 on the idea of pfor

10:48 rhickey: cemerick: short story - more speed, via dynamicity tradeoff - nothing new under the sun

10:49 cemerick: rhickey: yeah, I caught a brief bit of the conversation yesterday, w.r.t. issues with contrib ns' rebinding core fns

10:49 rhickey: but open questions about how to best expose/control, so please chime in once up to speed

10:49 chouser: apparently I have an unconcious urge to make 'for' as complex as possible. chunk support helped a lot. pfor would take it a significant step further.

10:50 cemerick: I actually do rebind the root of a couple of core vars, though I presume that wouldn't be impacted by dynamic linking.

10:50 or, static linking, that is.

10:51 chouser: for is the new LOOP? :O

10:51 rhickey: cemerick: meaning you replace the core fn?

10:51 chouser: cemerick: if you don't call it, it won't be staticly linked

10:51 rhickey: I'd like to call it direct linking

10:51 chouser: cemerick: if you don't call it, it won't be direct linked

10:52 cemerick: rhickey: yeah -- the memoization of classes, or bases (forget which)

10:52 chouser: ah

10:52 cemerick: ah, supers and bases

10:52 rhickey: but yes, replacing roots would be effected since code direct linked prior to the replacement won't see the new version

10:52 affected

10:53 cemerick: rhickey: I make sure I do my monkey-patching very, very early :-)

10:54 rhickey: I'm interested in any early experience reports on the latest new with direct linking

10:54 cemerick: I'm bundling a release this week -- will hopefully pull in HEAD over the weekend.

10:54 rhickey: you're expecting some pretty crazy perf improvements eh?

10:55 rhickey: cemerick: it seems like 20-25% across the board is easy, but in specific cases it can be much. much faster, like 10x +

10:56 right now it is limited to clojure*, so you won't get direct links for your own code

10:56 cemerick: is there more going on here than simply avoiding the indirection of the vars?

10:57 rhickey: cemerick: it's not actually the indirection, its the volatility

10:57 can't inline through volatile

10:57 cemerick: you mean all the stuff associated with binding...

10:57 oh, you mean java-volatile

10:57 rhickey: cemerick: no, dynamic binding is another layer, I'm just talking about replaceable roots

10:58 chouser: rhickey: re agent errors, you want some kind of guard to prevent any thread from doing clear-agent-errors while a error handler is running?

10:58 rhickey: or just guard the error handler thread itself while the handler is running?

10:59 rhickey: chouser: if easy, which it could be since you could compare *agent* to passed agent

10:59 but most important is to doc that it is not ok

11:00 until we figure out that it is :)

11:00 chouser: so other threads clearing while handler is running is ok

11:00 cemerick: so, without looking at HEAD (:-P ), I'm guessing there's now two Var classes, one with a volatile root another without -- and a direct-linked call site gets the latter, everyone else gets the former...

11:00 chouser: :-) right

11:00 rhickey: cemerick: no, direct linking is a property of the caller, not the var

11:00 cemerick: swing-and-a-miss

11:00 rhickey: so different callers might have different linkage

11:01 the only thing that *is* on the var currently is a :dynamic true metadata tag that indicates it should never be direct-linked as it is due to be rebound by design

11:01 currently pr is marked thusly for pprint

11:02 and test/report

11:03 chouser: sorry, I'm still not clear on what you want for clear-agent-errors. (send a (fn [_] (clear-agent-errors *agent*))) is ok, right?

11:04 rhickey: chouser: why would one do that?

11:04 * chouser ponders

11:05 cemerick: nuclear-level error clearing "I want a usable agent back, dammit!"

11:05 rhickey: cemerick: but the send part?

11:06 cemerick: *shrug*

11:06 chouser: actually that won't work because you can't send to an agent with errors

11:06 cemerick: I've taken to simply wrapping everything sent to agents with a (try (catch Throwable ...)), just to avoid having to deal with agent errors. :-(

11:06 rhickey: cemerick: you want to ignore the errors?

11:06 chouser: either ignore or ...dum da dum... provide a callback.

11:06 cemerick: right?

11:07 cemerick: rhickey: well, that (catch Throwable) is in a quickie macro. The "real" code being sent has proper error handling. I just wanted a safety in the event of a stack overflow, OOME, etc.

11:08 I'm only using agents in one spot, so it's entirely possible that I'm Doing It Wrong.

11:09 The client code only really cares about two states, :error and everything else. When the former happens, it gets logged to be pondered later, very little that can be done in-place.

11:09 Exceptions hanging around in the agent just muck up the other 99% of the work that goes off without a hitch.

11:10 rhickey: cemerick: so that ties into the auto-clear concept - send to callback and don't log internally

11:10 I'm not opposed

11:11 cemerick: rhickey: I'm afraid I'm not at all versed in the various proposals wafting around for agent errors. Learn from me at your peril. ;-)

11:11 rhickey: I guess we had talked about the return value of the callback controlling that and the next agent state

11:11 cemerick: these are things we already talked about

11:11 chouser: ok, so queued actions will proceed even if there's an error in the list. That's not a behavior I've taken advantage of.

11:13 so perhaps you might send several actions, some of which you know might fail and queue up a clear at the end of them so that future sends will be allowed.

11:13 rhickey: chouser: that's somewhat broken

11:13 chouser: sounds like a risky design, I suppose

11:13 yeah

11:16 * chouser reads some logs

11:21 tmountain: I was playing around with writing a squeeze function this morning to replace redundant runs of a given character in a string with a single instance of that character

11:21 http://travis-whitton.blogspot.com/2009/11/squeezing-string.html

11:22 for some reason, the version I wrote which uses reduce has terrible performance compared to using re-gsub from str-utils

11:22 I'm wondering if it's something in my code or if I should avoid using reduce if I'm concerned about performance?

11:23 rhickey: tmountain: building strings by successive concatenation is a bad idea in every programming language, here too

11:24 leafw: tmountain: use str, which uses an StringBuilder.

11:24 rhickey: setting aside that regex will build a little machine for you, you'll need something with efficient append - streams, transient vector etc

11:25 leafw: calling str over and over is no different than concat

11:25 leafw: true, still lots of new String being created.

11:25 tmountain: rhickey: so in the real world, I'd be better off with the regex or using something like a transient?

11:26 rhickey: tmountain: you can try a vector instead with little change to your existing code, and transient will little change to that

11:26 leafw: tmountain: no, rhickey meant you'd use a vector to accumulate strings, then apply str to it

11:26 tmountain: leafw: ok, gotcha

11:28 rhickey: make x a [] and (conj x y)

11:29 str when done

11:29 it still won't compete with a regex

11:30 also, last is dangerous

11:30 ,(doc last)

11:30 clojurebot: "([coll]); Return the last item in coll, in linear time"

11:30 rhickey: linear time == do not use for not known small

11:31 tmountain: rhickey: good to know. thanks for the tips.

11:37 replaca_: p

11:41 oops

11:46 Chousuke: hm, there's a ninja commit in the git repo :P

11:46 "Author: unknown <Ninja@.(none)>"

11:46 chouser: yikes

11:47 Chousuke: probably someone with misconfigured tortoisegit :)

11:47 magnet: that's what he wants you to believe

11:48 chouser: ah, pretty to see whose it actually is.

11:52 seems to me that most of the time if you provide an error-fn for an agent you don't want the error queued for you or the value of the agent to change, so simply providing an error-fn could do that

11:53 you can always have your error-fn queue the error somewhere else if that's what you want, otherwise just don't provide an error-fn and let it be queued in the agent

11:54 SergeyDidenko: Hi! Can anyone help me to simplify the following code: (def mymap {:vec [1 2 3]})

11:54 (assoc-in mymap [:vec] (conj (:vec mymap) 5))

11:54 I mean the second line

11:54 :)

11:54 chouser: so that really just leaves the (I think unusual) case where you want the error-fn to adjust the value of the agent, perhaps based on the fn, args, or old state of the agent. Could use the return value of error-fn to communicate that, but doing so complicates the "normal" case of just leaving it alone.

11:55 SergeyDidenko: (update-in mymap [:vec] conj 5)

11:56 SergeyDidenko: Thanks, chouser. Somehow missed that.

11:56 chouser: rhickey: how does a set-agent-value that only works inside error-fn strike you?

11:56 * chouser guesses that won't fly.

11:57 chouser: SergeyDidenko: np

12:03 having an error cause a change to the agent value isn't even an option today, so maybe that feature's just not needed.

12:09 so that would mean agents with an error-fn would never be in an 'error' state. If all the useful data (exception, agent, fn, args) get passed to error-fn as a map, you could do something as simple as (agent state :error-fn prn) to get an agent that never gets "stuck" and prints errors to stdout

12:09 I think I like that

12:09 rhickey: I'm not going to touch this without some sense I'm headed in the right direction. Do you want me to write this up better and maybe post to clojure-dev?

12:15 tmountain: I re-wrote the squeeze function, built up the data, and then applied str at the end, and it runs 27X faster ;-) http://travis-whitton.blogspot.com/2009/11/squeezing-string.html

12:23 chouser: (agent init :error-fn #(.printStackTrace (:error %))) if you want to get fancy

12:26 cemerick: chouser: nice :-)

12:31 djork: tmountain: nice

12:31 tmountain: good call on leaving str to the last step

12:43 esj: anybody here interacted with COM in clojure ?

12:45 duncanm: esj: via Java, or via .NET?

12:45 devlinsf: esj: No, but there is the JaCOB library

12:45 esj: Java

12:45 devlinsf: esj: http://danadler.com/jacob/

12:46 esj: yeah, i've seen JaCOB, com4j and ez jcom

12:46 was wondering if anybody had opinions

12:47 duncanm: heh, i wonder if you can run Clojure on the MS JVM

12:47 does clojure require java 5+?

12:49 devlinsf: duncanm: Yes, I believe java 5 is required

12:50 jweiss: can I use isa? with an interface? ie, how do i call isa? to check that Exception is a Throwable.

12:51 sorry that (Exception.) is a Throwable.

12:51 devlinsf: ,(isa? (class {}) clojure.lang.IFn)

12:51 clojurebot: true

12:52 jweiss: ,(isa? (Exception.) java.lang.Throwable)

12:52 clojurebot: false

12:52 devlinsf: ,(isa? java.lang.Exception java.lang.Throwable)

12:52 clojurebot: true

12:52 jweiss: devlinsf: that's because they are both classes

12:52 devlinsf: jweiss: Try this

12:52 hiredman: ,(doc instance?)

12:52 clojurebot: "([c x]); Evaluates x and tests if it is an instance of the class c. Returns true or false"

12:53 Chousuke: tmountain: I wrote a quick version of that using a transient vector and it's about 30% faster it seems :)

12:53 devlinsf: ,(isa? (class (Exception.)) java.lang.Throwable)

12:53 clojurebot: true

12:53 hiredman: ,(instance? Callable #())

12:53 clojurebot: true

12:53 hiredman: ,(instance? clojure.lang.IFn #())

12:53 clojurebot: true

12:53 jweiss: hiredman: i ask about isa? because i'm using multimethods, which calls isa?

12:53 devlinsf: jweiss: Use the class fn

12:54 Chousuke: tmountain: http://gist.github.com/242063

12:54 jweiss: so if i want to dispatch on a Throwable, how do i do that.

12:56 Chousuke: I like how few changes I had to make to use transients :P

12:56 jweiss: maybe i'm confused about what isa does. if i pass it two class objects, does it actually look at the hierarchy of their inheritance, or does it just say "yep, they're both class objects"

12:56 hiredman: it looks at the hierarchy

12:56 krumholt__: can someone explain to me why (map (fn [a b c] (a b c)) '(list list) [1 1] [2 2]) => (2 2) i would expect ((1 2)(1 2))

12:56 jweiss: hiredman: ok thanks

12:57 hiredman: you can even pass your own hierarchy to isa?

12:57 jweiss: hiredman: yeah i know, but i don't want to make my own in this case

12:57 Chousuke: krumholt__: you're using the symbol list as a function instead of the function list

12:57 ,('list 1 2)

12:57 clojurebot: 2

12:57 krumholt__: Chousuke, oh thanks

12:58 Chousuke: in general, it's ('sym coll not-found)

12:58 krumholt__: what does a symbol used as a function do?

12:58 Chousuke: looks itself up in whatever

12:58 or returns the second argument if it fails.

12:58 krumholt__: ok thanks

12:58 Chousuke: ie. same as a keyword.

12:59 you'd get the result you wanted if you used a vector instead of a quoted list :)

13:00 krumholt__: very nice :)

13:04 devlinsf: krumholt__: to empasize chosuke's point

13:04 ,(map (fn [a b c d] (a b c d)) '(list list) [1 1] [2 2] [3 3])

13:04 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: Symbol

13:04 devlinsf: ,(map (fn [a b c d] (a b c d)) [list list] [1 1] [2 2] [3 3])

13:04 clojurebot: ((1 2 3) (1 2 3))

13:05 tmountain: Chousuke: very cool

13:06 hiredman: ,(map (fn [a b c d] (a b c d)) (list list list) [1 1] [2 2] [3 3])

13:06 clojurebot: ((1 2 3) (1 2 3))

13:06 Chousuke: hiredman: very clever :P

13:06 hiredman: buffalo buffalo buffalo buffalo

13:06 defn: buffalo

13:06 duncanm: hmm

13:06 how does that work?

13:06 Chousuke: duncanm: (list list list) creates a list of two functions, list and list

13:07 hiredman: ,(list list list)

13:07 clojurebot: (#< clojure.lang.PersistentList$1@bd11b1> #< clojure.lang.PersistentList$1@bd11b1>)

13:07 duncanm: ohh

13:07 defn: ,(list list list list)

13:07 clojurebot: (#< clojure.lang.PersistentList$1@bd11b1> #< clojure.lang.PersistentList$1@bd11b1> #< clojure.lang.PersistentList$1@bd11b1>)

13:08 defn: ,(list (list (list list list)))

13:08 clojurebot: (((#< clojure.lang.PersistentList$1@bd11b1> #< clojure.lang.PersistentList$1@bd11b1>)))

13:08 Chousuke: Hm

13:08 I think Lisps problem wasn't that there were too many parentheses

13:09 it was that there were too many lists.

13:09 :P

13:09 defn: heh

13:09 Chousuke: also, Lisp's

13:10 duncanm: headius: the talks from JRubyConf will be posted, right? do you have an estimate?

13:11 defn: i wish they'd hurry up and post the RubyConf S. Halloway talk

13:12 headius: duncanm: I do not know, but it will hopefully come quickly

13:12 clojure came up several times...seems like a lot of people like the idea of jruby front-end with clojure for concurrent services in the back-end

13:12 jruby's becoming a pretty nice web gluey front-end for other jvm langs

13:17 ambient: why can't there be one lang uber alles? :(

13:18 sql, java, xml, http, html, orm, templates, blah, it all gives me a headache.

13:18 headius: ambient: there will never be one lang

13:18 ambient: i see no reason why everything could not be done with lisp

13:18 or a language without any syntax

13:18 annealer: i see no reason why i'd want to program in a world like that

13:18 rhickey: chouser: I think you can't pass fn + args, since fn isn't a great identity, so if you just pass error plus current state, it would be easy to return that state or some reset value. Setting a handler can replace putting in internal error log afaic

13:18 annealer: variety is fun. there is no one language to rule them all

13:19 headius: because not everyone will want to use lisp, and so everyone using lisp will have to duplicate effort others have already put in

13:19 ambient: variety distorts focus, focus is good for getting things done

13:19 headius: better to reuse than reimplement again and again

13:20 annealer: variety breeds innovation. there's more to life than just getting things done

13:21 ambient: i guess it's a good thing, we wouldn't want computing to be too simple so that there are more jobs available

13:21 cemerick: headius: I had an old RoR hand chat me up over the weekend about how we should use JRoR as our eventual front end. He made a compelling case.

13:21 headius: who was that?

13:21 cemerick: ^^

13:22 Rails 3 is also going to be even more compelling, since it will make it easier for us to swap bits out for existing java libs

13:22 cemerick: just a friend of mine who was deep into rails for some years, until he got yanked out into php land a few months ago

13:22 headius: there's several folks doing exactly that

13:22 JRoR front plus Clojure in the back

13:22 it's like a reverse mullet

13:23 ambient: does jruby hide the classpath awkwardness?

13:23 headius: generally, yes

13:23 require 'java'; $CLASSPATH << 'whatever.jar'

13:23 cemerick: insofar as the web stuff is fundamentally "just a cost" for us (modulo the whole notion of quality UX), using something that designers and other like-minded folk are super-comfortable with makes sense.

13:23 headius: it's not flawless, but it works for most people just fine

13:23 defn: http://disclojure.org/

13:24 chouser: I have exactly one rails project. It makes me unhappy.

13:24 ambient: the fact that you have only one or the fact that you have a rails project?

13:24 chouser: It's not ruby's fault either.

13:25 headius: we need to get a clojure-inline added to the inlining gem

13:25 cemerick: Just about any front-end I've ever had to build has been a miserable experience.

13:25 headius: someone added scala over the weekend

13:25 chouser: ambient: heh. I've used the project to learn rails, and I haven't been fond of what I've learned.

13:25 ambient: chouser: not meant as a joke, i was just wanting to know your opinion and your statement was ambiguous ;)

13:25 cemerick: chouser: I think the objective in general is, bang it out, it's all going to get replaced in 6 weeks. ;-)

13:26 defn: so true

13:26 cemerick: That was the general approach in the django world when I passed through there a while back, too.

13:26 chouser: I knew ruby already -- still my favorite pre-clojure language.

13:26 ambient: i've done some django, never touched rails

13:26 headius: rails 3 cleans up a lot of the yuck in rails

13:26 defn: I haven't tried rails 3

13:27 chouser: I thought that since I hadn't done much standard server-side web app design that I should use a project that had made a bunch of design decicions already

13:27 bitbckt: defn: it's still "edge"

13:27 headius: there's at least one place going live with jruby + rails 3 soon

13:27 cemerick: headius: what's your pitch, then? Why should I use JRoR instead of something like compojure + enlive?

13:27 defn: i tried doing a HAML + SASS + RoR project with 2.x, but I do NOT recommend it

13:27 headius: they're kind of crazy though

13:27 cemerick: no other web framework does as much for you as ror

13:27 defn: ^

13:27 there's a reason compojure is modeled after rails

13:28 ambient: most web frameworks give me headaches. I did Java Server Faces when it was barely version 1.0

13:28 cemerick: headius: but aren't I risking a significant skills/attention dilution by having yet another language floating around?

13:28 headius: ambient: I think that's a feature of JSF, actually

13:28 ambient: headius: not just headaches, but uncontrolled bursts of blind rage

13:28 * cemerick likes playing devil's advocate :-)

13:28 headius: cemerick: well, given that there's lots of folks building rails apps without really knowing ruby, I'd say the watering-down potential is low

13:28 KirinDave: cemerick: For the libraries. :) For the language, it's a lot like human language. Your total capacity grows with your total inventory.

13:29 headius: rails is really just a nice internal DSL for web apps

13:29 the fact that it's in ruby is peripheral

13:29 defn: cemerick: i don't think so. You have CSS, XHTML, why not throw a couple more in for other specific aspects of your application?

13:29 chouser: I would argue with "nice", esp. around activerecord

13:29 KirinDave: Also, find something that is more suitable for rapidly developing a web app with a small team.

13:29 defn: chouser: no one is forcing you to use activerecord

13:29 KirinDave: Most people don't understand the tradeoffs Rails decided to make.

13:30 cemerick: defn: yeah -- I'm, uh, promiscuous w.r.t. programming languages already. Just trying to draw headius out a bit :-)

13:30 defn: hehe :)

13:30 headius: I'm not a great person to advocate rails over X though

13:30 I don't do apps much these days

13:30 cemerick: chouser: I'd agree, but when one isn't using an RDBMS, then activerecord ceases to be a problem :-)

13:30 * bitbckt is reminded of the many "We're not Rails people" statements at JRubyConf.

13:30 cemerick: heh, I should head over to #ruby and see what I can stir up.

13:30 icey: twitter has turned into a really good irc warning system. when you start seeing the OHs you know it's time to login :D

13:30 bitbckt: cemerick: #ruby-lang

13:31 But if you go too far toward Rails, you risk getting punted into #ror, from there.

13:31 cemerick: huh, and there's a #jruby too

13:31 KirinDave: Which is totally worthless.

13:31 bitbckt: Rightly so, imho.

13:31 KirinDave: jruby is much better.

13:32 This is an example of #ruby-lang

13:32 http://kirindave.tumblr.com/post/24570389/incredibly-stupid-people-on-freenode-ruby

13:32 I would avoid them.

13:32 cemerick: headius: is glassfish still the preferred container for JRoR?

13:32 bitbckt: +1 on glassfish

13:32 technomancy: bitbckt: did I meet you at JRubyConf?

13:32 headius: cemerick: it's very nice

13:32 bitbckt: technomancy: Yessir, you did.

13:32 headius: as app server or as gem

13:32 defn: OooOooo! http://orgmode.org/worg/org-contrib/babel/org-babel.php There is no clojure support for org-babel

13:32 bitbckt: technomancy: I'm the awkward idiot that bugged you before your talk. :-)

13:32 defn: err rather org-babel support for clojure

13:32 now*

13:32 headius: bitbckt: who are you irl?

13:33 bitbckt: headius: Brandon Mitchell

13:33 cemerick: headius: is GF the only viable option, though?

13:33 headius: ahh ok, one more connection made then

13:33 technomancy: bitbckt: heh; yeah I was just kind of heads-down since I decided to to the lightning talk on short notice.

13:33 bitbckt: headius: We had dinner together a RubyConf 2 years ago.

13:33 headius: cemerick: nah, jror can deploy as a war file to lots of stuff

13:33 GF just has some other nice non-WAR options

13:34 bitbckt: technomancy: I understand. I appreciated your advocacy.

13:34 And Halloway, of course.

13:34 technomancy: he sure knows how to pitch

13:35 bitbckt: Yes, he does. Despite Susser.

13:35 >_>

13:36 headius: is phil hagelberg on irc?

13:37 he did a lightning talk at jrubyconf about using refs+stm from jruby

13:37 bitbckt: headius: technomancy

13:37 headius: oh, great :) hi, technomancy

13:37 bitbckt: hehe

13:37 headius: technomancy: I was thinking of ways to make that more seamless

13:37 bitbckt: Huzzah for Rubyists in #clojure...

13:37 KirinDave: headius: I am surprised you two haven't met.

13:37 Seems like you're on a collision course.

13:37 headius: I just didn't know nickname

13:38 technomancy: I've also had a handful of people that want to implement a "clojure mode" in Duby that uses clojure refs

13:38 perhaps for object fields or something

13:38 technomancy: that would be slick

13:39 bitbckt: Ooh.

13:39 technomancy: right now the problem with jruby integration is exception wrapping; retry exceptions inside ruby blocks get wrapped with ruby exceptions

13:39 chouser: icey: what do you meant?

13:39 * chouser still hasn't figured out any great way to use twitter.

13:39 technomancy: I was trying to patch Clojure to catch them at the appropriate place and retry, but I wasn't sure how to do that without making Clojure depend on JRuby

13:39 headius: yeah there's a backward-compat issue that's hard to deal with

13:40 jweiss: technomancy: i'm following step3 of swank-clojure install ( 3.

13:40 if you want to use a newer version of Clojure than 1.0 you will need to build it yourself and symlink the compiled jar to ~/.swank-clojure/clojure-$VERSION.jar after removing the old version.) i am getting classnotfound on clojure.main. did i need to make the link names exactly the same as the old filenames, even though it's a different ver of clojure?

13:40 headius: i.e. previous jruby folks decided to wrap all incoming java exceptions in our NativeException, rather than just make Java exceptions get JI-wrapped and use that

13:40 duncanm: headius: i had a similar thought the other day - duby syntax + clojure semantics might be useful for those afraid of the lisp syntax

13:40 technomancy: jweiss: it should just use all the .jar files in ~/.swank-clojure if you don't set the classpath yourself.

13:40 headius: duncanm: to be sure, and probably not hard to wire in

13:40 could spike a "clojure_compiler" for duby that does it without much effort

13:41 jweiss: technomancy: hm. do i need to recompile swank-clojure or anything like that?

13:41 technomancy: headius: yeah, tom was telling me that was the Way of the Future.

13:41 headius: technomancy: I think I just had an idea how to get real exceptions to propagate without breaking anything

13:41 we'll just have NativeException#=== return true for Java exceptions

13:41 KirinDave: technomancy: I have a question for you.

13:41 the-kenny: technomancy: Would it be possible to bring swank-clojure-project to use the var swank-clojure-extra-classpaths in addition to the classpaths from the project?

13:41 jweiss: i just renamed the old jar files, appending ".old" and symlinked the new ones (freshly built from master git branch)

13:41 headius: then existing rescue blocks will still work

13:41 hmmm

13:41 KirinDave: technomancy: I'm really curious about hacking on your build project now that i've spent so much time with it. But... I was curious...

13:42 technomancy: Would you be opposed to more direct interaction with clojars during the project invocation?

13:42 technomancy: headius: wow, if that would work, that'd be much cleaner.

13:42 KirinDave: technomancy: E.g., "I think it was... compjure or something. Let's search."

13:43 technomancy: the-kenny: there's an alias set up that is supposed to do that already

13:43 icey: chouser: sometimes I'll see someone mention a quote on twitter (invariably it's someone quoting headius) and it lets me know there's probably an interesting irc conversation going on ;)

13:43 headius: technomancy: yeah, definitely...then we'd just propagate the actual exception throughout

13:43 the-kenny: technomancy: Huh? my repl depends somehow on swank-clojure-extra-classpaths, and it doesn't work if I use swank-clojure-project

13:44 chouser: icey: ah, I see. thanks!

13:44 technomancy: the-kenny: nm; misread you. the idea of swank-clojure-project is that everything is self-contained; if you want to use jars outside the project dir use symlinks

13:44 the-kenny: technomancy: hm.. ok.

13:45 icey: chouser: are you chouser on twitter?

13:45 chouser: icey: no, chrishouser

13:45 technomancy: KirinDave: not sure quite what you mean... which leiningen task(s) would get hooked up to clojars?

13:45 KirinDave: technomancy: Well, a more fancy "new" would be pretty awesome, in my opinion.

13:46 headius: another possible reason to use ror for the front-end is that webapps are messy, stateful, mutable affairs; better to just let rails handle all that mess

13:46 technomancy: KirinDave: oh, so something that can pick from a number of new project templates?

13:46 that'd be nice

13:46 KirinDave: technomancy: Yes. And also maybe even integration with the clojars metadata.

13:47 the-kenny: technomancy: Another question: When do I have to (require 'swank-clojure-autoload) in my .emacs? I couldn't get it to work without copying some from the file to my .emacs.

13:47 KirinDave: Like let's say the project page is tied to a github, you could envision git enabled tasks to pull out submodles as necessary and properly configure the project to build them.

13:47 defn: What are chunked sequences?

13:48 KirinDave: defn: It's an optimisation

13:48 technomancy: the-kenny: that should be handled for you by an elpa install... if you're not using elpa it's more complicated.

13:49 KirinDave: defn: They basically compute the sequence in chunks to amortise the advancement cost over time.

13:49 defn: ooo cljdb!

13:49 KirinDave: ah-ha -- thanks

13:49 the-kenny: technomancy: I don't want to use elpa... I like to have control about such things.

13:49 rhickey: chouser: did you see above: I think you can't pass fn + args, since fn isn't a great identity, so if you just pass error plus current state, it would be easy to return that state or some reset value. Setting a handler can replace putting in internal error log afaic

13:49 KirinDave: defn: rhickey tweeted the link yesterday: http://bit.ly/7pmDgE

13:49 defn: ahhh, thanks again

13:50 back to work...

13:50 technomancy: KirinDave: right now projects can have dev dependencies on leiningen plugins, which would work for tighter integration for everything except new (since new runs without a project in place)

13:50 chouser: rhickey: yes I did thanks.

13:50 technomancy: but we're thinking about adding a user-level config file, so you could have leiningen plugins loaded across the board

13:50 chouser: rhickey: you think it's important to allow the error-fn to change the state of the agent?

13:50 headius: I wish we all had a common set of function interfaces across langs

13:50 technomancy: the-kenny: ok, but if you don't use the supported installer then you're on your own, sorry.

13:50 headius: sigh

13:50 the-kenny: technomancy: hm ok, no problem.

13:50 headius: technomancy: is there a bare "clojure" gem?

13:50 bitbckt: headius: That would ruin all the fun.

13:50 KirinDave: technomancy: Which is why the task would have to be built in.

13:50 the-kenny: It's working fine now.

13:51 KirinDave: technomancy: But after that, things like git assists would be easy to add.

13:51 rhickey: chouser: yes, but if handed the current state, should be no problem to simply return it

13:51 technomancy: headius: not without my wrapper afaik

13:51 cemerick: bitbckt: "bozo bit company" :-D

13:51 bitbckt: cemerick: *sigh*

13:51 chouser: rhickey: ok

13:52 bitbckt: cemerick: I can't express how true that is.

13:52 headius: technomancy: we should release one, so there's a basline gem people can depend on

13:52 cemerick: bitbckt: don't worry, the times, they are a'changin.

13:52 headius: or I need to get off my ass and wire maven support directly into rubygems

13:52 bitbckt: cemerick: I hope so.

13:52 headius: or just clean this up and make it handle dependencies well: http://github.com/jruby/maven_gem

13:53 then you'd just gem install clojure-1.0 and it would fetch from maven

13:58 icey: Does anyone know if anybody is working on a Clojure web framework that uses templates instead of representing HTML in Clojure?

13:59 KirinDave: icey: You can easily use a template agency with compojure.

13:59 chouser: rhickey: changing state means running validators which may in turn cause errors. I guess errors thrown by error-fn directly or from validators can be put in the errors list?

14:00 icey: KirinDave: pardon my ignorance, but what is a template agency?

14:00 KirinDave: icey: I dunno why I wrote agency. I must have had a serious brainfart there.

14:00 ... I am worried now.

14:00 I meant library but I typed agency. :(

14:01 icey: KirinDave: haha okay thanks :D I hit google thinking I had been looking for the wrong thing. Any idea what sort of engines people are using w/ compojure?

14:02 KirinDave: There was one really cool one I saw in here yesterday but I seem to have lost the think.

14:02 Fuck

14:02 What the hell is wrong with me. I'm typing every word but the word I mean. Am I grandpa gummy now?

14:03 cemerick: icey: enlive is great concept, haven't used it in anything significant myself, though.

14:03 KirinDave: icey: I was meaning to try http://clj-me.blogspot.com/2009/01/enlive-yet-another-html-templating.html

14:03 cemerick: just about anything can be wired in, though

14:03 KirinDave: http://github.com/cgrand/enlive/blob/2a15c466048f7e0311243b3d7a669705bbcbe072/src/net/cgrand/enlive_html/example.html

14:04 icey: Hmmm, enlive looks interesting; I might check that out, thanks :D

14:05 KirinDave: Yeah, it looks like a really good way to interact with pages that have very rich javascript.

14:05 icey: KirinDave: You can blame your mental state on the upcoming holidays; that seems to work for me

14:05 KirinDave: You can put in "stock" crap that simply provides sample data for your scripts.

14:05 icey: I wish. I did just get married. I hear that once you get married you get dumber. Something about settling down to have kids.

14:05 icey: KirinDave: that matches my experience with getting married ;)

14:06 I need HTML templates because I will often get completed sites sent to me that just need code added for the functionality, and I don't want to translate everything into Clojure to make it work

14:06 KirinDave: yeah

14:06 Well that whole sexpr-html is a very misguided idea when you're building whole pages.

14:06 It's nice for things like list items.

14:06 * chouser translates everything to .rhtml

14:06 cemerick: I still don't understand the urge to use sexprs instead of HTML.

14:07 KirinDave: cemerick: It's because people hate and/or look down upon HTML.

14:07 cemerick: I'm hoping it's deeper than that -- trying to leverage the power of macros, etc.

14:07 icey: cemerick: I really like them when I'm doing one-off small applications and I just need a couple of forms, for example. I can see everything at once, and use functions for my patterns

14:07 cemerick: Seems like one's looking for a nail in that case, tho.

14:08 chouser: my co-workers were very happy when I provided a way to use JavaScript syntax to build DOM tree for subsequent insertion on the page.

14:08 KirinDave: Right

14:08 For snippets it makes total sense.

14:08 Like, I have strings and a list of strings could easily be a list in html.

14:08 Great.

14:09 But the minute you start trying to make more complex tags it falls apart

14:09 And is less readable and less robust than HTML

14:09 chouser: hmmm

14:09 cemerick: It might be because I used them so much, but I still like JSPs -- super-simple, gets out of your way, gets the job done.

14:09 Avoid putting "real" code in there, of course.

14:09 icey: sexprs are also really nice if your application is composed, depending on prior user actions; I have a survey application that completely changes depending on what's been answered previously

14:09 chouser: Seems to me HTML was designed for marking up text. s-expr's (and json) are lousy for that.

14:10 cemerick: chouser: what do you think of the sexpr js templating lib that popped up a bit ago?

14:10 chouser: but if you're creating a dense tree of small nodes, html/xml gets annoying fast, while s-exprs, json, yaml, etc. do nicely

14:12 hm, seems I wrote about this once.

14:12 heh. old. http://n01se.net/chouser/blog/#blogsd

14:14 cemerick: link?

14:17 cemerick: chouser: yeah, not that I can find it again now. :-/

14:18 chouser: http://github.com/arohner/scriptjure/

14:18 OK, not *so* recent, but new to me. :-P

14:18 djork: is it just me or is the list of announced features for JVM 7 a bit... underwhelming

14:19 cemerick: huh, by our own arohner, even. I didn't even notice at first blush.

14:20 djork: wow, scriptjure sure highlights the similarities between JS/clojure

14:20 it would be interesting to see a return-less version

14:20 i.e. just automatically insert return in tail position

14:21 KirinDave: I wonder if Clojure is ever going to switch from its CL-style macro system to a more scheme-like MBE system.

14:21 It seems like MBE is more in line with the way clojure does method definitions.

14:21 the-kenny: MBE?

14:21 KirinDave: Macro By Example

14:21 Have you see the way PLT-Scheme does macros?

14:22 Very beautiful.

14:22 djork: hmm, I just got used to Clojure's macros

14:22 the-kenny: No I haven't, sorry.

14:22 djork: I never got my head around PLT's

14:22 KirinDave: http://docs.plt-scheme.org/guide/pattern-macros.html

14:22 djork: mostly because the docs are quite dense

14:22 KirinDave: djork: I dunno, PLT Scheme has some of the most approachable documentation anyone has ever had for a lisp.

14:22 djork: oh wow, that' snot bad

14:22 KirinDave: djork: Just read the guide, not the reference.

14:22 the-kenny: Maybe you can implement MBEs with clojure macros :D

14:22 djork: for some reason I remember struggling with it a while back

14:22 ah yes

14:22 it was the reference

14:23 KirinDave: What's so cool about it is that it automagically handles masking.

14:23 So you can just write macros without consideration for variable capture.

14:24 the-kenny: KirinDave: Clojure has auto-gensyms.

14:24 KirinDave: the-kenny: They're still explicit.

14:24 or so the docs suggested?

14:25 the-kenny: Yes, but it's easier than in CL :)

14:25 KirinDave: You need to decide when you want them

14:25 Oh sure.

14:25 And sometimes you need the raw dawg macro

14:25 I wonder if I could write an MBE library for clojure...

14:25 For 95% of all macros, MBE is superior, safer, and almost always clearer.

14:25 djork: go for it

14:26 the-kenny: KirinDave: Just try it :)

14:26 djork: I'm happy with defmacro so far

14:26 but I'm new to macros in general

14:26 the-kenny: If it isn't possible with macros (which i doubt), you can also implement it right in the reader ;)

14:27 KirinDave: the-kenny: It's possible with macros. Although it's best to be integrated into the reader to handle the namespacing issues.

14:27 djork: the-kenny: I think the trick with implementing MBE as a macro is the scope consideration

14:27 technomancy: did #^bytes get added as a type hint specifier, or is that still being worked on?

14:33 cemerick: technomancy: I think it's in there, yeah

14:33 jweiss: anyone here used c.c.logging ? getting it to work at the repl seems to be nontrivial

14:33 chouser: cemerick: ah, for generating js from clojure, I misunderstood you. I haven't used it yet, but do have a project where it might fit. So no real opinion other than it seems like to be filling a real need.

14:33 cemerick: jweiss: it needs a little work -- it binds at compile time

14:33 twbray: ,*command-line-args*

14:33 clojurebot: nil

14:37 cgrand: technomancy: #^bytes exists

14:37 technomancy: cool

14:38 it looks like you can type hint with classes that don't actually exist; that seems pretty strange

14:38 no warnings or anything

14:38 chouser: also with strings!

14:44 twbray: Pardon my extreme stupidity... been working in the REPL for a while, trying to run a script through main, failing. If I say (ns clojure.main) (defn main [args] ... ) in my script, then say java yadda yadda clojure.main my-script.clj, shouldn't that do it?

14:44 Looking at http://clojure.org/repl_and_main

14:46 chouser: twbray: when called from the command line like that, it's just executing everything at the top level. you could add your own (apply main *command-line-args*) to the bottom of the file if you want.

14:47 I think there's another way to get a fn named 'main' called, but I don't remember how.

14:47 twbray: All I really want is to get access to cmd-line args, having trouble getting *command-line-args* to have any values

14:47 technomancy: -main is for building an executable jar

14:48 twbray: There has got to be a way to get a command-line arg into my clojure script :(

14:50 lisppaste8: Chouser pasted "command-line-args, simplest example" at http://paste.lisp.org/display/91038

14:52 twbray: chouser: Thanks. That was my first attempt, must have had some subtle typo.

14:59 drewr: will clojure automatically benefit from Java 7's number underscores?

15:00 cemerick: isn't that just compiler sugar?

15:01 chouser: drewr: I doubt it. cemerick: probably

15:01 there have been proposals for spacers in numbers for Clojure

15:01 drewr: I remember those discussions

15:01 fogus_: What was the final verdict?

15:01 cemerick: I don't see the appeal, but whatever

15:01 drewr: maybe this will help make a decision

15:02 devlinsf: Java 7 is dead. Isn't that why we're here?

15:02 chouser: :-(

15:02 drewr: I think (range 10_000_000) is much nicer than (range 10000000)

15:02 chouser: I like (range 1e7)

15:02 drewr: yeah, I forget about that

15:03 chouser: but of course that doesn't help with 121121521111 or whatever

15:03 of which there are so many in my code

15:03 the-kenny: I think 10_000_000 is very ugly

15:03 ,(identity 10,00)

15:03 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: core$identity

15:03 chouser: comma is whitespace!

15:03 drewr: comma is whitespace, not null space

15:03 chouser: ~comma

15:03 clojurebot: It's greek to me.

15:03 fogus_: I like (range 046113200)

15:04 the-kenny: okay

15:04 chouser: fogus_: noooo...

15:04 duncanm: technomancy: is your site down? i'm having trouble installing SLIME from ELPA

15:04 drewr: fogus_: :-)

15:05 fogus_: chouser: You made the point though... it's not often that you'll see those huge constants except in toy code

15:05 devlinsf: fogus_: I don't get it

15:05 fogus_: ,(count (range 046113200))

15:05 clojurebot: 10000000

15:06 fogus_: devlinsf: ^^^^^

15:06 devlinsf: fogus_: Huh? Is it an overflow?

15:06 chouser: octal :-P

15:06 drewr: devlinsf: not base 10

15:07 devlinsf: Oh, okay

15:07 ,(range 08000)

15:07 clojurebot: Invalid number: 08000

15:07 chouser: read support for octal should look more like #octal:2342

15:07 devlinsf: Got it

15:07 drewr: ,0xfff

15:07 clojurebot: 4095

15:08 drewr: ,0777

15:08 clojurebot: 511

15:08 fogus_: ,(range 010)

15:08 clojurebot: (0 1 2 3 4 5 6 7)

15:09 chouser: ,(+ 1 36rHello)

15:09 clojurebot: 29234653

15:09 fogus_: This is like modern day calculator curse words

15:09 chouser: heh

15:10 devlinsf: chouser: is there a shortcut for 2r1111

15:10 chouser: shorter that "2r"? I don't think so

15:10 devlinsf: Well, something that implied binary

15:11 So it looks special

15:11 chouser: yeah, I don't think so.

15:11 devlinsf: Hmm, okay

15:11 Just the EE in me

15:12 chouser: Looking at the code now. The answer is "no"

15:14 but you can use a capital instead or r or x

15:16 fogus_: Where does the zero-prefix for octal come from anyway? C? Fortran?

15:16 devlinsf: I'd guess C

15:16 chouser: C at least, if not before

15:17 fogus_: I guess my question is what's the rationale?

15:18 chouser: rm, 8r377 is smalltalk

15:18 hrm

15:18 python3 uses 0o377 ...doesn't seem like a good idea to use ohs in numbers

15:18 alexyk: hi guys -- anyone used congomongo?

15:19 devlinsf: fogus: Wikipedia doesn't have anything :(

15:19 fogus_: Wikipedia doesn't have anything :(

15:19 fogus_: Yeah, depending on your font, 0O010 could be a headache to look at in Python

15:20 devlinsf: Yeah, that's where I tried first

15:20 jasapp: alexyk: I use it a bit

15:20 devlinsf: Maybe the 0x is an seembly holdout?

15:20 *Maybe the 0x is an assembly holdout?

15:21 defn`: Easiest, simplest way to get a basic blog set up with clojure syntax highlighting?

15:21 Preferably something that I can just use out of the box without extra config.

15:21 fogus_: defn`: Github?

15:22 defn`: fogus_: ?

15:22 the-kenny: defn`: gist.github.com

15:22 fogus_: defn`: Like this http://github.com/raganwald/homoiconic

15:22 defn`: oh duh, i didn't think of that!

15:22 i was hoping to put it on my domain

15:23 but i could just redirect i guess

15:23 alexyk: jasapp: I'm saying (:use somnium.congomongo) and it can't find it, although the jar is on the path.

15:23 the-kenny: defn`: You can use github-pages :) If you're a premium member, you can set CNAME-Values too.

15:23 chouser: I think I've seen github gists embedded in blog pages

15:24 clojure.org uses a javascript thingy

15:24 fogus_: I embed gists in my blog

15:24 technomancy: defn`: M-x htmlize-region is awesome if you blog from Emacs

15:24 chouser: fogus_: probably where I saw it then. :-)

15:25 duncanm: what's the difference between :use and :require again?

15:25 the-kenny: fogus_, chouser: http://github.com/blog/122-embedded-gists

15:25 fogus_: defn`: I use this cool WP plugin that lets me wrap the code in a tag and if a gist doesn't already exist it creates one and links to that

15:25 Chousuke: embedded gists are not so nice. they require javascript and just *disappear* if you don't have it enabled :P

15:26 it's pretty confusing to read blog posts stating "here's the code" when there's nothing.

15:26 devlinsf: duncanm: use mixes all of the functions into the namespace. require imports them and lets you alias them

15:27 duncanm: require helps avoid collisions. see str-utils2 for an example of a lib that is better reuire'd than use'd

15:27 jasapp: alexyk: is that in the ns macro?

15:27 fogus_: Chousuke: The plugin I use takes care of that... I wish I could remember the name without having to log into my blog admin :(

15:27 alexyk: yeah

15:27 I'm using it outside the macro, can I?

15:29 jasapp: I'm not sure I understand exactly, but if it's outside the ns macro, you want use the function, not use the keyword.

15:29 defn`: fogus_: that is cool

15:30 fogus_: defn`: I use this http://blog.kno.at/tools/highlight-source-pro/

15:30 alexyk: jasapp: ah ok, am very new to clojure :) in ns works

15:30 jasapp: alexyk: and you'll also want somnium.congomongo to be quoted

15:31 alexyk: jasapp: single quote in front, right?

15:31 fogus_: defn`: Whoops, that's not right. I use http://pomoti.com/gist-it

15:32 alexyk: fogus_: "Basically, that problem usually happens with those who ‘programming-bloggers’ are the main activity when not sleeping." :)

15:35 what do people use for SQL? anything prettier than raw jdbc?

15:36 drewr: alexyk: for simple cases, c.c.sql suffices

15:37 chouser: I continue to be intruiged by http://www.gitorious.org/clojureql/

15:37 haven't actually used it thought

15:37 though

15:37 I'm in nosql land now

15:37 drewr: chouser: +1

15:37 cql is really good, I just haven't had time to write a mssql backend

15:38 alexyk: drewr: who cares about MS :) postgres is all I need

15:39 chouser: I have an abstract system where I try different backends. Tried BDB and Mongo, but Postgres will do too.

15:40 chouser: if you're not writing sql-like queries in your app code, clojureql is probably the wrong level

15:40 fogus_: chouser: Which nosql?

15:40 chouser: writing our own :-)

15:40 drewr: nice

15:41 fogus_: NIH! ;-)

15:41 chouser: I was skeptical, but came around. I think we have sufficiently compelling reasons for not building on anything that's out there right now.

15:41 fogus_: chouser: In clojure?

15:42 drewr: all the nosql tech is so young

15:42 I've been impressed with cassandra but it's not quite there yet for our needs

15:42 chouser: fogus_: clojure, C++, Java plus some jruby for testing, a custom query language, and no doubt eventually php bindings.

15:45 somnium: alexyk: I've used it :)

15:46 alexyk: somnium: works nicely! :)

15:46 none of the ORM headaches from Scala... since not much types enforcement in here :)

15:47 rhickey: chouser: sorry, away for a bit - yes, if value returned by error-handler fails validation just put in normal error list

15:47 somnium: alexyk: yes, json format fits clojure's structures well. unfortunately I can't use it for my current project :( but I'm glad its useful to some people

15:49 alexyk: somnium: there's a competing project on github, by gilbertl, did you see that?

15:49 somnium: I'm not sure that we're competing :) We both use an open source language to wrap an open source driver for an open source database

15:50 alexyk: somnium: you are competing for users! :)

15:50 chouser: amazing amount of complexity packed in here. :-/ when to skip releasePendingSends()?

15:51 alexyk: ok, alternative... any idea of the differences?

15:53 chouser: skip releasePendingSends() even if the error was handled by an error-fn, right?

15:54 rhickey: hmmm

15:54 somnium: alexyk: I did look at it, I suspect its a bit slow, since it traverses maps with clojure.walk to handle keywords. Though I kind of cheated and wrote a little java class to do that.

15:54 duncanm: technomancy: i keep on seeing 'failed to download clojure jars' when i run M-x slime on a fresh machine

15:54 alexyk: somnium: you have a better readme, so I picked yours. :)

15:54 somnium: :)

15:55 chouser: if the action throws something, you'd be surprised to find some 'sends' go out but not others, wouldn't you?

15:55 alexyk: somnium: I have a 70 GB database with 100M twits, let's see how you can handle *that* :)

15:56 rhickey: chouser: which went out?

15:56 chouser: though if a watcher fails, you might be surprised if any sends are held back.

15:56 somnium: alexyk: it can create IPersistentMaps quickly, but I guess you'll run out of ram pretty quickly with that load :)

15:56 alexyk: somnium: is there any tuning I must/can do? I have a 64 GB RAM box for this job

15:57 chouser: if your action does: send 1, throw, send 2 ...1 will go out if released, but 2 would never have been queued

15:57 somnium: alexyk: mongo doesn't support concurrent reads until 1.4, + deftype and defprotocol make it even faster, so I'm kind of waiting for the next release

15:57 alexyk: 35 GB are data, 35 GB indexes

15:57 somnium: you mean 1.1.4?

15:57 somnium: alexyk: yes 1.1.4

15:57 alexyk: what are deftype and defprotocol?

15:58 somnium: alexyk: new performance enhancing clojure features, as for mongo, I guess you'll want to shard it, but the driver won't help with concurrency right now :(

15:58 kotarak: _ato: you are the clojars guy, right?

15:59 alexyk: somnium: java driver or clojure wrapper?

16:00 rhickey: chouser: ah, ok, so, never queued, not really missed. It seems there could be no correct default policy there, but currently we eat on error, so let's keep that. I guess a composite return could tell us what to do...

16:01 somnium: alexyk: well, the clojure wrapper is very threadsafe, but to get a performance boost from concurrency you'll need a connection pool to n databases

16:01 I would check the java driver to see if it offers any support for that

16:01 chouser: a composite return could also allow nil to mean no change to agent value, which would be handy for many minimal examples.

16:01 alexyk: somnium: ok

16:02 rhickey: chouser: how so? nil could be the new value

16:03 I'm not sure I follow the problem with returning what you are handed

16:03 do you want to avoid the validation etc?

16:04 chouser: No, it's not a big problem, but I expect a lot of simple cases to end up with error fns like #(do (prn %2) %1) instead of just prn

16:04 real-world code will have more complex handlers and returning an explicit new value won't feel awkward there

16:05 technomancy: kotarak: _ato is on aussie time IIRC, but I'm working on the project with him

16:05 chouser: but I thought you were suggesting error-fn return {:pending-sends :release, :new-value foo} or something, in which case nil could mean no change.

16:05 rhickey: yeah, I wouldn't worry, people will write one handler they like and reuse

16:06 chouser: ok

16:06 defn`: poor s_e_t_h and his failed clojure blog post

16:06 kotarak: technomancy: ah. Ok. Are there special requirements on the filenames copied? specifically: does the pom need to be called "pom.xml" or could it also by "foobar-1.2.0.pom.xml"?

16:06 rhickey: chouser: nil for the entire return? would that relase sends?

16:07 chouser: I ... uh, I dunno. I guess I would think not.

16:07 technomancy: kotarak: I don't see "pom.xml" hardcoded in, so I suspect your longer version would work. give it a try.

16:08 ordnungswidrig: clojure compiler error message is driving me nuts. the file with the namespace a.b must go in /a/b.clj right?

16:08 chouser: releasing sends seems like something you want only when things are working "normally"

16:08 kotarak: technomancy: ok, will try.

16:08 chouser: an action can always try/catch itself if it's expecting errors

16:09 ordnungswidrig: hmm, are dashes allowed in ns names? a-b.c-d ??

16:09 chouser: ordnungswidrig: yes, but are _ in file and directory names

16:09 rhickey: chouser: yeah, until you think about the exception conveying enough info for the handler to fabricate a valid work step. The biggest problem is not knowing how far through any sends you've gotten, as you mentioned before

16:09 ordnungswidrig: chouser: thanks!

16:10 rhickey: really, any action that sends needs to have its own handler, even if it ends up rethrowing

16:10 chouser: how do erlang and scala do this?

16:10 rhickey: so, let's just not release, and have a single return of new state - you can do an identity test to avoid validation/watchers

16:11 chouser: erlang is fail == die

16:11 chouser: oh

16:11 I assume neither hold "sends" at all?

16:11 rhickey: with death notification and restarts

16:12 chouser: we do notifyWatches on an action, even with the value is unchanged. You want to withhold notification if the error-fn makes no change?

16:12 rhickey: so you just have this chain of death notification links

16:12 ordnungswidrig: Anybody seen this with slime/swank: error in process filter: Symbol's function definition is void: swank-clojure-slime-mode-hook

16:13 chouser: also, is it really worth it to you to have me write this when all I do is pester you with every little decision. ;-)

16:13 rhickey: that has toggled back and forth a few times, note the boolean return on setState

16:13 ordnungswidrig: I'm using slime from elpa and maven swank-clojure 1.0-SNAPSHOT

16:14 chouser: rhickey: yeah, I noticed.

16:14 rhickey: I think it was your use case that swapped it last time :)

16:15 chouser: :-)

16:15 rhickey: a countdown watcher or something

16:15 technomancy: ordnungswidrig: did you install swank-clojure or just slime?

16:16 (in elpa)

16:16 ordnungswidrig: both

16:16 rhickey: in some sense, a watcher is like a permanent pendingSend, so they should have the same policy

16:16 ordnungswidrig: I suppose elpa takes precedence on debians slime

16:16 chouser: except they happen synchronously. But yeah, I definitely see your point.

16:17 technomancy: never used debian's slime; they could be conflicting

16:17 hiredman: woa

16:17 technomancy: you've seen javagems?

16:17 rhickey: so, no watchers on identical state

16:17 chouser: it seems a bit odd that an error-fn could change the state of an agent because a watcher threw something

16:17 ordnungswidrig: technomancy: I think it an outdated swank-clojure that maven is using. I try starting the repl by slime

16:18 rhickey: I'm happy having watcher errors go into the normal list

16:18 really, a watcher that can throw is bogus

16:18 chouser: my main complaint about the normal list is how it poisons the agent

16:18 yes

16:18 rhickey: but, I'm sure people want to route all problems to a single place

16:19 chouser: but routing errors seems a bit different than fixing up an agent state

16:19 rhickey: or there could be a watcher-error-handler

16:20 ordnungswidrig: technomancy: strange. slime starts a clojure repl but swank-clojure-project fails on missing clojure libs

16:21 chouser: wather-error-handler return values would be ignored instead of updating the agent

16:21 rhickey: that's probably easier architecturally for us, and makes more sense = would be passed exception ony, ignored return

16:21 chouser: but could default to be the same as the normal error-fn?

16:21 rhickey: no

16:21 different args

16:22 chouser: no state

16:22 rhickey: right

16:23 in fact, if no watcher error handler provided - I'd prefer to ignore them

16:23 chouser: ok!

16:23 rhickey: couldn't ignore before because there would be no way to find out about the failures

16:23 ordnungswidrig: technomancy: got it. had to run mvn dependency:copy-dependencies first :-)

16:24 rhickey: now user choice

16:24 chouser: right

16:24 we can consider changing the default for action errors to match at some later point. :-)

16:25 rhickey: chouser: well, there might be user code already using agent-errors

16:25 chouser: right

16:25 breaking change. not for now.

16:25 rhickey: right

16:25 chouser: :error-handler is better than :error-callback

16:25 rhickey: yes

16:25 kotarak: technomancy: it works! the name is not interesting. clojuresque 1.1.0 pushed to clojars. :) (formerly known as clj-gradle)

16:26 duncanm: technomancy: sigh, am i doing something stupid? M-x slime isn't workign for me ;-P

16:27 chouser: setWatcherErrorHandler in ARef instead of Agent?

16:27 ordnungswidrig: duncanm: what's your error?

16:27 duncanm: ordnungswidrig: failed to download clojure jars

16:28 oh doh

16:28 now it's working

16:28 ordnungswidrig: duncanm: *g*

16:28 rhickey: chouser: yes, and IRef

16:28 actually, no

16:29 this is just an async problem

16:29 all sync things can just let exceptions flow out

16:29 so, on Agent only

16:30 chouser: yes, ok.

16:32 technomancy: hiredman: yeah... the authors emailed me. it's an interesting project, but I don't think it's that relevant to clojure.

16:32 chouser: validator throws: error-fn is called, pending sends are dropped.

16:33 rhickey: chouser: sounds right

16:33 chouser: but ... watchers are still triggered if error-fn changes the state.

16:33 krumholt__: why does (eval (fn [] "test")) not yield "test" as a result? instead it returns what i would expect from (eval '(fn [] "test")). could someone explain that to me?

16:35 chouser: and sends queued by error-fns and by watchers triggered by error-fns are ... released? disallowed!? this all feels a bit wrong.

16:35 somnium: krumholt__: eval != invoke, try ((eval '(fn [] :foo)))

16:36 chouser: krumholt__: (fn ...) returns a value, a function. Eval'ing a value just returns the value.

16:37 krumholt__: or: (eval '((fn [] :foo)))

16:37 krumholt__: oh ok thanks. a function is a value eval returns that value makes sense thanks

16:37 rhickey: chouser: let's break it down

16:38 the reason to allow the handler to 'fix' the state is because re-queueing a new action will change the (possibly important) order

16:38 chouser: not sure what that means, but error-fn inserting a state change feels like the source of complexity to me

16:38 heh

16:39 rhickey: pending sends may be an incomplete set, there's no way to know, so if your action sends and might throw, you should have your own internal handling

16:39 chouser: ok, yes. There's no better way to indicate which sends you want to do than your own appropriately grouped try/catches

16:40 in the action

16:40 rhickey: so pending sends have to be chucked, but the one case you couldn't self-handle is validation failure

16:41 chouser: validators can't send because they're supposed to be pure

16:41 so no pending issue there

16:41 somnium: question to vimclojure users: is there a recommended way to manage the classpath for standard ./src ./lib ./build project structure?

16:42 kotarak: somnium: the launcher adheres to CLASSPATH env var, the new one also reads a .clojure file in the current directory.

16:42 chouser: does the same apply then to error-fn? can be a pure fn of the state and exception but shouldn't throw or send?

16:43 rhickey: validation failure is a programming error, so finding out about about it is most important

16:43 kotarak: somnium: you can also set CLOJURE_EXT to load jars in that directory

16:43 rhickey: error-fns aren't pure, in that they may frequently do queue I/O

16:44 but people use agents as queues...

16:44 chouser: is an error-fixer different than an error-queuer?

16:44 rhickey: handler implies both

16:44 chouser: yes I know

16:45 I'm wondering if that's an bad conflation

16:45 ikitat: I'm at a loss how to make use of clojure.test/use-fixtures http://paste.pocoo.org/show/152745/ gives me "Unable to resolve symbol: x in this contex"

16:46 rhickey: I think if it is clear - "I fixed this" vs "it never happened", then other decisions become easier

16:46 hiredman: ikitat: I don't know anything about test-is

16:46 but that looks like an issue of lexical v. dynamic scope

16:46 chouser: rhickey: ok, yes.

16:47 rhickey: I fixed it - all messages go out, it never happened - none do

16:47 chouser: yes

16:47 somnium: kotarak: where can I read on .clojure file in the current dir? I was thinking of writing a alternate bash script similar to swank-clojure-project (locate build.xml/pom.xml and build classpath).

16:47 hiredman: but then again, I don't know what I am talking about

16:47 somnium: kotarak: btw, mine breaks if I open a random .clj file not already in CLASSPATH, so maybe I have something configured wrong

16:48 rhickey: so, state identity is too weak

16:48 chouser: do, do you indicate which you're doing by returning an = value, or is that too much magic

16:48 yeah

16:48 rhickey: or at least unclear

16:48 kotarak: somnium: it's not a bug, it's a feature. You can turn it off in the latest bleeding-edge.

16:48 chouser: if you didn't fix it, you have no new value to provide

16:49 ikitat: hiredman, yeah, I figured that it's a scoping issue, the documentation for test-is isn't clear (to me) how this can be used

16:49 somnium: kotarak: I'm not qualified to have an opinion on bug/feature status at this point :) I'll try the bleeding edge, does it work with new branch?

16:49 chouser: I guess a single handler might need to look at the exception to know what it's doing, so providing separate fixer-fn from logger-fn is bad

16:49 rhickey: but as your use case indicated, sometimes a valid work step doesn't change the state

16:49 kotarak: somnium: yes, but the highlighting is not 100% up-to-date.

16:50 hiredman: ,(doc clojure.test/user-fixtures)

16:50 clojurebot: Gabh mo leithscéal?

16:50 kotarak: somnium: this will fix your problem: http://bitbucket.org/kotarak/vimclojure/changeset/f80ecd0532b7/

16:50 rhickey: I think return the exception to indicate 'didn't happen', else state and all messages go

16:50 hiredman: ,(doc clojure.test/use-fixtures)

16:50 clojurebot: No entiendo

16:50 chouser: hm!! return the exception.

16:51 rhickey: acts as an implicit notFixed flag

16:51 chouser: just too unlikely that someone wants to store that particular exception in the agent? better than re-throwing it?

16:51 kotarak: somnium: ad parsing poms: I don't see this is as the responsibility of vc. The user has to setup his classpath with the ng-server. This can for example done via some target for maven, ant or gradle.

16:51 somnium: parsing poms is a nightmare with vim.

16:51 rhickey: we don't want rethrow that's for sure, it's still handled

16:51 just not fixed

16:52 chouser: treat that particular exception different from any other exception then?

16:52 rhickey: ?

16:53 chouser: if the error-fn returns an exception other than the one passed in, that becomes the new value of the agent.

16:53 kotarak: somnium: as for the .clojure, I must confess, that I haven't pushed the changeset, yet. sorry. My mistake.

16:53 rhickey: we could have a return-this-value-if-not-fixed, but seems a bit much

16:53 chouser: yes, I can see that.

16:53 hiredman: ikitat: it looks like a fixture is just a normal function

16:53 ikitat: the only usage of use-fixtures in clojure-contrib seems to modify *ns* and that is the one and only case I can find.

16:53 somnium: kotarak: ah ok, well I threw together an alternative nailgun launcher that just exports command line args to classpath, and that seemed to work

16:53 hiredman: so you will need to setup x as a dynamically rebound var

16:53 rhickey: the other option is the agent itself

16:53 chouser: heh

16:54 rhickey: but people get so confused already between the agent and its state

16:54 hiredman: ikitat: http://clojure.org/vars

16:54 chouser: I'm ok with the exception itself, esp. for an experimental feature

16:54 rhickey: what is getting passed - the agent or its state?

16:55 somnium: kotarak: oh, my idea wasn't to parse .pom, just find it, and then add ./src ./lib etc to classpath, then launch nailgun, for convenience

16:56 chouser: seems like if you've got an agent managing exceptions as values *and* your actions throw exceptions *and* you've got an error-fn *and* you want to fix up the error, well, you already used up all your grace.

16:56 rhickey: patch in assemble passes agent to error-fn, but I think that's wrong, should be state.

16:57 in assembla

16:57 rhickey: it's not exceptions as values, its the identical exception that was passed to the handler, not by type at all

16:57 chouser: yes

16:57 kotarak: somnium: ah. Ok. I just have CLASSPATH=src:classes CLOJURE_EXT=lib and I start the ng server from the project root. Universally working for all my projects. :)

16:57 rhickey: so unless the agent is going to use that specific exception object as its state...

16:58 chouser: right

16:58 loony

16:58 rhickey: chouser: this was a simpler idea when it was to be a queue

16:58 no question about the activity of the handler itself

16:59 for instance, we're still not good if the handler wants to send the fix as a new action

16:59 chouser: ok, and watchers aren't fired until after the error-fn, and only if error-fn doesn't return the sentinel

17:00 the handler can either send (if it wants it queue at the end) or do an action directly, can't it?

17:00 ikitat: hiredman: it seems the right thing to do is (def x) (def y) (use-fixtures :each ... (binding [x 2 y 3] ... ) I was hoping to have a way to not bleed x and y into the namespace

17:00 rhickey: chouser: a reentrant send? where does it go?

17:01 somnium: kotarak: ok, that is simpler. thanks

17:01 Anniepoo: hmm... ok, beginner question

17:02 chouser: if error-fn does a send and returns a fixed-up value, all the actions's queued sends and the error-fns sends all get released, don't they?

17:02 rhickey: it will be in pending sends, which aren't going out since not fixed

17:02 chouser: oh, you're saying if error-fn wants to send but not fix

17:02 bleh

17:02 rhickey: I guess it would have to know to return the existing state

17:03 also, handed only the state, to whom does it send?

17:10 ordnungswidrig: I have lengthy call of ((-> f wrap1 wrap2 wrap3 wrap4) arg) where wrap* are higher order functions that wrap a given function. How can I trace invokations of the wrappers easily?

17:12 hiredman: (doto prn)

17:12 chouser: rhickey: *agent* since we're in-thread

17:16 ordnungswidrig: hiredman: say how?

17:17 rhickey: chouser: it seems like there are more facets - like would people still want to be able to neuter the agent for further actions? what about other things in its queue

17:17 hiredman: ordnungswidrig: or something like that

17:18 ordnungswidrig: *g* I'll try

17:18 hiredman: ((fn [x] #(doto (x) prn)))

17:19 ,(-> p ((partial partial inc)) ((fn [x] #(doto (x) prn))))

17:19 clojurebot: java.lang.Exception: Unable to resolve symbol: p in this context

17:19 hiredman: ,(-> 1 ((partial partial inc)) ((fn [x] #(doto (x) prn))))

17:19 clojurebot: #<sandbox$eval__5995$fn__5997$fn__5999 sandbox$eval__5995$fn__5997$fn__5999@15fc68a>

17:19 hiredman: ,((-> 1 ((partial partial inc)) ((fn [x] #(doto (x) prn)))))

17:19 clojurebot: 2

17:19 2

17:20 rhickey: also, if you 'fix' in order to send a true fixing action, other messages and the watchers will go out

17:22 michaeljaaka: hi, how to easily make passing parameters to function by symbols?

17:22 I have looked into core.clj

17:22 rhickey: in a queue model, there'd be no immediate fixing, and thus no sends at all, but we'd have to send the agent itself since dequeuing on another thread

17:22 ordnungswidrig: hiredman: thanks.

17:23 michaeljaaka: and found something like (defn me[ & args] (let [ x (apply hash-map args)] ... and later (:sym x)

17:23 is it ok?

17:23 or is there any easier way

17:24 btw. I was activly writing to clojure google group but my last two post didn't appear - am I banned there, spamming there or something?

17:25 hiredman: michaeljaaka: you can use straight up map destructuring

17:25 ~destructuring

17:25 clojurebot: destructuring is http://clojure.org/special_forms#let

17:27 michaeljaaka: ok, I will try it again, last time when was trying to play with function parameters nothing worked for me ;(

17:34 "Clojure supports abstract structural binding, often called destructuring, in let binding lists, fn parameter lists,"

17:34 (defn testfun[ & a :as e ] (println (:dom a)))

17:35 expressions given in example doesn't work for fn parameter lists

17:35 hiredman: michaeljaaka: then read the example again

17:36 michaeljaaka: ok :) (note: I understand examples for let binding)

17:36 djork: michaeljaaka: let/fn have the same destructuring rules

17:37 hiredman: michaeljaaka: you are missing en tire set of []

17:38 so obviously you did not read the example closely enough

17:39 michaeljaaka: hmmm it is obvious that for let

17:39 I have to pass second []

17:39 djork: ,((fn [[a b & c :as d]] (println a b c d)) [:foo :bar: bat :baz])

17:39 clojurebot: Invalid token: :bar:

17:39 michaeljaaka: which initializes left form

17:39 djork: oops hah

17:39 devlinsf: Hey, how do I create fields in a gen-class?

17:39 djork: ,((fn [[a b & c :as d]] (println a b c d)) [:foo :bar bat :baz])

17:39 clojurebot: java.lang.Exception: Unable to resolve symbol: bat in this context

17:39 djork: I fail it

17:39 ,((fn [[a b & c :as d]] (println a b c d)) [:foo :bar :bat :baz])

17:39 clojurebot: :foo :bar (:bat :baz) [:foo :bar :bat :baz]

17:40 alexyk: somnium: ping

17:40 djork: michaeljaaka: the rules for let and fn bindings are the same

17:40 alexyk: I get integers back from json as 2.3275269E7, how can I convert them back to ints?

17:41 do we have longs, too?

17:41 michaeljaaka: yes, I have noticed now

17:41 that I was missing double []

17:41 [[ all goes here ]]

17:42 somnium: alexyk: hi

17:43 alexyk: somnium: so I'm wondering about getting back ints and longs from json ^^

17:43 from mongo

17:43 although it looks like mongo returns floats

17:44 how in clojure do you check the type of x?

17:44 devlinsf: (class x)

17:44 alexyk: yep

17:44 devlinsf: ,(class {})

17:44 clojurebot: clojure.lang.PersistentArrayMap

17:44 devlinsf: Ooops

17:45 alexyk: so if I do (def x <very long int>) will it make it long?

17:46 I see if I do (def x (long <very long int>)) then it does

17:46 the-kenny: ,(class (bigdec 1e100))

17:46 clojurebot: java.math.BigDecimal

17:46 hiredman: (class 1e100M)

17:46 ,(class 1e100M)

17:46 clojurebot: java.math.BigDecimal

17:47 alexyk: I just care for long and int for now :)

17:47 (long 2.173617511E9)

17:47 ,(long 2.173617511E9)

17:47 clojurebot: 2173617511

17:47 alexyk: ,(int 2.173617511E9)

17:47 clojurebot: 2147483647

17:48 alexyk: see wha'am sayin'?

17:48 I get back floats from JSON and need to make them either int or long again

17:48 and I don't want to waste bits

17:48 I guess I'll just use longs for the long ones :)

17:49 somnium: alexyk: I'm not sure, I just tried a test and it came back as expected

17:49 alexyk: somnium: do you see integrals? I have floats for twit ids and user ids

17:49 :id 2.173617511E9, ...

17:50 somnium: -> (insert :nums {:x (int 1)})

17:50 alexyk: ah, right, you do insert via clojure. I've used mongoimport.

17:50 And it made all numbers floating-point.

17:50 somnium: ok, so not my fault I hope :)

17:50 alexyk: somnium: you're fine :)

17:51 I just wonder if you tried mongoimport-ed json

17:51 hiredman: :|

17:51 best not to be doing float -> int/long conversions

17:52 alexyk: hiredman: well, it's a cheap way to dodge the question for mongo, I guess. All the digits are there, at least.

17:52 hiredman: :(

17:52 somnium: hmm, java.lang.BigDecimals do get converted to doubles though

17:53 makes me want to rewrite the encoders in clojure even more

17:53 alexyk: somnium: what do defprotocol and deftype do which would speed it up?

17:53 somnium: I've actually taken to using strings and then (read-string) in clojure for sensitive numbers

17:53 ordnungswidrig: Is there a function to flatten nested lists? Or sth to convert sth to a one-element-list unless it's a list?

17:54 somnium: alexyk: check assembla and lots of discussion in the logs here and the mailing list

17:54 alexyk: somnium: ok :)

17:56 michaeljaaka: ,(defn me[ { :keys [ one two ] } m] (println (:one m)))(me :one 2 :two 3 )

17:56 clojurebot: DENIED

17:56 michaeljaaka: ,(defn me[ { :keys [ one two ] } m] (println (:one m)))

17:56 clojurebot: DENIED

17:57 ordnungswidrig: michaeljaaka: you must not use defn

17:57 michaeljaaka: ok :) I noticed :)

17:57 ,(fn[ { :keys [ one two ] } m] (println (:one m)))(me :one 2 :two 3 )

17:57 clojurebot: #<sandbox$eval__6052$fn__6055 sandbox$eval__6052$fn__6055@1655d7e>

17:58 michaeljaaka: ,((fn[ { :keys [ one two ] } m] (println (:one m)))(me :one 2 :two 3 ))

17:58 clojurebot: java.lang.Exception: Unable to resolve symbol: me in this context

17:58 michaeljaaka: ,((fn[ { :keys [ one two ] } m] (println (:one m)))( :one 2 :two 3 ))

17:58 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to keyword: :one

18:00 michaeljaaka: why this is wrong?

18:01 hiredman: (:one 2 :two 3)

18:01 ordnungswidrig: michaeljaaka: the form ( :one 2 :two 3)

18:01 michaeljaaka: how I should def fun so I have use (myfun :one 2 :two 3)

18:01 I don't want to play with clojurebot (ieave him alone)

18:02 I want just to write one stupid function :( I almost done writing cool program and ended with many args

18:02 and wanted to pass them with symbols

18:02 to make it more readable

18:04 somnium: ,(-> {:one 1} ((fn [{:keys [one]}] (println "one is" one))))

18:04 clojurebot: one is 1

18:05 spuz: Hello, all, I've written an article about how I went about optimising my Clojure fractal renderer: http://developmentjungle.wordpress.com/2009/11/24/optimising-mandelbrot/

18:05 michaeljaaka: somnium: it is cool

18:06 spuz: It's most likely that I'm still doing newbie things so any and all feedback is very welcome!

18:06 michaeljaaka: but how to call it in terms of usage (myfun :one 1 :two 2)

18:06 etc.

18:07 somnium: michaeljaaka: easiest would be to use defnk in clojure.contrib.def

18:07 michaeljaaka: somnium: anyways thanks, you explained how to use symboled binding

18:07 oh, so destructuring doesn't help here

18:07 just I wanted to know that

18:07 somnium: it does, defnk is a macro that destructures for you

18:08 hiredman: I wish people would just use map destructuring

18:08 somnium: you have to do [arg1 ... argn & kwargs]

18:08 hiredman: intead of whatever macros, or apply hash-map

18:08 instead

18:09 michaeljaaka: ohh, so by default hash-map is a pure solution

18:09 just wanted to know that

18:09 apply on hash-map

18:09 somnium: hiredman: people like sugar?

18:09 hiredman: michaeljaaka: no!

18:09 apply hash-map is horrible

18:10 ,((fn [{:keys one}] one) {:one 1})

18:10 clojurebot: java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol

18:10 hiredman: ,((fn [{:keys [one]}] one) {:one 1})

18:10 clojurebot: 1

18:10 hiredman: :P

18:10 somnium: hiredman: the nicest thing about defnk is the dryness, default args and automatic symbols in ~@

18:10 michaeljaaka: but is used in core.clj

18:10 i like to learn by example

18:11 hiredman: :|

18:11 spuz: looks nice

18:11 michaeljaaka: ,( (fn[ { :keys [ one two ] } m] (println one)) [ :one 2 :two 3] )

18:11 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: sandbox$eval--6103$fn

18:11 michaeljaaka: doesn't work

18:12 hiredman: for many many reasons

18:12 michaeljaaka: I think you should become more familar with more basic things before you start with destructuring

18:13 michaeljaaka: well for example?

18:13 hiredman: for example, [:one 2 :two 3] is a vector

18:14 ordnungswidrig: spuz: nice post.

18:14 hiredman: the fn you created there takes two args, but you only passing it a single vector

18:14 even if the fn took one arg, you trying to do map destructuring on a vector

18:15 spuz: hiredman: thanks, I think the main interesting part is digging into Clojure's internals with VisualVM. Of course I'm not an expert but I thought it would be useful to show my findings

18:16 hiredman: spuz: yeah, exploring clojure's call tree++

18:17 michaeljaaka: ok

18:19 I will just use

18:19 ,((fn[ & a ] (let [ b (apply (hash-map) a) ] :one b )) :one 2)

18:19 clojurebot: 2

18:19 ordnungswidrig: good night everyone

18:19 michaeljaaka: bye!

18:19 hiredman: michaeljaaka: :|

18:19 kzar: <h1>I wonder what happens to the logs</h1></body></html>

18:19 hiredman: (hash-map) is a bug there

18:20 michaeljaaka: so it is in core.clj :)

18:20 hiredman: no

18:20 the idiom is (apply hash-map …

18:20 not (apply (hash-map) …

18:20 seriously

18:21 michaeljaaka: ah

18:21 ok

18:21 hiredman: you need more practice just reading and understanding clojure code

18:21 michaeljaaka: in core.clj is hash-map not (hash-map)

18:21 hiredman: I would suggest sitting down with project euler or similar

18:21 michaeljaaka: yeah, practicing :) just writing google map reduce in clojure

18:21 almost done ;)

18:22 hiredman: don't worry about destructuring or keyword args till you can read and write code

18:22 michaeljaaka: I can almost guarantee it will be full of bugs if your interactions with clojurebot are a representative sample

18:22 michaeljaaka: with true distribution between machines

18:23 no problem ;) I'm just learning language, often just asking and making stupid questions

18:23 but finally gots alwasy this "oh this is it"

18:24 hiredman: java.lang.IllegalStateException: case already refers to: #'clojure.core/case in namespace: ring.jetty (jetty.clj:1)

18:24 grrrr

18:26 _ato: michaeljaaka: btw, something I've noticed with your code is the spacing. Normal Clojure style is to do: (defn [arg1 arg2] ...) rather than (defn[ arg1 arg2 ] ...) which you seem to be doing. Not a huge deal but if you get used to the same style everyone else uses than it will be easier for you to read their code and for them to read your code. :-)

18:27 michaeljaaka: yeah, I must change it, the same is with writing doc for function, I need to learn writing doc before fn binding

18:27 fn params

18:27 the-kenny: Are there some "coding conventions" for clojure like for Common Lisp?

18:31 KirinDave1: How does one go about converting a set to a list?

18:31 _ato: the-kenny: not specific clojure ones AFAIK. The conventional style is basically the same as Lisp/Scheme style though: http://mumble.net/~campbell/scheme/style.txt

18:31 ,(seq #{1 2 3})

18:31 clojurebot: (1 2 3)

18:32 KirinDave1: Ah, I see.

18:32 the-kenny: _ato: Yeah, I know the conventions for Lisp, but I think Clojure needs some improvements (hashmaps, for example)

18:32 _ato: KirinDave1: ^

18:32 the-kenny: Maybe I'll start a page in the Wiki

18:32 :)

18:33 _ato: the-kenny: good idea. :-) Do you mean either breaking the line or using commas with hashmaps: {:k1 :v1, :k2 :v2} to pair keys and values?

18:35 the-kenny: _ato: Yeah, and also how to write and indent hashmaps with one element per line.. clojure-mode seems to have problems with "{\n:foo 42\n}" so I'm using "{:foo 42\n:bar 23} currently.

18:35 I'm interested in what other people think and use

18:36 Chousuke: I think {:foo 'bar\n :zonk ...} is the most common

18:36 generally, you don't separate the opening bracket from the first item

18:37 _ato: yeah, I tend to treat () [] {} #{} etc all the same way. no whitespace or newlines at the start or end

18:37 Chousuke: some people seem to like writing function definitions like (defn foo[params] ...) but I think that's just misleading :)

18:37 it makes foo[bar] look like some kind of special syntax

18:38 the-kenny: Yes, it reminds me of C++ or Java.

18:40 KirinDave1: ,(isa? #"" java.util.regex.Pattern)

18:40 clojurebot: false

18:41 KirinDave1: (class #"")

18:41 ,(class #"")

18:41 clojurebot: java.util.regex.Pattern

18:41 KirinDave1: So uh, how do I know if I have a regex?

18:41 Chousuke: heh, that lisp style guide says to avoid point-free style :P

18:41 _ato: ,(instance? #"" java.util.regex.Pattern)

18:41 clojurebot: java.lang.ClassCastException: java.util.regex.Pattern cannot be cast to java.lang.Class

18:42 _ato: did I get backwards

18:42 ,(instance? java.util.regex.Pattern #"")

18:42 clojurebot: true

18:42 KirinDave1: Ahh

18:42 Yeah I guess that's it then.

18:42 Weird, I thought that isa? did that too.

18:42 _ato: ,(isa? java.util.regex.Pattern #"")

18:42 clojurebot: false

18:44 _ato: I agree with generally avoiding point free style. I don't mind the occasionally partial, or comp with just two functions in it, but if you chain together a whole line of comps and partials it's really hard to understand what's going on

18:45 Chousuke: the problem is made worse by the fact that point-free style in clojure is just verbose :P

18:51 KirinDave1: :\

18:51 The most awkward part of learning a new language is in those first concrete modules you write and you go ":\ Man I wrote this the wrong way."

18:52 tomoj: is it evil to rely on hashCode for vectors being consistent across JVM executions?

18:53 Chousuke: yes?

18:54 IIRC the contract for hashCode specifically states that, but I'm not sure.

18:54 tomoj: yeah the contract specifically states that it doesn't need to be consistent, but it seems that it is for vectors

18:55 Chousuke: That seems very likely to break.

18:56 tomoj: guess i can prn and hash that string.. hmm

18:58 hiredman: hmmm

18:58 actually

18:59 technomancy: clojurebot: style is http://mumble.net/~campbell/scheme/style.txt

18:59 clojurebot: Ack. Ack.

19:00 technomancy: hiredman: we're coming up on clojurebot's first birthday soon, aren't we?

19:02 hiredman: clojurebot: if you where a super hero what would your origin story be?

19:03 long sentences like that peg the fuzzer hard

19:03 technomancy: is it still thinking?

19:03 hiredman: yep

19:04 somnium: is he smart enough for s/where/were?

19:04 hiredman: java's cpu time is falling

19:04 huh

19:04 out of heap space

19:04 :(

19:05 the-kenny: :(

19:05 hiredman: clojurebot: your origin story?

19:05 clojurebot: http://clojure-log.n01se.net/date/2008-11-21.html#13:04

19:05 hiredman: huh

19:05 technomancy: oh, my clojure birthday was last week!

19:06 I thought it was this week. time to cancel the party. =(

19:06 the-kenny: If clojurebot gains the ability to modify his own source code, he will surely become skynet

19:06 hiredman: clojurebot: clojurebot |has| a lot of features

19:06 clojurebot: In Ordnung

19:07 somnium: ~terminator

19:07 clojurebot: excusez-moi

19:08 the-kenny: clojurebot: You |will not| become skynet

19:08 clojurebot: In Ordnung

19:08 technomancy: "so far it's hard to keep a bug alive long enough for a tracker to be useful. They tend to be fixed within a day or two, if not hours or minutes." <= from a year ago. =(

19:09 _ato: :(

19:10 hiredman: clojurebot: you?

19:10 clojurebot: You will not become skynet

19:10 the-kenny: clojurebot: Do you plan to evolve to skynet?

19:10 clojurebot: You will not become skynet

19:11 danlarkin: technomancy: ha!!

19:15 somnium: clojurebot: clojurebot |will| become skynet

19:15 clojurebot: Alles klar

19:17 the-kenny: Oh no :(

19:17 somnium: its kind of scary he responded with Alles klar

19:20 the-kenny: Ja, das stimmt.

19:20 ;)

20:02 cark: hiredman: what are the pipes for when talking to clojurebot ?

20:02 krumholt__: ,(((fn [r] ((fn [f] (f f)) (fn [f] (r (fn [x] ((f f) x)))))) (fn [f] (fn [n] (if (= n 0) 1 (* n (f (- n 1))))))) 5)

20:02 clojurebot: 120

20:18 hiredman: cark: arbitrary predicates

20:18 clojurebot defaults to X is Y

20:18 but with the pipes you can say X | Z | Y

20:18 cark: oh i see

20:19 clojurebot: clojurebot?

20:19 clojurebot: clojurebot has a lot of features

20:19 cark: allright thanks =)

20:19 does it do the "also" part automatically now ?

20:20 i mean, no overwriting existing definitions ?

20:22 chouser: rhickey: if we give up on handlers fixing state, whether queue or synchronous model, most of the complexity goes away. error actions always "never happened", no watchers, no sends

20:22 hiredman: cark: yes

20:23 you can remove a definition if you know the exact tripple

20:23 triple

20:23 cark: ah so i'll need to be sneaky when adding definitions aboutu you !

20:23 thanks anyways =)

20:29 Anniepoo: ,(set! *ns* "tacos for lunch")

20:29 clojurebot: "tacos for lunch"

20:30 Anniepoo: ,(+ 1 2)

20:30 clojurebot: 3

20:30 Anniepoo: 8c)

20:32 tomoj: mm tacos

20:32 chouser: what have you done!?

20:32 ,`foo

20:32 clojurebot: sandbox/foo

20:32 chouser: hm

20:33 Anniepoo: just wondered if that crashed clojurebot

20:33 I'm using hiredman's sandbox for a thing I'm building

20:33 tomoj: (set! *ns* "foo") blows up for me

20:34 and *ns* is left unchanged

20:34 Anniepoo: throws a java exception, yet

20:34 tomoj: ,*ns*

20:34 clojurebot: #<Namespace sandbox>

20:35 tomoj: weird that you still get a return value

20:36 Anniepoo: I'm still trying to find a better way to prevent an evaluation from making global changes than clojurebot uses

20:36 clojurebot does a macroexpand, then looks for 'bad forms'

20:36 this seems iffy to me

20:36 hiredman: it is

20:36 cark: what's your use case for sandboxing ?

20:37 Anniepoo: I'm trying to make an 'injectable code' server

20:37 you send me a form, I evaluate it and send you the result

20:37 cark: does the injected code need to be fast ?

20:38 Anniepoo: hmmm.... why, you know a slow way?

20:38 cark: yes =)

20:38 Anniepoo: what's the slow way?

20:38 cark: do your own lisp interpreter, only reuse the clojure reader

20:39 sounds like a lot of work, but it really isn't

20:39 Anniepoo: that might actually work

20:39 it's not as elegant as allowing arbitrary clojure

20:39 I could reverse hiredman's scheme, make a list of everything that's OK

20:40 cark: but you have perfect control

20:40 hiredman: you could send the code to appengine to run :P

20:40 let google worry about the sandboxing

20:40 Anniepoo: what's appengine?

20:40 hiredman: ~google appengine

20:40 clojurebot: First, out of 327000 results is:

20:40 Google App Engine - Google Code

20:40 http://code.google.com/appengine/

20:40 hiredman: googles hosting thing

20:41 Anniepoo: ah, ok, sorry, didn't get it, yes yes

20:41 hiredman: it's free up to a certain point

20:41 which is pretty cool

20:41 Anniepoo: well, I'm acutally not concerned about the java sandboxing, which, as you know, is pretty trivial

20:41 it's actually a bigger problem to sandbox the clojure

20:42 in an ideal world I'd make a new JVM environment for each session

20:42 hiredman: yeah, but you can just ship the clojure code to google, and it's their problem

20:42 Anniepoo: so if you ruin your environment it's your problem

20:42 no, I'm not worried about violating the java sandbox

20:43 I'm worried about somebody clobbering my clojure server

20:43 hiredman: I know, but the clojure code can do whatever it wants on google's jvm in the sky

20:43 google limits execution time to something like 30 seconds

20:43 and has other limitations as well

20:43 Anniepoo: ok, I could do the same thing locally, spawn a jvm

20:43 and install a security manager, then eval the code

20:43 cark: mhh you can instanciate a clojure environment from java, so i guess you could do it from clojure as well, so i guess you'd get a new instance of the whole thing ?

20:44 Anniepoo: that works, but is massively inefficient

20:44 hiredman: I bet shipping the code to google would actually be faster than ramping up a new jvm

20:44 Anniepoo: good point, cark

20:44 if you can do that

20:44 but I haven't figured out how to

20:45 how would I make a new environment? That's what I really want

20:45 hiredman: make a new classloader and load clojure.lang.RT

20:45 Anniepoo: really?

20:45 Hmm....

20:45 OK

20:45 sounds like deep doings, but I'm up for it

20:46 * Anniepoo flexes her biceps (looks like Olive Oyl)

20:47 cark: mhh nope =(

20:47 http://markmail.org/message/madkidutwpp2yd44?q=thread:tx23zaxf77b6widh

20:49 hiredman: I dunno about that, but clojure runtime is initilized via a static init block in RT

20:49 Anniepoo: ok, now gotta find some sorta docs on clojure.lang.RT

20:49 hiredman: pffft

20:49 docs

20:52 Anniepoo: 8cP Somehow reading the source code to RT strikes me as likely to induce paranoid schizophrenia or warts or soemthing

20:52 hiredman: *shrug*

20:55 (== clojure.lang.RT (-> (ClassLoader/getSystemClassLoader) (.loadClass "clojure.lang.RT")))

20:55 er

20:55 user=> (== clojure.lang.RT (-> (ClassLoader/getSystemClassLoader) (.loadClass "clojure.lang.RT")))

20:55 false

20:55 user=>

20:58 Anniepoo: ooh, are you saying that if I call RT:load that's all I gotta do here?

20:59 hiredman: possibly

21:01 Anniepoo: hmm... Ah, you're saying make a new classloader and then use it to load RT, which will make a 'new' RT class?

21:01 I wonder if that makes a memory leak

21:02 after I've processed a few thousand of these I've got my memory full of class definitions of RT

21:03 hiredman: user=> (-> (ClassLoader/getSystemClassLoader) (.loadClass "clojure.lang.RT") (wall-hack-method :var [String String] nil "clojure.core" "+") (apply '(1 2 3 4)))

21:03 10

21:03 user=>

21:04 actually

21:06 you'll want (proxy [ClassLoader] [(ClassLoader/getSystemClassLoader)])

21:06 Anniepoo: ok, I'm getting 10% of this, but will go do my homework. Keep talkin!

21:06 hiredman: Classes can be GC'ed, but I forget the provisos

21:07 Anniepoo: I'll find out how

21:07 chouser: classes get GCed when their classloader gets GCed

21:07 I think

21:08 hiredman: ok, yeah, that is why you need the proxy

21:08 so you have an instance of the classloader you can let go of

21:08 Anniepoo: ah

21:08 hiredman: instead of the bare system classloader

21:09 Anniepoo: nifty nifty!!!

21:09 that's what I've been looking for

21:10 hiredman: maybe not

21:10 Anniepoo: hmm, why not?

21:11 hiredman: it looks like altering the metadata on the var named by clojure.core/+ from the new RT alters the meta data on the old one

21:11 (implying they are the same)

21:11 :|

21:12 Anniepoo: 8c( not good

21:12 hiredman: oh

21:12 I wonder if its a result of var interning from compile to runtime

21:12 anyway, *shrug*

21:13 ah!

21:13 yeah, it must be

21:13 _ato: are you trying to run two seperate clojure instances in the one JVM?

21:13 http://gist.github.com/240818

21:13 ^ that's what I was playing with the other day

21:14 Anniepoo: wow, sweet, ato!

21:16 ok, this looks promising.

21:17 So, I wonder what the memory overhead will be for each of these instances I have laying around

21:18 _ato: note that you have to use java interop stuff to "talk" to the "inner" Clojure as they're completely segregated, the data structures in the outer clojure can't be passed directly to the inner one AFAIK. But you could of course write a function that prn's some code to a string then does a read-string and eval on it in the inner Clojure.

21:19 Anniepoo: yes,

21:19 I'm going to be evaling a string anyway

21:19 I want to make a sort of 'rmi' for clojure

21:20 you send me a string, I eval it (suitably sandboxed) and return the value to you

21:20 the hard part is the 'suitably sandboxed'

21:22 _ato: ah yeah, you'd probably to proxy URLClassLoader to setup it's permissions to block access to files and sockets and such

21:22 also note that creating a fresh classloader and loading a fresh copy of clojure in it can take a while, it's about 600ms on my PC

21:22 Anniepoo: oochie. 8cP afraid of that

21:24 maybe I can make a custom version of RT

21:26 take all the static members and swap them out

21:27 hiredman: :|

21:27 the time is not in loading RT, it is loading everything else

21:27 when you load RT you are loading all the classes clojure uses

21:28 Anniepoo: yes, I suppose. And it smells of back to the bad-forms method

21:28 hiredman: and for interning stuff like Var you need to have them seperate

21:28 Anniepoo: the interpreter seems to make more and more sense

21:29 8cD What we need is clojure in clojure!

21:29 hiredman: you could pool RTs

21:29 Anniepoo: no, because the point is to have a 'fresh' one

21:29 _ato: you could pre-create a pool of them

21:29 use one

21:29 and throw it away

21:29 hiredman: spin up two or three, every time you spin up one

21:29 _ato: create a new

21:29 etc

21:30 Anniepoo: true, but that limits my sustained rate, and works the server

21:30 I'm beginning to think the interpreter way is the right way

21:30 _ato: there might be a way to put most of the classes in a parent classloader and just the stuff that changes like RT itself in multiple child classloaders

21:30 Anniepoo: make a toy lisp interpreter in Clojure.

21:31 _ato: so they share most classes

21:32 actually that probably wouldn't work as RT and the collections are pretty tightly coupled, the collections call into RT

21:32 kzar: Kind of a dumb question but I'm writing a simple recursive function and I'm trying to create a lazy sequence of numbers. I tried doing something like (lazy-seq x (recur (+ x 1))) but it doesn't work because x is an integer. What's the right way around that?

21:33 _ato: use the function name instead of recur

21:33 hiredman: kzar: it doesn't work because you can't call recur within lazy-seq

21:33 _ato: recur does tail call optimisation, but a lazy-seq exits the function so it doesn't make sense

21:34 Anniepoo: well, thanks all, this has been helpful. I'll explore the options

21:34 _ato: oh

21:34 and you need: (lazy-seq (cons x (recur (+ x 1)))))

21:34 kzar: lazy-seq doesn't cons for you

21:35 err, I of course mean: (lazy-seq (cons x (my-fn (+ x 1)))))

21:35 hiredman: "Elapsed time: 1.846638 msecs"

21:35 kzar: Sweet gotya, thanks

21:36 hiredman: RT loads pretty fast here

21:36 _ato: hiredman: ah awesome

21:36 maybe it's fast if you use the same version

21:36 it can probably used the already loaded classes

21:37 I was loading 1.0 inside 1.1

21:38 zaphar_ps: is the clojure documentation available as a downlaod anywhere?

21:38 that would be really useful

21:39 Anniepoo: hiredman, you're probably only having to reload the one class

21:39 but since the versions are diff ato's reloading the world?

21:40 _ato: zaphar_ps: try this: http://github.com/ksuzuki/Save-cljsites

21:41 zaphar_ps: there's also various other suggestions on the google group: http://groups.google.com/group/clojure/search?group=clojure&q=offline+documentation

21:42 zaphar_ps: if you're using emacs + slime move the cursor over the name of a function and press: C-c C-d C-d (that obviously doesn't let you search though)

21:42 zaphar_ps: ahh nifty that's like the wget option I was considering

21:43 _ato: yeah I use vimclojure which has similar

21:43 but like you say it doesn't allow searching or browsing

21:43 kzar: _ato: That worked but when I took too many from the lazy sequence I got a stack overflow. Your right that recur wouldn't work because it gives me an error so is there an alternative?

21:43 _ato: kzar: strange... you shouldn't get a stackoverflow, can you pastebin your whole function

21:43 ?

21:45 Anniepoo: anybody know of a lisp interpreter in clojure? I'm beginning to like that tack a lot

21:47 lisppaste8: kzar pasted "fib" at http://paste.lisp.org/display/91070

21:48 _ato: ah, I get a heap overflow not a stack overflow

21:49 kzar: _ato: whoops sorry me too

21:50 _ato: try reduce instead of apply

21:50 I suspect apply is holding onto the head of the sequence

21:52 kzar: _ato: Hmm that's taking ages to run

21:53 _ato: hope my macbook doesn't blow a hole in my crappy desk, it's whiring up ominously

21:54 _ato: well you're asking it to sum 4 million fib numbers

21:54 _mst: kzar: I don't think you need to sum the first 4,000,000 numbers to solve that problem ;)

21:54 _ato: the final answer is going to be enormous

21:55 kzar: I guess so but here's the question: "Find the sum of all the even-valued terms in the sequence which do not exceed four million."

21:55 _mst: yep, but even fib(100) exceeds four million by loads

21:56 kzar: oh I read it while the number in the sequence is less than four million but it meant while the sum was less than four million

21:57 _ato: it does mean the numbers in the sequence are less than four million

21:57 it doesn't mean while the *length* of the sequence is less than four million

21:57 kzar: yea gotya :/ I'm glad this is logged for everyone to see

21:57 _ato: you probably want (take-while #(< % 4000000) ...) instead of (take 4000000 ...)

21:58 _mst: less ambiguously: (reduce + (take-while #(< % 4000000) (filter even? (fib)))) ;)

22:00 kzar: oh cool, that's pretty powerful

22:00 lisppaste8: kzar annotated #91070 "better" at http://paste.lisp.org/display/91070#1

22:21 alexyk: how do you print to stderr?

22:30 zaphar_ps: alexyk: (.println (System/err) "foo")

22:30 off the top of my head that should work

22:30 uses javas stderr print stream

22:31 alexyk: thx!

22:32 zaphar_ps: http://clojure.org/java_interop

22:32 that would probably be useful

22:32 alexyk: so here .println is called on System/err? is that the syntax?

22:32 zaphar_ps: alexyk: yeah

22:40 alexyk: after further reading *err* represents stderr in clojure as well

22:41 alexyk: zaphar_ps: can we use (print ...) with it somehow?

22:41 weird: (print *err* "au") gets me a: #<PrintWriter java.io.PrintWriter@2db7ae22> aunil

22:42 zaphar_ps: you can .println with it

22:42 but print doesn't take a stream it assumes *out*

22:43 somnium: you can also do (binding [*out* *err*] ...)

22:43 zaphar_ps: somnium: yeah

22:45 alexyk: ah ok it just printed *err*

22:47 zaphar_ps: code?

22:50 alexyk: I mean representation of *err* is #<PrintWriter java.io.PrintWriter@2db7ae22>

22:52 zaphar_ps: alexyk: right

22:59 * defn waves

23:16 * zaphar_ps waves back

23:19 kzar: how could you take the last two items in a sequence?

23:20 defn: nthrest

23:20 err not what you were asking i suppose

23:24 _mst: if you happen to have a vector: (take 2 (rseq [1 2 3 4 5]))

23:25 defn: (reverse seq), (take 2 seq)

23:25 oh yeah, rseq

23:25 you'll probably wanna reverse the final output from _mst's though

23:26 ,(reverse (take 2 (rseq [1 2 3 4 5 6])))

23:26 clojurebot: (5 6)

23:29 defn: you also could (let [sz (count [1 2 3 4 5 6])] (rest (split-at (- sz 2) [1 2 3 4 5 6])))

23:29 ,(let [sz (count [1 2 3 4 5 6])] (rest (split-at (- sz 2) [1 2 3 4 5 6])))

23:29 clojurebot: ((5 6))

23:29 defn: or something like that

23:32 JAS415: you could also do (drop (-(count coll) 2) coll)

23:32 zaphar_ps: why do read and readline not accept a java.io.FileReader?

23:34 JAS415: have you looked at the duck-streams contrib module?

23:34 defn: ^^

23:34 zaphar_ps: JAS415: no I haven't

23:35 JAS415: it might be useful to you

23:38 defn: ,(let [size (count [1 2 3 4 5 6])] (subvec (- size 2) size [1 2 3 4 5 6]))

23:38 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IPersistentVector

23:38 defn: doh

23:39 JAS415: other way round

23:47 eno__: ,(let [v [1 2 3 4 5 6] size (count v)] (subvec v (- size 2)))

23:47 clojurebot: [5 6]

Logging service provided by n01se.net