#clojure log - Aug 26 2009

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

0:00 mebaran151: it seemed to work

0:00 clojure contrib with the old version

0:45 headius: mikem: clojure's using nailgun now too, eh?

0:45 we need to get together and make some improvements

0:53 hiredman: vimclojure comes with a nailgun server

0:57 replaca: is anyone else getting errors building the latest contrib?

0:58 I'm getting compile_clojure: [java] java.io.FileNotFoundException: Could not locate clojure/contrib/expect/test_is_adapter__init.class or clojure/contrib/expect/test_is_adapter.clj on classpath:

1:00 hiredman: yep

1:00 replaca: oh, just a typo in build.xml

1:00 one sec, i'll check in a fix

1:05 fixed, you can pull now

1:05 hiredman: neat

1:57 lowlycoder: how do i search for sample code taht uses letfn

1:58 LauJensen: lowlycoder: Google seemed to do the trick: http://groups.google.com/group/clojure/browse_thread/thread/a7aad1d5b94db748

1:59 lowlycoder: what did you search for?

1:59 LauJensen: "clojure letfn"

2:00 hiredman: ~google clojure letfn

2:00 clojurebot: First, out of 68 results is:

2:00 letfn - mutually recursive local functions - Clojure | Google Groups

2:00 http://groups.google.com/group/clojure/browse_thread/thread/a7aad1d5b94db748

2:00 hiredman: huh

2:11 lowlycoder: is there anyway I can use letfn on a proxy?

2:16 in clojure, how can you create a proxy that will remove itself?

2:25 this is weird; is it possible to define a macro (run-once ...) so that even if (run-once ...) is embedded in the function of a body, it's only executed once, even if the function is called multiple times?

2:27 hiredman: what are you doing?

2:27 lowlycoder: i'm doing something wrong (and re-engineering my solution to not need this)

2:27 but now, i'm curious

2:37 http://paste.lisp.org/+1UEG <-- is there a way to make this shorter / more idiomatic

2:38 hiredman: looks like you are re-implementing memoize

2:38 ~def memoize

2:38 lowlycoder: whoa, it happens only once?

2:38 that's an interesting wya to use memoize

2:38 no it's not

2:38 i'm trying to remove the listener after it execs

2:39 hiredman: what

2:39 this is ridiculous

2:39 remove from what?

2:40 lowlycoder: i remove the listener after it exeutes once

2:40 ideally i would use letfn and not have to deal with my-ref

2:40 but i don't know how to use letfn with proxy

2:40 hiredman: have you read the docs for proxy?

2:40 lowlycoder: i have

2:40 hiredman: I suggest you do, there is a very simple way to do this

2:41 lowlycoder: it returns a class

2:41 no mention of the function

2:41 the this?

2:41 hmm

2:41 hiredman:

2:50 JAS415: ~def proxy

2:51 Each method fn takes an additional implicit first arg, which is bound to 'this.

2:51 lowlycoder: JAS415: yep; just got it working; thanks :-)

2:52 JAS415: cool

2:52 this is very useful, i had the same type of problem until i found it

2:53 lowlycoder: yeah, i started out with a "solution" where I had a global ref that would change the first time i exec the handler and in future checks, it would ignore the handler

2:53 then I moved on to what I pasted into lisppaste

2:53 but this solution I like the best :-)

3:20 mebaran151: has anybody tried the new enclojure

3:21 REPL seems to be failing on me in Netbeans with the newest one

3:22 lowlycoder: does enclojure have vim intergration?

3:36 i'm really starting to hate clojure's lack of continuations

3:36 i'm seeing them everywhere

4:27 LauJensen: hiredman: feeling a little grumpy today ?

4:31 hiredman: ?

4:31 every day

4:31 lowlycoder: does clojure have a deque structure, where I append to the front and take from the end?

4:32 hiredman: ,(doc butlast)

4:32 clojurebot: "([coll]); Return a seq of all but the last item in coll, in linear time"

4:32 hiredman: hmm

4:33 ,(doc subvec)

4:33 clojurebot: "([v start] [v start end]); Returns a persistent vector of the items in vector from start (inclusive) to end (exclusive). If end is not supplied, defaults to (count vector). This operation is O(1) and very fast, as the resulting vector shares structure with the original and no trimming is done."

4:33 lowlycoder: ?

4:33 clojurebot: clojure-maven-plugin is http://github.com/talios/clojure-maven-plugin

4:33 lowlycoder: hmm, i'll just use reverse function

4:34 hiredman: ,(conj [1 2 3] 4)

4:34 clojurebot: [1 2 3 4]

4:34 LauJensen: lowlycoder: If not, it wouldn't be difficult to make your own, and you can always take from the rear using last and append using (conj '(1 2 3) 4)

4:34 ~(conj '(1 2 3) 4)

4:34 clojurebot: (conj {:a 1} (when true {:b 2}))

4:34 hiredman: ,(subvec [1 2 3 4] 1)

4:34 clojurebot: [2 3 4]

4:34 LauJensen: w00t?

4:34 clojureb0t is b0rked

4:34 hiredman: LauJensen: what?

4:34 LauJensen: ~(conj '(1 2 3) 4)

4:34 clojurebot: (conj {:a 1} (when true {:b 2}))

4:35 LauJensen: that should give me (4 1 2 3)

4:35 Chousuke: ~conj

4:35 clojurebot: (conj {:a 1} (when true {:b 2}))

4:35 hiredman: LauJensen: ,

4:35 LauJensen: ,(conj '(1 2 3) 4)

4:35 clojurebot: (4 1 2 3)

4:35 LauJensen: Oh - So I'm the noob :)

4:35 btw, all you danish reading compojure lovin' clojure fans, check out http://www.bestinclass.dk

4:35 hiredman: anyway subvec and conj will let you use a vector as a deque

4:36 Chousuke: hmm, doesn't subvec have performance issues if you stack it too much? /:

4:36 hiredman: last I heard it did not

4:37 (doc subvec)

4:37 clojurebot: "([v start] [v start end]); Returns a persistent vector of the items in vector from start (inclusive) to end (exclusive). If end is not supplied, defaults to (count vector). This operation is O(1) and very fast, as the resulting vector shares structure with the original and no trimming is done."

4:37 hiredman: bah

4:37 ~def subvec

4:38 ~def c.l.RT

4:40 ~def c.l.APersistentVector

4:41 LauJensen: hiredman: Dont you worry that tinyurl will consider you a spammer?

4:43 hiredman: nope

7:05 gko: ,(= (java.lang.Long. "123") (java.math.BigInteger. "123"))

7:05 clojurebot: true

7:06 gko: ,(#{(java.lang.Long. "123")} (java.math.BigInteger. "123"))

7:06 clojurebot: nil

7:06 gko: why ???

7:14 is that normal?

7:27 liwp: gko: I think set uses .equals() to find items whereas (=) uses numerical equality for numbesr

7:28 ,(.equals (Long. "123") (java.math.BigInteger. "123"))

7:28 clojurebot: false

7:28 liwp: ,(.equals (Integer. "123") 123)

7:28 clojurebot: true

7:29 liwp: ,(#{(Integer. "123")} 123)

7:29 clojurebot: 123

7:30 gko: liwp: so, set of number = pain ?

7:32 or what should I use instead?

7:32 liwp: yeah, I think it tends to be uncomfortable unless you can guarantee that all the numbers are e.g. ints

7:33 I'm not sure what the recommended way of dealing with this is

7:33 if you do need to worry about BigIntegers, then you can of course make everything into a big-int before you add it to the set and look it up

7:34 ,(doc bigint)

7:34 clojurebot: "([x]); Coerce to BigInteger"

7:35 liwp: ,(#{(Long. "123")} (long 123))

7:35 clojurebot: 123

7:35 liwp: ,(#{(java.math.BingInteger. "123")} (bigint 123))

7:35 clojurebot: java.lang.ClassNotFoundException: java.math.BingInteger

7:35 liwp: uhh

7:35 ,(#{(java.math.BigInteger. "123")} (bigint 123))

7:35 clojurebot: 123

7:36 liwp: gko: but yeah, you need to be careful

7:37 gko: yep.

7:50 raphinou: is there a way to avoid the repeat of (count args) in this code? (let [argsnum# (if (< 0 (count args)) (count args) "") ] some-code)

7:53 matley: raphinou, only if you write a macro if-negative-let afaik

7:55 raphinou: ok, thx matley. It's not worth it in my case

7:58 gerryxiao: hello

7:58 how to change Graphics to Graphics2D in clojure?

7:59 (Graphics2D g) seems not work

7:59 g is Graphics

8:00 liwp: I assume you're calling a method on g that is only defined for Graphics2D instances?

8:01 try adding a type hint to the call site, e.g. (.foo #^Garphics2D g <rest of args>)

8:01 gerryxiao: nope

8:02 i 'm use Canvas class to draw stuff

8:02 paint(g)

8:03 g is Graphics

8:03 i want to change it to Graphics2D and use methods from Graphics2D

8:04 liwp: try this: (.paint canvas #^Graphics2D g)

8:04 matley: newbie question. I am trying to subclass a ListModel. In this case the subclass should have an additional state (a sorted-set). Is it right to do (let [state (ref ...)] (proxy [javax.swing.DefaultListModel] [] ... .... )) ?

8:04 arbscht: ,(doc cast)

8:04 clojurebot: "([c x]); Throws a ClassCastException if x is not a c, else returns x."

8:05 gerryxiao: ok

8:18 it works, thx

8:19 liwp :-)

8:19 liwp: good

8:20 gerryxiao: but i think "#^Graphics 2D" is much ugly

8:20 liwp: I haven't really figured out yet what clojure's (cast) is good for

8:20 yeah, the type hinting does get a bit ugly

8:20 gerryxiao: i have to type it much times

8:21 liwp: there was some discussion about a macro that would allow something like g:Graphics2D in function definitions

8:21 gerryxiao: (let [g2d #^Graphics2D g]) can't work?

8:21 liwp: gerryxiao: if it is in the same function you can type hint a let binding and then use that

8:21 yep, that's it

8:23 gerryxiao: that's a bit better

8:25 when will newnew be merged to master?

8:29 liwp: don't know

8:53 LauJensen: ~max

8:53 clojurebot: max people is 164

8:53 LauJensen: ~clojureql

8:53 clojurebot: clojureql is http://gitorious.org/clojureql

9:11 lpetit_: Hi I can't find a pre-existing function returning a (flat or not) list of filepaths (recursive from a root directory). Neither in core or contrib ? Do I miss something or do I have to (yet again) rewrite my own ?

9:12 cgrand: ,(doc file-seq)

9:12 clojurebot: "([dir]); A tree seq on java.io.Files"

9:13 lpetit_: thx, I was searching on the wrong keyword (directory, folder)

9:20 gerryxiao: hello

9:20 how to name static innerclass in clojure?

9:20 classname/innerclass ?

9:20 Chouser: classname$innerclass

9:21 gerryxiao: ok

9:21 cark: carefull about importing the innerclass too, or use fully qualified names

9:22 gerryxiao: (import (java.awt.geom Line2D))

9:22 cark: nope you need the containing class as well

9:23 (import (java.awt.geom Bleh$Line2D))

9:23 gerryxiao: oh

9:23 thx

9:43 Chouser: some day I'll come up with a use for condp's :>> clause

10:00 Fossi: hey

10:02 we want to call some java methods on an object dynamically, like (.. (Query. "foo") (addFilter "bar") (addFilter "baz"))

10:02 with bar and baz coming from a map for example.

10:03 we used reduce for a while which went ok, but it's getting more complicated as we want to call another method

10:03 is there a simple way to do such things? can you for example somehow treat java methods as first class functions and put them into a map?

10:04 liwp: ,(doc memfn)

10:04 clojurebot: "([name & args]); Expands into code that creates a fn that expects to be passed an object and any args and calls the named instance method on the object passing the args. Use when you want to treat a Java method as a first-class fn."

10:04 liwp: does that help

10:05 Fossi: quite some :)

10:06 rhickey: memfn predates #() and the latter is preferred

10:14 ankou: what's the difference between reader macros and vectorsyntax? As far as I can see they are not really like macros, but just other special syntax rules? what's the difference between [a b] as (vector a b) and '(a b) as (quote (a b)) ?

10:17 opqdonut: none really

10:17 rhickey: ankou: when the reader reads [a b] it reads a vector object containing 2 symbols, not (vector a b). When it reads '(a b) it reads the list (quote (a b)), where quote, a and b are symbols

10:17 opqdonut: oh, okay

10:17 rhickey: ,'[a b]

10:17 clojurebot: [a b]

10:18 ankou: okay

10:25 rhickey: cgrand: let me know when you've tried the tweaks I posted, after that I think we're ready for a patch?

10:27 ankou: it would be nice to have some sort of tabcompletion in the repl

10:28 Chousuke: it's possible with rlwrap

10:28 or slime :P

10:28 rhickey: or enclojure

10:29 ankou: what is rlwrap or enclojure? I would like to use slime but I'm soo used to vim and viper wasn't that good. Slimv wasn't very nice either

10:30 the same problem with IDEs, I never saw a good vi-plugin

10:30 eevar2: enclojure is a netbeans plugin

10:31 liwp: ankou: rlwrap is utility that uses readline to provide any std io prompt with things like history and tab-completion

10:31 Chouser: ankou: vimclojure exists

10:31 ankou: I'm psyching myself up to again try enclojure + jvi in netbeans

10:32 rhickey: Has anyone tried: http://jboss.org/hornetq.html ?

10:32 ankou: Chouser, with vi-plugin I meant something integrating vi in an IDE, not integrating closure in vim. I really missed splitwindows in jvi. I'm normally working with 4 codewindows and would really miss this

10:33 danlarkin: rhickey: do you have the power to invite a regular old email address to join clojure-dev? I want to join but not with a google account, which it seems is the only way google will let me

10:33 Chouser: ankou: look at vimclojure -- runs in real vim

10:33 cgrand: rhickey: gah! I didn't think of reusing the Box. I see you make room for two extra key-values pair when a bitmapnode grows. Did you try parallel arrays instead of the interleaved array?

10:34 ankou: Chouser: I'm currently using it

10:34 Chouser: ankou: and it doesn't do tab completion??

10:35 ankou: don't know, I was talking about the REPL.

10:36 rhickey: cgrand: I haven't tried 2 arrays, and think we can leave that idea for the moment. In my testing leafless is at least as fast as what we've got now, and sometimes faster, with better memory utilization. The last thing I haven't tested is seq perf

10:56 cemerick: rhickey: I just saw hornetq yesterday myself. It certainly *sounds* like a winner. I need some lightweight messaging library very shortly, so I'll probably put it through its paces.

10:56 rhickey: cemerick: cool let me know what you think if I don't get around to it first

10:56 cemerick: I'm suspicious of anything coming out of jboss, though. It sits next to spring et al. in my head.

10:56 rhickey: libs that this are what make Clojure so useful

10:57 cemerick: heh, yeah, they seem to be bending over backwards here highlighting no deps other than the JDK etc, seems small enough

10:58 cemerick: I worry about 2 months from now, I'm using hornet, and then one little piece that would be helpful as an add-on comes out, but depends upon 18 spring libs.

10:58 rhickey: cemerick: the splitting off and packaging seems a quite deliberate effort to give it an independent life

11:00 cemerick: well, here's hoping. Once burned, etc...

11:02 rhickey: with these MQs it all comes down to lots-of-users + lots-of-fixes so it gets fully shaken out

11:03 cemerick: rhickey: what others have you taken a look at so far? I'm only now starting to look.

11:04 rhickey: ActiveMQ, OpenMQ, Joram, mostly reading, a little twiddling

11:05 cemerick: ah -- I'm definitely looking for something embeddable, useful for point-to-point stuff

11:05 rhickey: activemq and joram embed

11:05 cemerick: We use openmq serverside, which is fine enough.

11:05 Haven't pushed it any though.

11:05 ah, I saw openmq and assumed they were all server-side :-/

11:07 rhickey: joram has a kind of unique multi-peer strategy when embedded. If used persistently, a client can durably 'send' a message when not connected to the network, and will get to target server when reconnected

11:08 ankou: is there any form of destructuring for lists?

11:08 Chouser: ankou: vector destructuring forms work on all seqables

11:09 rhickey: ,(let [[a b c] (range 3)] [c b a])

11:09 clojurebot: [2 1 0]

11:09 cemerick: rhickey: Oh, that's sexy.

11:09 huh, JMS compliant and around since 2000.

11:09 old code so much better than new code :-)

11:10 rhickey: cemerick: yeah, really cool design. Persistent perf is always the challenge, HornetQ is definitely teasing here

11:11 cemerick: The up-front mention of "POJO" is a warning flag. That often means "there's a lot of complexity under the covers so that setters are actually triggering messages/transactions/connections under the covers" in other libs.

11:12 rhickey: cemerick: I that what it means? I couldn't figure it out :)

11:12 cemerick: well, it means a lot of different things to different people.

11:13 Many libs are annotation-driven these days, where you add a @Whatever to your class or field, and it decorates all your "POJO" methods with whatever machinery is appropriate. Hibernate comes to mind as a significant example.

11:16 rhickey: cemerick: isn't the problem/magic in the annotator rather than the annotatee?

11:17 cemerick: rhickey: definitely -- what I was saying was that "POJO" might mean that a lot of functionality is only available via annotations.

11:20 rhickey: cemerick: well, I like that you can create a configuration thingy in code. One thing about Joram is, even when embedded, needs some XML to configure, iirc

11:20 cgrand: rhickey: https://www.assembla.com/spaces/clojure/tickets/183-leafless-PersistentHashMap

11:21 cemerick: sure. Annotations aren't a good path AFAIC, though -- the less Java I need to continue to have around, the better.

11:22 rhickey: cemerick: agreed

11:22 cgrand: cool, thanks

11:23 cemerick: I'm hoping someone with serious Java-fu comes along with a contrib to support annotations in clojure. That's probably the last significant interop hole left.

11:24 thickey: work in progress for new t-shirt: http://www.flickr.com/photos/tommyvulgar/3858634993/

11:25 liwp: thickey: nice!

11:25 danlarkin: I love the copy

11:27 thickey: thanks

11:27 cemerick: thickey: man, has that woodstock feel, even :-P

11:29 thickey: definitely inspired by rock posters

11:30 rhickey: cgrand: patch doesn't apply cleanly on master: Patch failed at 0017 replace copyOf with arrayCopy

11:31 thickey: wild!

11:31 thickey: :)

11:37 cgrand: rhickey: try git am -3 leafless.patch

12:00 bitbckt: thickey: Love the shirt design.

12:01 thickey: thanks!

12:02 bitbckt: I look forward to buying one. :-)

12:02 rzoom: A+++ will order

12:08 rhickey: cgrand: patch applied - thanks!

12:23 Chouser: 'into' on a finger-tree should keep the same order, so conj should add to the right, so then push could add to the left.

12:23 pop would then remove from the left -- is there anything handy for removing from the right?

12:26 rhickey: Chouser: interesting. depending on if you look at a finger tree as a seq (possible), maybe cons/next for left and conj/pop for right?

12:27 Chouser: yeah, I had thought of that too. Not sure of the drawbacks of implementing ISeq directly...

12:29 right now, cons never calls a method of the existing object

12:29 rhickey: writing a finger tree in new new?

12:30 Chouser: that's the plan. slapping it together with non-standard functions on top of vectors right now

12:30 conjl/conjr, ft-seq/ft-rseq, etc.

12:30 rhickey: cool

12:31 using delays for laziness?

12:32 cemerick: ah, compressed oops are default in jdk7 now

12:32 rhickey: compressed oops?

12:33 cemerick: ordinary object pointers

12:33 rhickey: this in 64-bit?

12:33 cemerick: yeah. Irrelevant in 32.

12:33 ah: http://wikis.sun.com/display/HotSpotInternals/CompressedOops

12:34 rhickey: they were all excited about that at JavaOne

12:34 Chouser: I haven't groked the paper all the way to the end. My understanding is the only place I need laziness so far for seq, and lazy-cat's giving me that for free.

12:34 cemerick: the key changeset went in on Monday: http://hg.openjdk.java.net/jdk7/hotspot/hotspot/rev/82bd76d4d7f2

12:35 Chouser: it's entirely possible I as yet misunderstand the internal requirements to deliver the complexity promises. I'll do some testing at some point to make sure I'm not claiming it's a good finger tree if it's not.

12:35 rhickey: Chouser: I thought laziness was needed to get amortized time properties

12:36 Chouser: rhickey: yes, but I thought that was for the head/tail view stuff.

12:36 ah, no, you're probably right.

12:36 rhickey: Chouser: maybe, I haven't looked at it in a while

12:37 Chouser: that's where they discuss it, but perhaps they're showing that the seq doesn't force the creation of the tree until needed.

12:38 I'll read that again and make sure. This stuff is definitely stretching my understanding on several levels. Difficult but fun!

12:39 rhickey: you need to be careful as, for Clojure, we care about the amortized time characteristics in a *persistent* setting

12:39 "The same bounds hold in a persistent setting if subtrees are suspended using lazy

12:39 evaluation. This ensures that transformations deep in the spine do not take place

12:39 clojurebot: lazy is hard

12:39 rhickey: until a subsequent operation needs to go down that far. Because of the above prop-

12:39 erties of safe and dangerous digits, by that time enough cheap shallow operations

12:39 will have been performed to pay for this expensive evaluation."

12:40 ankou: is there a possibility to import a whole javapackage?

12:41 like import javax.swing.*; in java

12:42 rhickey: you can also leverage: "In a strict language that provides a lazy evaluation primitive, we need only suspend the middle subtree of each Deep node, so only Θ(log n) suspensions are required in a tree of size n."

12:43 Chouser: finger trees would be an awesome addition - good luck!

12:44 Chouser: heh, thanks.

12:46 My current plan is to support a map of measure/reduce functions, so you can do different kinds of searches on the same tree

12:48 rhickey: neat

12:49 technomancy: ankou: no

13:15 cark: clojure.test is not in 1.0 ?

13:16 hiredman: nope

13:16 cark: and test-is is not in contrib anymore ><

13:17 hiredman: there is a 1.0 compat branch of contrib

13:17 cark: oh well that's for simple stuff, i'll do ad hoc testing

13:17 until clojure 1.1 !

14:08 a generic pool library : http://github.com/cark/clj-pool

14:09 krumholt_: what is a good way to deliver a clojure application?

14:09 cark: smallish, but might be usefull to these database guys (clojureql hint hint)

14:10 krumholt_ : make an executable jar

14:12 krumholt_: cark, i tried and failed. is there a better example then on the clojure.org website for how to do this?

14:14 cark: it take a couple hours of suffering to make a nice ant build file, then just copy it for each project =)

14:14 clojurebot: build is working

14:14 cark: i could send you one of my build files, but it wouldn't make sense without the projects themselves

14:15 krumholt_: cark, right now i am manually ordering everthing folder structure etc it is very annoying. maybe i try ant scripts

14:16 cemerick: krumholt_: clojure's jar itself is executable. You should be able to follow its build process as a template in that respect.

14:16 yeah, doing it manually is a little insane :-)

14:17 technomancy: krumholt_: here's what I was using on an earlier project: http://github.com/technomancy/mire/blob/910d02c5d616672f46430625874cf7a68ed46eb2/compile.sh

14:17 hiredman: maybe someone should make a sort of skelton executable jar that executes a function based on a property file

14:17 krumholt_: technomancy, thanks

14:17 hiredman: technomancy: clojurebot should work with the latest fnparse now

14:18 technomancy: hiredman: awesome

14:20 cemerick: hiredman: shouldn't people just learn how to use the massive pile of tools that are out there?

14:21 I'd hate to see some 5% solution become standard practice.

14:22 cark: well there's a fine line between adding another dependency and having enough functionality

14:22 and sometimes those java libraries a heavy

14:22 heavy to use i mean

14:23 cemerick: I wouldn't call ant 'heavy'. Not using some kind of build tool is like not using autoconf with a C build or something.

14:24 hiredman: cemerick: it would be kind of nice just to be able to copy your clj files somewhere, edit a properties file to note the namespace and name of the function to call, run ant, and have an executable jar

14:24 cark: cemerick : agreed

14:24 hiredman: but everyone hates autoconf

14:25 cemerick: hiredman: oh, I thought the properties file thing was to avoid ant. If ant is in there anywhere, why not just copy and paste any of the dozen executable jar recipes out there?

14:25 hiredman: cemerick: because you then have to copy and paste for every project

14:26 cemerick: hiredman: not if you use ant properly. That's what imports and macros are for.

14:30 technomancy: is getting nicer docstrings for namespaces targeted for 1.1?

14:30 *nicer docstring syntax

14:33 saml: do you use emacs?

14:34 technomancy: saml: me? I do.

14:34 http://technomancy.us/126

14:49 Chousuke: technomancy: hmm, maybe you should add to the instructions how to specify the encoding for SLIME to use. it seems to default to latin1 :/

14:53 technomancy: Chousuke: yeah, good point

15:11 rhickey: suggestions welcome for multimap reader syntax, a la #*{k v k2 #{vs ...} ...}

15:11 cschreiner: Looking for the slides from the Clojure for Lispers presentation

15:12 cark: rhickey : huh what is it for ?

15:12 cemerick: rhickey: what does that do?

15:12 jensli: Should a multimap really have special syntax?

15:12 rhickey: multimaps ar elike maps but can support more than one value per key

15:13 jensli: do you want to be able to read/print it? I do

15:13 jensli: Shouldnt one be more conservative with special syntax, to reduce complexity?

15:13 Chouser: don't want to just repeat the key?

15:13 kotarak: ehm, what is the difference to a map of keys to sets?

15:13 cemerick: rhickey: isn't that just {:a #{1 2 3}}, or whatever?

15:13 rhickey: Chouser: will answer you in a sec

15:14 ,(seq {:a #{1 2 3}})

15:14 clojurebot: ([:a #{1 2 3}])

15:14 * cemerick gets the feeling we're all going to get taken to school now

15:14 cemerick: ;-)

15:14 kotarak: hehe

15:14 Chouser: #*{[1 2 3] :key-1, [1 2 3] :key-2}

15:14 cemerick: indeed.

15:14 rhickey: but for multimaps would be [:a 1] [:a 2] [:a 3]

15:15 Chouser: oops. #*{[1 2 3] :val-1, [1 2 3] :val-2}

15:15 cemerick: rhickey: and I assume assoc would add in an additional value to the pool for the given key, etc?

15:15 Chouser: I would have used multimaps somewhere if we had them. I foreget where that was though...

15:15 rhickey: there will be assoc* and dissoc*, which add/remove from the set

15:16 jensli: assoc-multi?

15:16 rhickey: Chouser: to your question, my design distinguishes keys that support multiple values from keys that don't

15:16 cemerick: I guess I'd say it doesn't excite me. assoc-in and update-in are very capable

15:16 Chouser: some keys in a multimap would still only have one value? overwriting?

15:17 rhickey: (assoc* #*{:a 1} :a 42)) = error multi-assoc to single-value key

15:18 (assoc #*{:a #{1}} :a 42)) = error single-assoc to multi-value key

15:18 so the literal needs to distinguish, thus {:a 1 :b #{1}} yields single-value :a, multi-value :b

15:19 jensli: Just be carefull to minimize the amout of code that consists of '*' and '#'...

15:19 cemerick: rhickey: is there a performance improvement compared to update-in on a regular map?

15:20 rhickey: cemerick: no

15:20 Chouser: seems like multi-value keys would be more common than single-value in a #*{} -- perhaps use syntax to indicate the single case instead?

15:21 rhickey: but there will be a (contains-entry? mm k v)

15:21 Chouser: #*{:a 1 :a 2 [:b 3]}

15:21 rhickey: count is a count of vals, not keys

15:21 er, count of entries

15:21 a multimap is not merely a map os keys to sets

15:22 cemerick: rhickey: I'm surprised you're considering special reader syntax -- seems like a pretty minor structure.

15:22 rhickey: Chouser: but don't forget that literals often have runtime holes - #*{:a 1 :b a -set-I-already-made}

15:23 cemerick: I have big plans

15:23 Chouser: cemerick: shhh. Soon I'll be petitioning for finger tree literals #*++[:a :b :c]

15:23 cemerick: hah

15:24 Chouser: I was about to say something about bit-set literals, but nevermind :-P

15:24 rhickey: Chouser: good point, I want to discuss the general problem of supporting more core structures, I think you might get #[...]

15:24 jensli: I dont know if I dare to learn a language where people have so big plans...

15:24 rhickey: cemerick: bitsets, now that is uninteresting :)

15:25 cemerick: LOL

15:25 Chouser: rhickey: there are already a lot of restrictions on runtime holes for maps

15:25 rhickey: jensli: you can use just lists and pretend it's an old-fashioned Lisp

15:25 cemerick: jensli: "In Rich Hickey We Trust" is the motto here :-)

15:25 Chouser: no way to do this currently, right? {:a 1 (thing-that-produces-key-and-vals)}

15:26 rhickey: Chouser: I don't see that as the same at all, trying to replace many things with one

15:27 what I'm really asking about is the space before the {}, i.e. #*, ## etc?

15:27 jensli: forgot :)

15:28 but it's true, there's a limit to how much symbol overloading we can do

15:29 it could have been #set{...} and everything else in the future could have names in there

15:29 #multimap{...}

15:30 Chouser: that's pretty close to #=(multimap ...) territory.

15:30 I guess the args are evalutated at a different stage.

15:30 rhickey: Chouser: except the latter won't work with read-eval turned off

15:30 Chouser: eh. yeah.

15:30 wtetzner_: what does #= do?

15:31 Chouser: wtetzner_: read-time eval.

15:31 wtetzner_: oh

15:31 Chouser: wtetzner_: it's used by *print-dup* to generate very specific container types

15:32 rhickey: it's not like there's a ton of core-ish data structures. Started with lists/maps/vectors, added sets, only looking at finger trees and multimaps at present

15:32 Chouser: ,(binding [*print-dup* false] (prn (sorted-map :a 1 :b 2)))

15:33 clojurebot: {:a 1, :b 2}

15:33 cemerick: such valuable real-estate, though....

15:33 Chouser: ,(binding [*print-dup* true] (prn (sorted-map :a 1 :b 2)))

15:33 clojurebot: #=(clojure.lang.PersistentTreeMap/create {:a 1, :b 2})

15:33 * cemerick wonders what made him start thinking like a minimalist today :-P

15:34 Chouser: cemerick: trying to think up contrasts for the vs. Scala thread? :-)

15:34 cemerick: Chouser: I've got it queued up, haven't read it yet.

15:34 dmiles_afk: clojure use a real live java.lang.Integer right?

15:34 cemerick: I've actually been keeping up on my group reading quite a bit though.

15:34 Chouser: cemerick: don't bother

15:34 cemerick: ut-oh

15:34 dmiles_afk: something scala did was heavy boxing avoidance

15:34 Chouser: ,(class 5)

15:34 clojurebot: java.lang.Integer

15:35 dmiles_afk: the way they did that was when they compiled a finction they added extra unboxed signatures

15:36 cemerick: rhickey: what's the plan when some group needs to make heavy use of an entirely separate set of (for them) core data structures? bit-sets, k-d trees, and skip lists, or whatever.

15:36 * cemerick keeps angling for the userspace reader :-D

15:36 dmiles_afk: a java lisp i work on uses boxed types.. i think Clojure could be considered Duck Types

15:37 Scala does heavy boxing avoidance

15:37 rhickey: cemerick: what happens when I want to combine your code that uses reader and someone else's?

15:37 dmiles_afk: so.. where i am going is trying to decide if the java lisp i work on should adopt Clojure's Duck Types vs Scalas boxing avoidance

15:37 Chouser: dmiles_afk: Clojure can use primitives for locals and method calls and returns.

15:38 cemerick: rhickey: hey, you're the expert! ;-) I presume the reader to be used is ns-specific, and declared as such in the top-level ns form?

15:38 dmiles_afk: Clojures method can leverage very fast box/unbox of the JVM since it staying inside java.lang.Number/* .. but..

15:38 rhickey: cemerick: but I want to use both in my files

15:38 Chouser: dmiles_afk: I believe limited support for primitive clojure fn args and clojure collections are planned.

15:38 dmiles_afk: i dont know if its more or less effectient than a LispInt

15:39 rhickey: cemerick: nevermind the hassles of making the supporting custom reader code accessible and available in advance of use

15:39 dmiles_afk: Chouser: yeah that is probaby needed.. but makes me wonder *how needed*

15:39 cemerick: rhickey: well, that sounds a little nutty :-) One reader per ns seems perfectly reasonable, and addresses anyone's domain-specific requirements.

15:39 Chouser: dmiles_afk: depends on your task, I suppose. I hardly ever need even the primitive locals, let alone anything larger-scope.

15:40 dmiles_afk: Scala did that just in case .. "because they used ScalaInt"

15:40 cemerick: rhickey: I know, I know. I'm just looking out for the whole general-applicability angle.

15:40 dmiles_afk: o they were avoid a worse case

15:40 its possible that Cljojures worsecase is not that bad

15:40 wtetzner_: if i do (SwingUtilities/invokeLater (fn [] (run-code "asdf"))), does run-code use the binding in the swing thread?

15:41 dmiles_afk: ,(+ 5 1)

15:41 clojurebot: 6

15:41 wtetzner_: is there a way to set a thread-local binding in the swing thread?

15:41 dmiles_afk: thats clojures worsecase i think

15:41 the (+ 5 1)

15:41 wtetzner_: without having to rebind for every fn i send to it?

15:41 dmiles_afk: well what would be more worsecase is (+ 2555 2551)

15:41 Chouser: wtetzner_: the only way the swing thread would have a local binding in place is if you put it right there in your anonymous fn

15:42 wtetzner_: in other words, "no"

15:42 wtetzner_: ok

15:42 Chouser: dmiles_afk: well, + is a clojure-inlinable fn, so it can actually be working on primitives.

15:42 wtetzner_: so if i want a way to access the main JFrame in my gui, i should store it in a ref or something?

15:43 Chouser: wtetzner_: yes, or a global var or atom, or maybe a promise if you want to get fancy.

15:43 wtetzner_: promise?

15:43 dmiles_afk: Chouser: (- 2555 (+ 2555 2551)) the result fn would need to be a primitive

15:43 rhickey: cemerick: I don't know that you need custom reader support for data literals like bit-sets, k-d trees, and skip lists, other than #your-factory-fn{...}

15:43 arbscht: wtetzner_: I like to create partial functions capturing that kind of context. see for an example http://gist.github.com/164652

15:44 dmiles_afk: ,(class (+ 2555 2551))

15:44 clojurebot: java.lang.Integer

15:44 Chouser: rhickey: ooh, I'd take #my-fn{...} in a second, esp. if I get to read the ... myself

15:44 dmiles_afk: well it will proably always say that ')

15:44 [12:44] <clojurebot> j

15:44 oops

15:44 cemerick: rhickey: you do if those (or whatever) are you bread and butter. What if you had to write #vector[...] every time you use one?

15:44 Chouser: #my-ns/my-fn{ ... } -- perfectly composable

15:45 dmiles_afk: well it will proably always say that 'java.lang.Integer' on (class...) becasue class takes an Object

15:45 cemerick: Chouser: ssshh, I'm swinging for the fences here! ;-)

15:45 dmiles_afk: would for instance (class...) have 8 differnt singatures?

15:45 rhickey: Chouser: it's not that simple:

15:45 user=> (def a 42)

15:45 #'user/a

15:45 user=> {:b a}

15:45 {:b 42}

15:45 Chouser: cemerick: but I don't want your uncomposable readers! :-)

15:46 dmiles_afk: (that what scala did.. but still)

15:46 actually maybe in the end scala and clojure would have 15 possibles

15:46 cemerick: Chouser: why not both? :-)

15:47 dmiles_afk: the [Z [B etc

15:47 rhickey: note how the compiler can generate a data literal expression that involves evaluation

15:47 cemerick: I know a couple of people for whom notation is *everything*, which is why I keep bouncing on this particular nerve

15:48 rhickey: cemerick: wanting something and providing an answer to these critical questions are two different things

15:48 Chouser: cemerick: yes, and those people would write a lib that required a notation that clashed with someone else's lib, and everyone would be stuck.

15:48 rhickey: also, there is distinguishing use in code from use in data files

15:49 in practice, reader macros are not often used in CL and when used in libraries, widely despised, due to these issues

15:49 Chouser: dmiles_afk: repl-utils/expression-info lets you see when the Clojure compiler would emit code that uses primitives.

15:50 dmiles_afk: Chouser: yeah i betting sometimes the compiler can identify a all primitive situation pretty well

15:51 Chouser: well, #*{} is about as intuitive a choice as you'll find, i think, for multimap

15:52 cark: rhickey : reader macros are maybe bad for libraries but sometimes usefull at the application level

15:52 Chouser: though #{} for very value is pretty noisy and potentially misleading.

15:52 rhickey: Chouser: I thought so, given assoc* and dissoc*, but open to suggestions

15:53 cemerick: rhickey: would Chouser's #ns/fn{...} idea be potentially better in terms of library interop (regardless of the evaluation issues)?

15:53 rhickey: Chouser: true, in the 'all keys will support multi' it's very verbose

15:53 * cemerick is working on learning something today

15:54 rhickey: cemerick: I don't know, I think Chouser wants more inside {} than I was talking about with #your-factory-fn{...}

15:55 but the point I raised about evaluation of subcomponents is important. Right now, e.g. #= does not eval subcomponents/args

15:55 so supports read-time constants only

15:56 #your/fn[every one of these is evaluated] would be doable

15:56 or #your/fn{every one of these is evaluated}

15:58 that's different from #your/fn{gets to read this and return some arbitrary thing}

15:59 but as I said, it's not that simple

16:00 when I read {:fred ethel :ricky lucy} you get a map of keywords to symbols

16:00 but the evaluator will in turn evaluate that map-as-code and try to resolve ethel and lucy

16:00 getting the same for your data structures would be more involved

16:02 Chouser: yes, I want more in #my-fn{...} than rhickey wants to give me.

16:03 rhickey: but perhaps I see your point -- the evaluator knows how to eval a map, but might not know how to eval a my-collection.

16:03 rhickey: Chouser: exactly

16:04 (def a 42) #my-collection{a} == ?

16:04 I presume you don't want a collection with a symbol in it

16:04 cemerick: I guess I keep thinking about it in terms of the clojure reader simply being a particular implementation that parses and evaluates things in a specific way...some other reader would have its own rules, but still apply them with the assistance of an evaluation mechanism that returns a value given a symbol.

16:05 rhickey: cemerick: reading and evaluation are separate

16:05 cemerick: oh, definitely...that's what I'm getting at

16:06 rhickey: but evaluation isn't just symbols, that's just my example. you could have calls, other nested data structures etc that need to be evaluated

16:07 cemerick: ah. See, I'm assuming that the userland reader would have to identify such things and hand them up to the default reader to be handled appropriately.

16:07 * rhickey thinks Chouser is reading Compiler.MapExpr right now

16:08 rhickey: cemerick: it's not happening at read time, but at evaluation time, later

16:08 Chouser: even without user reader macros, would you have similar questions about supporting more core collections?

16:09 rhickey: Chouser: it would be great to focus on collection extensibility right now, userland reader macros is an exhausting topic with no answers afaict

16:11 for truly extensible collection support you need: extensible syntax, a way to get at code for read-time data collection construction, a way to get at code for evaluation of custom collection literals

16:12 i.e. Expr support for your collection type

16:12 the latter is not nothing

16:13 Chouser: does CL not have this issue because its only literal is the list?

16:13 only literal collection

16:16 rhickey: Chouser: CL doesn't have any evaluation in data literals, only constants, and backquote, the latter is hardwired for lists and vectors

16:18 Howard: question about commiting changes to clojure-contrib

16:18 does Rich extend write access to the repository

16:18 or do we fork it, make changes, request a pull (via GitHub)?

16:18 (I'm on the contributor list)

16:19 Chousuke: for contrib, there are contributors, a handful of committers and rich

16:19 Chouser: Howard: http://clojure.org/patches

16:19 Chousuke: but most stuff is sent via patches, yes

16:19 Chouser: pull requests aren't used anywhere currently

16:19 kotarak: Pull requests require a high level discipline..

16:20 Which makes them not very suitable for open contribution, I guess.

16:20 Howard: Sorry I missed that ...

16:20 Chousuke: you'll be fine if you just use git format-patch to generate the patches from your commits

16:20 Howard: Sure, seems like a lot of trouble though

16:20 Chouser: Howard: the list of people with commit access is at the bottom of this page: http://github.com/richhickey/clojure-contrib/tree/master

16:20 Howard: it means I can't really be self sufficient

16:21 Chousuke: Howard: sure you can. just commit to your own git repo as much as you want and do a git format-patch when you're ready to send in your changes.

16:21 the patch files generated contain git commit info so all important data is preserved.

16:22 Howard: It's just a bit different from the Apache way, where once you are accepted as a committer, you can commit

16:22 rhickey: Chouser: In CL, if you want to do the equivalent of [a b c] you need `#(,a ,b ,c)

16:22 Chouser: right, clojure has four levels: user, contributor, committer, and Rich.

16:23 rhickey: ow

16:23 Howard: Ok, so just attach my patch to my ticket, then rich will apply it and close it

16:23 Chousuke: rhickey: is #() really equivalent to [] though? :/

16:23 Howard: And identify the ticket number is the commit message

16:23 rhickey: so Clojure is way ahead in having vectors/maps/sets with read/print/evaluation support

16:24 kotarak: Huge advantage! I really like the easy access to maps and vectors!

16:24 rhickey: Chousuke: no, that's my point CL #() is not Clojure []

16:24 Chousuke: Howard: you can add "fixes #nnn" to your commit message and assembla will autoclose the bug when it's committed :)

16:25 kotarak: Chousuke: which Rich doesn't really like, he prefers "refers #nnn"...

16:25 Chouser: Howard: if the patch is for contrib, you'll one of the committers will commit and close the ticket.

16:25 rhickey: nor is Clojure [a b c] == (vector a b c), because it reads as a true vector of symbols

16:26 Chousuke: yeah, that's what I thought.

16:26 Chouser: rhickey: it's that latter point that I'd not really internalized before.

16:27 Chousuke: Chouser: heh.

16:27 rhickey: Chouser: that's the key to print/read being a replacement for JSON/XML, useful when there's no eval at all

16:27 Chousuke: Chouser: it reads a data structure, then calls (vec stuff-that-was-just-read)

16:28 Chouser: or in my reader, I actually always read stuff into vectors (because they expand at the end) and then do (apply hash-map...) or (set ...) on it.

16:29 a bit wasteful but easy :P

16:30 Chouser: right, but I hadn't thought through the consequences of having things other than lists in what the reader produces. That is that eval has different behavior based on the type of thing that was read.

16:31 I mean, I guess I knew that, but didn't understand all the consequences.

16:31 Chousuke: it has consequences with macros too.

16:31 Licenser: Hi everyone

16:32 is there any list of the keywords Clojure has?

16:32 Chousuke: keywords? you mean special forms?

16:32 hiredman: they are listen on a side somewhere

16:32 slide

16:32 there are seven or so

16:32 Chousuke: def, fn* loop, let*, ., try, ... hmm. I forget.

16:33 Licenser: hmm yes the things I can put in the first argument of a () to do something, things like def and if

16:33 hiredman: Licenser: well you can put any function there

16:33 or any IFn

16:33 Licenser: I hean the build in ones, not self defined ones

16:33 so if yes but and not

16:34 kotarak: Licenser: (approximately) http://clojure.org/API

16:34 Chouser: Licenser: use the source!

16:34 Chousuke: ah, right, if of course.

16:34 hiredman: http://clojure.org/special_forms

16:34 Licenser: Use the source Luke!

16:34 hiredman: thanks that is what I was looking for :d

16:35 hiredman: this is lisp, the difference between built in and built on is negligible

16:35 Chousuke: that page is lying anyway. some of the special forms listed are actually macros

16:35 Licenser: oi :/

16:35 Chouser: right, depends on why you want to know

16:35 Howard: at the risk of sounding stupid; after I've attached my patch, what action do I take on the ticket (i.e., "mark ready to test") and do I reassign it?

16:36 kotarak: But the star form is the special form, fn=>fn*, let=>let*

16:36 Chousuke: yeah.

16:36 Licenser: Chouser: for highlighting source ^^

16:36 Chouser: Licenser: use the source if you want the actual list of real builtins. Use the web page if you want to know what's promised.

16:36 Licenser: ah. use the web page.

16:36 Chousuke: I wonder if newnew will cause fn* to go away.

16:36 kotarak: I highlight according to the web page.

16:37 Howard: I wonder if newnew will get a better name :-}

16:37 rhickey: so, back to multimaps - any feedback other than you're all disappointed you're not getting what you really wanted? :)

16:37 Chouser: the fact that fn is a macro but fn* is builtin is just an implementation detail -- may change at any moment.

16:37 rhickey: Howard: its has - reify

16:37 Chousuke: oh, right. you decided on that then? :)

16:37 cemerick: ah-ha, didn't know it was official :-)

16:37 hiredman: neato

16:38 rhickey: I could go with #mmap{...} pretending that one day #blah{} will be extensible

16:38 but Chouser's point on verbosity with all-multi-keys is valid

16:39 hiredman: #mmap would require some adjustment to the reader, wouldn't it?

16:39 rhickey: hiredman: yes

16:39 Chouser: rhickey: you specicially want to support providing a set at runtime for multiple values?

16:39 rhickey: this would be a new core datatype

16:40 Chouser: dunno, right now in the design I am supporting any collection as the init for a multikey

16:40 i.e. you can't have a singlekey that maps to a collection

16:41 Chouser: ah, ok ... I was just trying to phrase that point. :-)

16:41 rhickey: so #*{:a 1 :b [2 3]} would work too

16:41 hiredman: hmmm

16:41 rhickey: this mostly for the evaluated case #*{:a 1 :b (a-seq-fn)}

16:42 Chouser: what about {:a 1 :b #*expr} ?

16:42 Chousuke: wait, what datatype is this?

16:42 hiredman: multimap

16:42 Chouser: that way {:a [1 2] :b #*[3 4]} would have :a as a single key, :b as a multi

16:42 rhickey: Chouser: nothing around {}? multimap triggered by #* inside?

16:43 Chouser: sure

16:43 rhickey: how do you make an empty multimap or one initialized with only single keys?

16:43 Chousuke: that would make my reader design rather ineffective :-(

16:43 Chouser: or both, I suppose. #*{:a 1 :b #*[2]} My main point was new reader support for the mutli-values

16:44 hiredman: rhickey: well assoc* on a regular map could return a multimap?

16:44 rhickey: Chouser: are you saying :b is a multikey or :a?

16:44 Chouser: that doesn't help remove clutter, but it makes single-value collections possible.

16:44 rhickey: ooh, I meant :b as multikey, but the alternative is interesting.

16:44 rhickey: Chouser: I don't think I care about singlekeys mapping to collections

16:45 lots of complexity elsewhere if supported

16:45 Chouser: #*{:a #.:single :b [:multi]} bleh.

16:46 wtetzner_: so a multimap is a map whose keys can hold multiple values?

16:46 rhickey: I am trying to address #*{:a [1] :b [2] :c [3] ...} when you want all the keys to be multi

16:46 Chouser: yeah, though even that is better than #{} for each value

16:47 rhickey: wtetzner: basically, with the twist that some keys can be non-multi, and that is enforced

16:47 kotarak: Why not making multi the default? #*{:a 1 :b 2 #1 :c 3} (with c single key.)?

16:48 wtetzner_: rhickey: oh, i see

16:48 rhickey: so that's why a map of vectors isn't the same thing

16:48 Chousuke: #*[:a :b]{:a 1 :b 2 :c [1 2 3]}? :P

16:48 iffy.

16:48 rhickey: kotarak: taking colls in the literal is not bad, as (#*{:a 1 :b [2 3]} :b) -> #{2 3}

16:49 wtetzner_: are multimaps used often enough to give it reader syntax?

16:50 rhickey: wtetzner_: depends upon your domain

16:51 wtetzner_: maybe something like this: {:a 1 :b 2 | :c [1 2 3] :d [4]}

16:51 rhickey: so far today they seem not so popular :(

16:51 wtetzner_: where single keys and multikeys are divided by a |

16:51 Chouser: why not support both repeated keys *and* collection values to indicate multi.

16:52 rhickey: Chouser: repeated keys seem really painful

16:52 and would never print that way

16:53 cemerick: rhickey: I just don't see the big deal given update/assoc-in, sorry. :-|

16:53 rhickey: you've got the vision thing, though, which trumps a lot

16:54 Chouser: ok, so the real clutter issue is when you when you want to declare a key as multi but have zero, one, or a runtime expression value.

16:54 rhickey: cemerick: there are differences in seq/count, can test for contains-entry

16:54 Chouser: pretty much

16:54 cemerick: do you do anything with RDF?

16:55 cemerick: ah-ha

16:55 no, thank goodness

16:55 wtetzner_: rhickey: is it neccessary to have a special character at the front for it to be a reader macro?

16:55 Chouser: so now I'm liking wtetzner_'s suggestion

16:56 rhickey: Chouser: the problem with that (separator) is the asymmetry with whatever the factory fn will be

16:56 wtetzner_: why couldn't the factory function do something like that?

16:57 is | a legal symbol?

16:57 i guess it might be bound to something though

16:57 rhickey: wtetzner_: take | as an argument?

16:57 wtetzner_: rhickey: yeah, but i guess that's a bad idea

16:57 rhickey: very difficult, will mess up apply and composition in general

16:58 Chouser: #*[:a :b]{:c nil :d [1 2] :e 3 :b 5}

16:58 kotarak: rhickey: why do you need enforcement of single-keyd-ness?

16:59 wtetzner_: do reader macros require that the starting character is a special character?

16:59 Chouser: every key is multi unless noted in the []. (multi-map single-keys map-thing)

16:59 Chousuke: Chouser: heh, I suggested the same earlier ;P

16:59 wtetzner_: could you do something nicer like M{:a 1 :b 2 :c [1 2 3] :d [4]}

17:00 rhickey: Chouser: thinking through composition scenarios, I see needing to ask for single keys etc

17:00 Chousuke: wtetzner_: that makes symbol parsing a lot more complicated

17:00 Chouser: Chousuke: yeah, I saw that, but I thought you were listing the multis

17:00 saml: did you write a computer game in clojure? 2d or 3d with audio?

17:00 wtetzner_: ok

17:00 Chouser: Chousuke: though looking at it a again, perhaps you weren't. :-)

17:00 Chousuke: wtetzner_: it's easier to have some special character for use in reader macros

17:00 wtetzner_: but all of the special characters are starting to make it look too much like perl

17:01 maybe #M{...}

17:01 Chousuke: Well, ^#'foo is pushing it, yes, but ....

17:01 it's nowhere near perl.

17:02 Chouser: $_=~/(.)$/ # perl

17:02 wtetzner_: haha

17:02 i didn't say it was as bad as perl, just that i don't want it to get any closer to perl

17:03 Chousuke: but certainly alphanumerics are usable for reader dispatch, as long as the # remains in place :P

17:03 wtetzner_: ah

17:04 kotarak: When we drop the enforcement of single-keyd-ness, wouldn't then the hassle just disappear? #*{:a [1] :b [1 2 3]} ... Don't care for :a being single-key or not ....

17:04 rhickey: kotarak: It's an enhancement to the normal multimap thing, much easier to use these - without it there will always be some keys for which 'there should only be one' and manually enforcing that is tedious

17:04 kotarak: well, you'd say #*{:a 1 :b [1 2 3]} in that case then

17:05 only using coll when more than one

17:05 wtetzner_: what if you wanted a key to have a collection as its value?

17:05 but only one collection

17:05 Chouser: zero-value case is annoying too.

17:05 rhickey: wtetzner_: can't

17:05 Chouser: ?

17:05 JAS415: i don't get it, what does the * mean

17:06 rhickey: JAS415: placeholder for something indicating multimap

17:06 kotarak: rhickey: #*{:a [[1]] :b [1 2 3]} .... would allow that, again enforcing single-keyd-ness is the problem... (Just strip one set of [] to get the values...)

17:06 JAS415: oh

17:07 Chouser: #*{:a [1 2 3] :b [4] :c 5 :d nil} even if :a and :b are multis, and :c is single (ie. our clutterful option), what's :d? a single nil, or an empty multi?

17:08 wtetzner_: Chouser: if it was multi, wouldn't it be #*{:a [1 2 3] :b [4] :c 5 :d [nil]} ?

17:08 rhickey: Chouser: single nil, use [] for emtpy multi

17:08 wtetzner_: or that

17:08 Chouser: wtetzner_: [nil] would be a multi with currently just one nil.

17:09 ok, so clutterful handles zero value case ok: nil vs. []

17:09 rhickey: clutterful, h? :)

17:09 kotarak: I don't like the "no vectors" taste... :(

17:10 Chouser: rhickey: can you eloborate re: thinking through composition scenarios, I see needing to ask for single keys etc

17:10 kotarak: Then multi-maps don't nest anymore with the rest of the collections ...

17:10 rhickey: Chouser: what happens when you want to make a new multimap out of others?

17:10 kotarak: they nest in

17:11 a key point of multimaps is the flattening that they do. As cemerick has pointed out, you can have mappings to sets right now

17:11 kotarak: rhickey: But I can't do #*{:a []} (single-key with empty vector value)

17:11 rhickey: kotarak: I understand

17:12 Chouser: oh, we don't even have a 'push'. sheesh.

17:13 rhickey: Chouser: heh, I just did (doc push) before :)

17:13 wtetzner_: maybe: #M{[:a 1 :b 2] [:c [1 2 3] :d [4]]}, with a constructor function (multi-map [:a 1 :b 2] [:c [1 2 3] :d [4]])

17:14 or #M{(:a 1 :b 2) (:c [1 2 3] :d [4])}

17:14 Chouser: I think that's got the same composition problem that I'm trying to grok.

17:14 rhickey: wtetzner_: if you're not going to get out of :d [4] there's no point to separating them

17:15 Chouser: what's the zipmap equiv for multimaps?

17:15 keying off the collection-ality of the val is easy

17:15 separate keysets is hard

17:16 Chousuke: metadata? :P

17:16 Chouser: what will conj do?

17:17 rhickey: personally, most handwritten map inits are small, so I think this might be a non-problem. I'll go with collection inits for multikeys in the first pass and we'll see if it is a real problem

17:17 Chouser: (conj #*{} [:a 1] [:a 2]) ; ok or not?

17:18 wtetzner_: how about #M{:a 1 :b 2 :c |1 2 3| :d |4|}, so you're not using the vector syntax

17:18 although that has the constructor asymmetry problem

17:18 rhickey: Chouser: I think conj will do assoc*

17:19 since :a is not already there and single, will be ok, build a multikey for :a

17:20 kotarak: Why not making all keys multi per default and require a constructor for single keys? (multi-map [:a :b] :a 1 :b 2 :c [1 2 3])?

17:24 krumholt__: if anyone is particularly bored maybe make a patch so that bit-or accepts an arbitrary number of arguments :)

17:30 JAS415: im having too much fun searching for lolcats on twitter :-P

17:33 Chouser: JAS415: maybe make a patch so that bit-or accepts an arbitrary number of arguments :-)

17:33 JAS415: hahaha okay i'll look at it

17:33 Chousuke: shouldn't be too difficult :/

17:34 JAS415: yeah it should be just like + or -

17:35 kotarak: Why do I get that: "java.lang.NoSuchMethodError: clojure.lang.Namespace.importClass(Ljava/lang/Class;)Ljava/lang/Class;" when I try to compile c.c.lazy-xml?

17:37 Hmm.. I tells me, it's from seq_utils.clj:24...

17:38 alrex021: Hi guys. Need some help please to review a snippet of code I wrote. I pretty sure it can be inmproved

17:38 oops, trigger happy

17:38 kotarak: http://paste.pocoo.org/show/136443

17:38 ^^^ the stacktrace

17:39 Chouser: kotarak: doing anything unusual with classloaders?

17:40 kotarak: Chouser: not really. just setting up different compilation trees for the Ivy packages. Lazy-xml (/ seq-utils?) is the only package so far, where I see this-

17:41 melling: trying to get slime working. Get an error launching inferior-lisp... can't find swank.clj

17:41 java.lang.ClassNotFoundException: swank.swank (NO_SOURCE_FILE:0)

17:41 what do I have to set in my .emacs.

17:41 these files are in /opt/swank-clojure/swank

17:43 thought this would do it.

17:43 (setq swank-clojure-extra-classpaths (list "/opt/lib/java/clojure-contrib.jar:/opt/swank-clojure"))

17:43 kotarak: Chouser: Ok. Found the problem. For some reason, lazy-xml uses the clojure-1.0.0.jar, while the others use a more recent version.

17:44 Argh... DRY caught me again.

17:44 * kotarak has to investigate gradle to get rid of ant.

17:45 alrex021: I have two vectors of user roles. new-roles and existing-roles. I must remove old roles that are not in new-roles and add any from new-roles that re not in existing-roles. (I know I could just replace the old ones in existing-roles...but I actually want to leave those intact.) I'm sure there are better ways to do this. any comments welcome. http://gist.github.com/175860

17:47 I'm trying to compare some code I had to write today at work in pure java, quite a loop headache as compare to what I even have so far in clojure.

17:48 arohner: has anyone gotten slime to print test/is output in your slime window rather than the console when using slime-connect?

17:48 clojurebot: slime is icky

17:49 kotarak: alrex021: maybe you want sets?

17:49 arohner: alrex021: yeah, using vectors for this seems weird

17:50 I would use a set or a map

17:50 then you can use contains?

17:50 or set/difference

17:50 technomancy: arohner: try clojure-test-mode; it shows the test output in the test buffer itself.

17:51 arohner: technomancy: I don't have a clojure-test-mode, where do you get it?

17:51 JAS415: ok, i've made the changes to make it take multiple args

17:51 technomancy: arohner: http://github.com/technomancy/clojure-mode

17:51 haven't updated it for clojure 1.1 though. =\

17:52 JAS415: now i have to figure out assembla

17:52 melling: Put path in clj-server file: http://yusupov.com/blog/2009/basic-clojure-setup-part-2

17:52 I'm done!

17:53 arohner: technomancy: oh wow my clojure-mode is old. 2008/11/13

17:54 technomancy: arohner: you're missing out!

17:55 drewr: whoa

17:59 JAS415: how do i add a ticket to assembla?

18:00 rhickey: https://www.assembla.com/spaces/clojure-contrib/support/tickets

18:00 https://www.assembla.com/spaces/clojure/support/tickets

18:00 JAS415: ah thanks

18:00 rhickey: if you are not a contributor

18:03 hiredman: ~ticket #164

18:03 clojurebot: {:url http://tinyurl.com/kmlk4k, :summary "[PATCH] embedded constants", :status :test, :priority :low, :created-on "2009-08-02T03:20:33+00:00"}

18:04 hiredman: not that that has anything to do with anything, it just caught my eye

18:05 ~ticket #2

18:05 clojurebot: {:url http://tinyurl.com/l6lcfw, :summary "Scopes", :status :new, :priority :normal, :created-on "2009-06-15T12:35:58+00:00"}

18:07 alrex021: kotarak: here is an improved ver that uses sets with difference and intersection http://gist.github.com/175860

18:09 not to sure if its smart to to do difference and intersection and then use into to conjoin them

18:10 hiredman: clojure.set operations use sequences internally anyway

18:10 :/

18:14 ~ticket #112

18:14 clojurebot: {:url http://tinyurl.com/nbtghb, :summary "GC Issue 108: All Clojure interfaces should specify CharSequence instead of String when possible", :status :new, :priority :low, :created-on "2009-06-17T21:06:11+00:00"}

18:15 hiredman: ##java seemed to think this idea was broken for some reason, bugs with handling charsequences in jvm?

18:16 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4838318 ooh "3-Accepted"

18:17 kotarak: alrex021: what you do now is only the identity, no? A = A \ B union A intersect B, which is exactly what you wrote there.

18:24 bitbckt: ~latest

18:24 clojurebot: latest is 1382

18:24 Chousuke: hmm

18:24 that's somehow wrong.

18:24 hiredman: latest is left over from svn

18:24 ~commit

18:24 clojurebot: I don't understand.

18:25 hiredman: bah

18:25 bitbckt: I'm just exploring.

18:25 hehe

18:25 hiredman: ~last commit

18:25 clojurebot: Huh?

18:25 JAS415: user=> (bit-xor 1 2 3 4 5 6 7 8 9 10)

18:25 (bit-xor 1 2 3 4 5 6 7 8 9 10)

18:25 11

18:25 hiredman: huh

18:26 (doc bit-xor)

18:26 clojurebot: "([x y]); Bitwise exclusive or"

18:26 hiredman: JAS415: that throws an IllegalArgumentException for me

18:27 Chousuke: you need a CA to contribute though :/

18:28 even for trivial patches ;(

18:29 JAS415: yeah i need to submit the patch

18:29 hm

18:29 is there any reason to do (reduce / (x y) more)

18:29 instead of

18:30 (/ x (reduce * y more))

18:30 Chousuke: the two-argument versions are inlined

18:30 JAS415: yeah i think i got a patch for that too

18:30 Chousuke: and I think the former is neater.

18:31 JAS415: yeah but / is a lot less efficient than *

18:31 arohner: technomancy: when I install clojure-mode through ELPA, now C-c C-l (load file) doesn't work on new buffers created after I slime-connect

18:31 JAS415: just wondering if there was a situation where it was mathematically different

18:31 kotarak: ANd x is a function? (reduce / x (cons y more))

18:31 JAS415: like maybe with imaginary number or something

18:31 Chousuke: JAS415: hm, right.

18:31 technomancy: arohner: how about C-c C-k?

18:31 Chousuke: doesn't support imaginary numbers anyway

18:31 JAS415: (reduce / (/ x y) more)

18:31 Chousuke: er. /

18:31 JAS415: shuld be that, was a typo

18:32 arohner: technomancy: undefined

18:32 JAS415: okay

18:32 arohner: what function does that map to?

18:32 JAS415: i'll do it with the * anyway

18:33 technomancy: arohner: slime-compile-and-load-file

18:33 arohner: does it show "Slime[clojure]" in the modeline?

18:33 arohner: no, it shows just (Clojure)

18:33 buffers that were open before the slime connect work fine

18:34 technomancy: arohner: try M-x slime-mode then

18:34 arohner: hrm. there may be some funkiness in my .emacs screwing with clojure-install

18:34 let me retest

18:34 technomancy: somehow the hook to activate that automatically must not be run

19:32 JAS415: assembla is pretty neat

20:16 arohner: If I want to access a nested class, its (Outer$Inner/method), right?

20:16 http://webdriver.googlecode.com/svn/javadoc/index.html?index-all.html

20:17 (WebDriver$Options/setSpeed Speed/SLOW) is not working for me

20:17 or am I missing something?

20:18 rhickey: setSpeed is not a static method

20:20 arohner: what kind of driver are you using?

20:20 arohner: HtmlUnitDriver

20:21 krumholt__: if java expects null as a parameter can i just use nil?

20:21 rhickey: (-> (HtmlUnitDriver.) manage (setSpeed Speed/SLOW)))

20:22 some .s in there

20:22 arohner: rhickey: ah, thanks

20:24 durka421: krumholt__: yes

20:24 krumholt__: durka42, thanks

20:25 Chouser: rhickey: so you'd be open to 'cons' calling a method on a collection. It never does that currently.

20:26 rhickey: ,(doc cons)

20:26 clojurebot: "([x seq]); Returns a new seq where x is the first element and seq is the rest."

20:26 Chouser: I don't need a ruling immediately. :-)

20:26 rhickey: wouldthat still be true?

20:27 Chouser: yes

20:27 rhickey: then I think it's good

20:27 finger trees are uber-seqs

20:27 Chouser: ,(class (cons 5 '(1 2 3)))

20:27 clojurebot: clojure.lang.Cons

20:28 Chouser: PersistentLists are also seqs, but don't get to participate in cons.

20:28 rhickey: ,(class (cons 42 nil))

20:28 clojurebot: clojure.lang.PersistentList

20:28 Chouser: whee!

20:30 rhickey: not sure this should be:

20:30 ,(class (cons 12 (cons 42 nil)))

20:30 clojurebot: clojure.lang.Cons

20:30 Chouser: right

20:30 rhickey: but in any case cons makes no promise about the return type other than seq

20:30 Chouser: ,(take 4 (map class (iterate #(cons 1 %) nil)))

20:30 clojurebot: (nil clojure.lang.PersistentList clojure.lang.Cons clojure.lang.Cons)

20:30 Chouser: (doc rest)

20:30 clojurebot: "([coll]); Returns a possibly empty seq of the items after the first. Calls seq on its argument."

20:31 Chouser: (doc next)

20:31 clojurebot: "([coll]); Returns a seq of the items after the first. Calls seq on its argument. If there are no more items, returns nil."

20:31 Chouser: I should be able to do those too.

20:31 rhickey: right

20:32 otherwise you're not really a seq

20:32 Chouser: but that means my .seq will have to return this, while rseq can return a cursor object

20:32 rhickey: yes (identical? ft (seq ft)) -> true

20:33 Chouser: another thought I had was a .reverse that actually just flipped a switch to allow conj/pop from the other side.

20:33 rhickey: trickier will be wiring into concat

20:34 Chouser: IConcat? :-)

20:34 rhickey: could be

20:35 Chouser: I dunno thought, that would break the current docstring. not a lazy seq

20:35 back in a minute...

20:40 I would tend to think ft-concat is not the same thing as concat.

20:41 rhickey: why not?

20:41 there's just nothing to be lazy about

20:42 Chouser: concat works on anything seqable. ft-concat only works on ft's with the same measure/reduce functions.

20:42 clojurebot: functions are maps

20:43 rhickey: Chouser: you'll have to explain those to me more

20:47 Chouser: their first example is a measure of size and a reduce of add

20:48 so the measure is (constantly 1)

20:49 and the reduce is +

20:49 a node of 3 elements [1 2 3] would cache it's reduced measure of 3

20:50 these operations are done when nodes are constructured, and then used for operations like split

20:50 in this case, split can use these measures to ask for the nth element of the tree

20:51 but you might have application-specific functions as well, for priority queues and such.

20:54 rhickey: ok, so concat could concat 2 non-conforming fts

20:55 do your fts have to have measure/reduce fns?

20:55 Chouser: right, by walking them. but it would not produce a ft that you could split

20:56 no

20:56 rhickey: ok, then separate ft concat

20:57 Chouser: but you can't split without measure, just conj l/r

20:58 rhickey: do you support multiple measure/reduce pairs at once?

20:58 Chouser: huh. the paper doesn't seem to define pop/next

20:59 rhickey: I plan to. the paper supports multiples by combining functions -- my current plan is to allow a set of named measure/reduce pairs

20:59 rhickey: isn't pop whatthey ar ecalling deque?

21:00 Chouser: they define little triangles to the left and right, which are conj l/r

21:01 then they define reduce and seq-like views

21:01 I don't see an actual "deque" operation.

21:04 rhickey: I think pop/next are split

21:04 ?

21:04 Chouser: could be

21:06 but split as they define it requires a measure fn, and I ought to be able to do pop/next without any measure/reduce.

22:12 any reason delay is not IMeta?

22:29 I can't tell if reductions must be delayed, or if that's even possible.

22:40 JAS415: hmm

22:41 is binding as complicated as it seems to me?

22:43 Chouser: ok, I think can't be delayed.

22:44 JAS415: are you referring to the use of thread-local bindings, or something else?

22:44 JAS415: i guess i am just kind of wondering how I know when I am in a specific thread

22:44 in a swing app for example

22:45 like I do a binding to something and call (main)

22:45 then it seems like it gets unbound when I use menus and stuff

22:45 possibly because they're creating threads under the hood?

22:46 Chouser: (binding [x 5] (foo)) will only have x bound until (foo) returns

22:47 JAS415: ooh

22:47 okay

22:47 so it has to do with when it returns

22:47 hmm

22:48 Chouser: binding is very much a temporary kind of thing, for a particular dynamic excursion down the call stack.

22:49 JAS415: i was hoping i could create new threads with different bindings kind of enclosed in them

22:50 Chouser: if the thread stays busy in some kind of event loop, then wrapping a single binding around that will work.

22:50 tomoj: hmm.. would (Thread. (binding [x 3] foo)) work?

22:51 or since you're returning a function there, the binding is ignored?

22:51 Chouser: (Thread. #(binding [x 3] (foo))) would work

22:51 JAS415: what was trying was (thread. #(binding [x 3] (foo)))

22:51 problem was

22:52 (foo) returns

22:52 i still have the window open

22:52 and nothing is bound anymore

22:52 Chouser: right

22:52 JAS415: so i just need to keep it from returning

22:53 yeah so i can make it sleep

22:55 hmm

22:55 nope

22:55 (new Thread #(let [[con prov](login xx

22:56 xx)]

22:56 (binding [tw/*consumer* con

22:56 tw/*provider* prov]

22:56 (main-window)

22:56 (loop [] (recur)))))

22:56 doesn't seem to work

22:56 Chouser: aren't all swing events sent to a single thread?

22:56 JAS415: well that would explain a lot :-P

22:56 wtetzner: yeah swing isn't thread safe

22:56 JAS415: bummer

22:57 wtetzner: so you need to use (javax.swing.SwingUtilities/invokeLater some-function)

22:57 and it sends some-function to the swing thread

23:00 does anyone know how the swing thread starts?

23:01 oh

23:01 nevermind

23:02 http://www.javapractices.com/topic/TopicAction.do?Id=153

23:06 JAS415: hmm

23:07 maybe i'll try a different approach

23:11 wtetzner: i wonder if there's a way to intercept the creation of the swing event thread

23:11 to add bindings to it

23:12 Chouser: why not use lexical scope instead?

23:13 wtetzner: well, i was just thinking it would be nice to be able to bind the main JFrame to a swing var

23:14 since swing isn't thread safe, it feels wrong to store it in a global reference like a ref or atom, or global var

23:16 JAS415: ah

23:16 well what i was hoping to do was have multiple logins

23:16 which is actually kind of orthogonal to whether or not swing is thread safe

23:17 just that the things that have to activate and interact with the logins have to be in a specific thread if I want to use thread-local bindings

23:17 wtetzner: well you can use (javax.swing.SwingUtilities/invokeLater some-function) to interact with swing

23:21 JAS415: reason i would rather not do lexical scope is that it seems like i'd be passing a lot of stuff directly

23:21 Chouser: could you close over it instead of passing it?

23:23 JAS415: yeah i was considering that

23:23 generating all the functions when the person logs in and closing over the results

23:31 what if i just created a seperate process?

23:32 Chouser: wow. big hammer.

23:32 JAS415: yeah i guess too big

Logging service provided by n01se.net