#clojure log - Jun 24 2009

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

3:27 Lau_of_DK: Top of the morning gents

3:27 cgrand: morning Mr Lau!

3:50 frodef: so how do I specify the method class signature with proxy? I need one object with two methods with the same name but different argument classes..?

3:51 (mymethod [#^the-class arg] ...) seems not to be right?

3:59 hiredman: frodef: you don't

3:59 hoeck: frodef: proxy maps a clojure fn to each method-name, so you have to dispatch inside the fn

3:59 clojurebot: proxy is <Chouser> proxy teases with its ease of use, then suddenly betrays.

3:59 hiredman: what you do is you put a cond or similar inside the method

3:59 frodef: ah, ok. So both methods in the interface maps to the same-named fn. Thanks.

4:36 how do I ask wheter a value implements a certain interface?

4:36 (or is of a certain class?)

4:36 ah, instance?

4:37 ..for classes, but not interfaces.

4:38 urgh, for interfaces too. I got the argument ordering wrong. sorry about the noise.

6:33 how do I round a number to nearest integer? e.g. (round 10 3) -> 3

6:33 ..or (round (/ 10 3)) -> 3

6:35 sunwukong: round found in clojure.contrib.math works like your second example

6:37 frodef: ok, thanks.

6:43 AWizzArd: General question for your opinion: do you know/think that it is allowed to have a (clojure) program automatically gathering information from a website? For example look up automatically 3000 words in a dictionary?

6:45 sunwukong: imho legally: yes ; morally: depending on the actual server/amount of data

6:45 dhaya: AWizzArd: The same rules that apply for search engines crawlers apply. (robots.txt etc). Also, hitting the site without sufficient pause time, will likely get your IP banned.

6:55 AWizzArd: ah good, the robots.txt should help, thanks you two

8:36 rhickey: sweet, this is what's nice about being on the JVM. Had updated my os x java vm, now includes VisualVM...

8:37 so I type jvisualvm at a prompt, VisualVM comes up, calibrates for my machine, show a gui, oh look, there's my (already running) repl session, connect, start getting monitoring, proifiling etc

8:40 not as powerful as yourkit, but handy

9:02 Chouser: rhickey: I think you have enough earnings from Clojure T-shirts to offer a bounty for contrib.jar

9:02 rhickey: Chouser: heh, now I need to bribe, eh?

9:03 mblinn: well you could pay in t shirts

9:03 Chouser: bah, a couple dollars short, at least for some shirts.

9:03 rhickey: just making you aware of your options. :-)

9:04 rhickey: thanks

9:04 Chouser: ah, it looks like any white T would be covered.

9:05 * rhickey just dropped $200 of donation money on another year of wikispaces

9:06 rhickey: hmm, I see "What would it take?" implies a bribe possibly

9:07 Have been working on pre/post conditions

9:07 Chouser: cool

9:09 rhickey: something like:

9:09 (defn foo

9:09 #^{:pre [(even? x) (< x y)] :post [(not (nil? _))]}

9:09 [x y] ...)

9:09 eventually some mojo to make that:

9:09 (defn foo

9:09 [x y]

9:09 {:pre [(even? x) (< x y)] :post [(not (nil? _))]}

9:09 ...)

9:10 but still yielding the map as metadata on the arglist

9:10 Chouser: I've been telling people that Clojure will probably eventually have some kind of compile-time assertion system where "classic" static typing would be a subset. Is that roughly true?

9:10 rhickey: thus tools could find and display via metadata

9:11 Chouser: that's one idea, built on some type of built-in logic lang like datalog/prolog

9:11 Chouser: yeah, ok. That was my impression.

9:11 rhickey: would be a hybrid of checker and analysis tool

9:12 one point on the post conditions is how to label the return value (_ above)

9:12 Chouser: runtime pre/post is good too of course. Do you imagine it being used mainly during testing and turned off during production?

9:12 rhickey: options are _, or the fn name (would require it be named)

9:13 Chouser: that depends on the app, so there will have to be some flags

9:13 Chouser: _ elsewhere has come to mean "I don't care" ... might be pretty confusing to overload that meaning here.

9:13 rhickey: considered assert no/yes/condiionally (supply a var)

9:14 Chouser: agreed, _ means don't care everywhere else

9:14 achim: how about making % readable outside #(...) for such things (similar to unquote)?

9:14 rhickey: could use a fixed name, like 'ret'

9:14 achim: I have though about that

9:14 Chouser: achim: I was wondering that too

9:15 rhickey: one problem is that it would allow a lot of errors to flow through and become 'I don't understand %', also would let people do (let [% 42] ...)

9:16 right now when you see % you know you are in an anonymous fn def

9:16 Chouser: people can already do (binding [map filter] ...) Just because it's bad doesn't mean it has to be forbidden.

9:16 rhickey: agreed

9:17 one other point was possible destructuring of return value for post

9:17 Chouser: hmmm

9:17 rhickey: else :post [(let [[x y] %] ...)]

9:18 ok if only one test, tedious if more

9:19 Chouser: right, but giving a spot in which to name the rtn value would solve both the naming and destructuring at once.

9:19 rhickey: Chouser: that's something different altogether, seems like a hassle

9:19 Chouser: :rtn rtn :post [(< 5 rtn 10)]

9:20 rhickey: I don't like it separate from post

9:20 Chouser: yeah, that was to avoid :post [rtn (< 5 rtn 10)]

9:20 rhickey: exactly

9:21 but :post [aname ...] is the best I could come up with, just irregular

9:23 either name is always required, or must be a symbol/vec/map binding form

9:23 will work until we have lists as destructuring forms :)

9:26 Chouser: I don't think 'always required' is so terrible, but changing from binding to test exprs without sentinel in a single vector's a bit tricksy

9:26 rhickey: agreed, not done anywhere else

9:27 lpetit: why not a short and a long form ?

9:27 Chouser: [:pre (< 5 x) (even? x) :post [rtn] (< 5 rtn 10) (odd? rtn)]

9:27 eh.

9:27 achim: might type-based preconditions eventually be a way to avoid boxing/unboxing of numbers? i.e. if the args to a function are constrained to be ints, would it be possible to generate bytecode that took unboxed ints as arguments?

9:28 rhickey: achim: no

9:28 Chouser: I was thinking having the binding form always in a vector might help it stand out, but that doesn't really look much less confusing.

9:28 lpetit: short form takes directly a vector of forms

9:28 long form takes a map with :rtn (taking possibly a binding) , :tests (or something else) taking the vector of forms

9:29 rhickey: Chouser: plus the result is still a to-be-parsed bag

9:29 Chouser: not much point if the long form is longer than (let [[x y] %] (and ...))

9:29 rhickey: lpetit: I'd really like to avoid that kind of thing. ns/require/use are the most complicated parts of Clojure for that reason

9:30 lpetit: rhickey: I understand

9:30 Chouser: now's not the time to discuss, but I'd love to require removed and 'use' simplified. I think it can be done.

9:32 lpetit: having the output follow a given "destructuring form" may convey enough information on itself to deserve not being mixed with other post conditions.

9:33 frodef: is there some variable somewhere that limits the size of stacktrace that gets printed?

9:33 rhickey: I'm going to work on the presumption that multi-test postconditions requiring destructuring will be rare

9:33 frodef: I have a stack overflow that I find it hard to find the source of.

9:34 Chouser: frodef: you might look at clojure.contrib.stacktrace

9:35 lpetit: So maybe having along with :pre and :post some :rtn-struct (I'm really bad at naming things :-(.

9:35 If no :rtn-struct (or some really better name!) is provided, then use % or the function name or whatever you come up with as a default value to reference the return value in the post conditions

9:35 If :rtn-struct is provided, then the symbols (either a simple one to name the result, or more complex ones when destructuring is leveraged) are provided for each form in the :post vector ?

9:35 clojurebot: http://clojure.org/data_structures#toc10

9:36 frodef: Chouser: ok, thansk

9:38 lpetit: so the simple case : :post [(pos? %)]

9:38 the moderate complex case :ret-struct [k v] :post [(not (nil? k)) (not (nil? v))]

9:38 note that :ret-struct could then be used to externally document the structure of the return value. Maybe I don't like that so much, because we do not separate whether the destructuring is used for documentation or for not DRYin the post-condition code ...

9:39 In the same time, the post condition code serves as documentation ....

9:40 Chouser: lpetit: the docs point is interesting -- very similar to how args are used now: destructuring for practical as reasons, but by default included in the docss.

9:42 frodef: hm.. these lazy lists are no fun debugging, are they.. :)

9:43 Chouser: frodef: can be a bit tricky. if you can handle a dorun temporarily, that sometimes helps.

9:44 lpetit: Chouser: maybe just the name :ret or :rtn instead of :ret-struct could be sufficient : it would document if anything is guaranteed by the function in terms of structure (even a single symbol is an explicit information that *nothing* is guaranteed, which is an indication)

9:44 frodef: Chouser: doall should do the same, no?

9:45 lpetit: But maybe it is too early and overlapping with the general problem of how to optionally expose type information

9:45 Chouser: frodef: well it de-lazy's your seq. Might be unacceptable depending on why your seq is lazy, but if it's ok it may shorten your stack trace and make things happen in a dynamic context that is less surprising.

9:46 lpetit: except it's so nicely symmetric with input args.

9:51 weissj: what is the clojure equivalent of mapcar?

9:52 Chouser: weissj: I think just 'map'

9:52 lpetit: Chouser: yes, indeed. So you like the idea ?

9:53 Chouser: lpetit: well, I like the idea of having a place to explicitly declare return value destructuring for use in docs and post conditions. Haven't seen a syntax I like yet though.

9:55 (defn [a b c] :rtn [a] ...) except that looks like it might return the value of arg a, which is of course completely wrong.

9:55 lpetit: :returns ret-name :post [(pos? ret-name) (even? ret-name)]

9:55 or :returns [key val] :post [(not (nil? key)) (pos? val)]

9:55 inserted in the map along with :pre , :docstring ... keys

9:56 Chouser: lpetit: I don't think that's terribly, but rhickey already said he didn't like it separated from the :post exprs.

9:56 terrible

9:58 lpetit: (defn foo #^{ :pre [(even? x) (< x y)] :returns [k v] :post [(not (nil? k)) (> v y)] } [x y] ...)

9:59 Chouser: well, the args names are separated from the :pre, and that seems not to be a problem, though :-)

9:59 Drakeson: assume (f l) -> [l1 l2]

9:59 how can I partition a list by iteratively applying f to the current list, spitting out l1, and keep l2 as "current list"? is there a way better than loop?

9:59 lpetit: ,(doc partition)

9:59 clojurebot: "([n coll] [n step coll]); Returns a lazy sequence of lists of n items each, at offsets step apart. If step is not supplied, defaults to n, i.e. the partitions do not overlap."

10:00 lpetit: oh no

10:00 Chouser: Drakeson: example?

10:01 I don't really understand what are in l1 and l2

10:01 lpetit: ,(doc split-with)

10:01 clojurebot: "([pred coll]); Returns a vector of [(take-while pred coll) (drop-while pred coll)]"

10:03 Drakeson: assume I call it partition-with. (partition-with #(split-at 3 %) (range 1 10)) -> [(1 2 3) (4 5 6) (7 8 9)]

10:05 Chouser: ahh

10:06 returning a vector means non-lazy, so it can be built on reduce

10:06 frodef: increasing the jvm's stack size seems to help me.. consequently I suspect that the zip-filter.xml uses stack O(n) to the XML input size?

10:07 Drakeson: Chouser: laziness > vector, assume it returns a list then.

10:13 ,lisppaste

10:13 clojurebot: java.lang.Exception: Unable to resolve symbol: lisppaste in this context

10:13 Chouser: ,url

10:13 clojurebot: java.lang.Exception: Unable to resolve symbol: url in this context

10:13 Drakeson: ~paste

10:13 clojurebot: lisppaste8, url

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

10:14 Drakeson pasted "partition-with" at http://paste.lisp.org/display/82424

10:14 Drakeson: now, that is not equal to some other function we already have, right?

10:16 Chouser: Drakeson: I don't think so.

10:16 Drakeson: thanks

10:16 Chouser: for some cases, contrib.seq-utils/partition-by might suffice, but it's doing something a bit different.

10:17 Drakeson: I stole it from partition-by

10:17 Chouser: oh, ok.

10:17 Drakeson: (modified it a bit)

10:17 btw, I need that function for parsing.

10:18 Chouser: I think partition-by could be written using split-with and your partition-with

10:32 lpetit: http://clojure.org/lazy says "lazy-seq goes at top level of lazy sequence function" , and also "lazy-seq and delay both perform closed-over local clearing on the tail call of their body", so my question is : could there be a problem with the pasted partition-with code ? if not, are there corner cases where not placing lazy-seq as the top level form of lazy sequence function could have memory...

10:32 ...problem ?

10:39 ?

11:45 rhickey: Drakeson: that code is not fully lazy

11:46 Chouser: btw, someone pointed out that reduce on range is slower in chunked than master.

11:47 I had to chain 2 or 3 more chunked operations before the chunking was a win over the Range object.

11:47 rhickey: Chouser: I know, I took out the IReduce special paths in order to see what matters, reduce on range being a nice demo but not typical

11:47 Chouser: right

11:48 tsdh: Hi. I'm currently transforming some clojure code into an eclipse projects to make it appealing to my colleagues.

11:48 rhickey: just added reduce on the chunks themselves, with other tweaks today (reduce + (filter even? (map identity v))) almost 2x as fast as yesterday (in chunks), and 5x as fast as pre-chunks

11:49 tsdh: In one clojure app, I use some images in the GUi. Now I have the code in src/foo/bar/baz.clj and the images in icons/*.png. But I don't have a clue howe to reference them...

11:50 (ClassLoader/getSystemRosource "icons/a.png") returns nil. Adding several ../ in front doesn't make it happy, either.

11:50 Drakeson: how would you serialize an object into a file? would you use spit and pr-str ?

11:51 stuartsierra: Drakeson: yes, or open a writer and use pr

11:52 Drakeson: how would you get rid of *print-level* and *print-length* temporarily?

11:52 ,*print-level*

11:52 clojurebot: 30

11:52 stuartsierra: (binding [*print-level* nil, *print-length* nil] ...)

11:52 tsdh: I think in Java I would use getClass().getResource(relativePathFromThis), but that has no equivalent in clojure, afaikt.

11:52 Drakeson: aaah, that's it, thanks.

11:55 tsdh: Oh, using simply (ImageIcon. "icons/a.png") works. Well, most often the simplest solution is still the best.

11:55 ;-)

12:09 baetis-fly: Can anyone explain when you'd want to use definline?

12:09 opqdonut: for performance reasons i guess

12:10 Chouser: if you want to take or return primitives in some cases, but allow your fn to be used in other higher-order cases as well.

12:11 baetis-fly: Let me be more specific. In compojure, there is a definline servlet which takes a function and creates a proxy servlet for the route. If I called (servlet) in the same namespace as my route (function) then i can do hot reloads when i redefine the function. When i call it from another namespace, that no longer works.

12:12 Chouser: baetis-fly: link to that code?

12:13 baetis-fly: Chouser: sure, one sec.

12:14 http://github.com/lrenn/compojure/blob/4a2079d1a28cddcb174c4a7f650c6a70e3258f31/src/compojure/http/servlet.clj

12:16 It's that "automatically updates if the routes binding is redefined" part that stops working when i move the servlet call into a different namespace than the route definition.

12:18 Chouser: I'm not sure why that's not a macro. Clearly there's something I'm not getting here.

12:19 baetis-fly: Chouser: That's what I thought. Which is why I asked what definline was used for. I'm just not sure why James is doing it that way. I'll goto the source. Many thanks Chouser.

12:34 combasa: morning

12:35 rhickey: what's the best way to push a local branch to github and have it be tracked? github's recipe here: http://github.com/guides/push-a-branch-to-github seems to leave it untracked

12:36 last time I had to delete local after push, then branch --track, seems wrong

12:36 Chouser: rhickey: you mean you want plain "git push" and "git pull" to operate on that branch?

12:37 rhickey: when in that branch locally, yeah

12:37 that's how chunks is working

12:37 Chouser: oh, I see. I'm still learning how to use git against a git remote (instead of svn remote)

12:37 combasa: I wish I knew more about git, im just learning

12:38 Chouser: I've edited .git/config manually before, but I bet that's not right.

12:38 or rather that there's something better.

12:38 Chousuke: use git config :P

12:39 rhickey: for chunks I did git push origin chunks, git branch -d chunks, git branch --track chunks origin/chunks

12:39 Chousuke: basically, you need to set configure branch.<name>.remote and branch.<name>.merge

12:39 rhickey: couldn't find a way to push with tracking

12:40 Chousuke: so git config branch.chunks.remote origin; git config branch.chunks.merge chunks

12:40 rhickey: Chousuke: I understand, but, ugh

12:40 Chousuke: actually, if the remote is origin, the first config is unnecessary

12:42 rhickey: this recipe seems oriented towards knowing you want a remote branch up front:

12:42 git push origin master:refs/heads/some_branch

12:42 git fetch origin

12:42 git branch −−track some_branch origin/some_branch

12:42 git checkout some_branch

12:46 Chousuke: git checkout -b branch origin/branch sets up tracking by default

12:46 hmm

12:47 rhickey: Chousuke: that's not the scenario

12:47 combasa: ya i was going to say wouldnt `git checkout -b mybranch master` make mybranch your current branch, then you could setup remote and push be pushing with that?

12:47 rhickey: local branch exists, want to create on remote with tracking

12:47 Chousuke: well, for that you'd need the two git config commands.

12:48 then just push

12:48 rhickey: using commands, not config file editing

12:48 Chousuke: I get the config file method

12:48 Chousuke: as I said earlier, just: git config branch.chunks.remote origin && git config branch.chunks.merge chunks

12:48 could probably make an alias for that.

12:49 combasa: haven't tried but why not setup branches in their own directorys then you dont need multiple configs each repository would have its own, not sure how you'd setup a branch in a different directory though

12:52 I'm going to have to re-read `git help branch` again I see

12:53 Chousuke: you can't really have a branch in a different directory other than by cloning

12:54 but clones of local repositories are cheap, as git just uses hardlinks whenever it can

12:55 combasa: yeah I realised it was a dumb idea :P

12:56 actually that reminds me, I wanted to ask.. if I wanted to start looking into the clojure source where would be a good place to start?

12:56 Chousuke: which part of the source?

12:56 combasa: yes which part

12:56 Chousuke: I mean, the java or the clojure side? :)

12:56 core.clj is pretty easy to understand.

12:57 the java stuff... not quite. :P

12:57 combasa: I'll have a look there then

12:57 where would be a good java place to start?

12:58 Chousuke: I haven't looked at it much :)

12:58 I guess it depends on what you want to know.

12:59 combasa: is the goal to have it all done in clojure at some point?

12:59 Chousuke: well, most, anyway

12:59 but that's probably not going to happen very soon :/

12:59 combasa: well I don't think it really matters either way does it

13:01 Chousuke: hmm, interesting

13:01 there's a Seqable.java~be56ab81e88f8001494058a055089e982595c453 in my clojure source tree. in src/jvm/lang :P

13:01 looks like it's untracked.

13:07 amunite: hi all. i'm following http://yusupov.com/blog/2009/basic-clojure-setup-part-1/ to setup clojure in os x, but i cannot make it work. java is unable to find clojure.jar at all. any advice or clue?

13:08 combasa: do makes use .bashrc files? im on linux

13:08 mac's I mean

13:09 kotarak: When you use bash... then "yes" I suppos.

13:09 combasa: I see, maybe I'll just have a look at the guide first

13:09 Chousuke: by default, Terminal.app uses login as the shell, so it uses .profile

13:09 but if you use bash then bashrc will matter too.

13:13 combasa: hmm that guide smells a little funny to me

13:16 technomancy: it's pretty old

13:16 well, sort of old.

13:17 I guess the move to git is recent enough not to call it old. =)

13:26 Jomyoot: Is there a web framework for clojure?

13:27 combasa: I believe enclojure is a web framwork, but I haven't looked at it yet

13:27 slashus2: ~compojure

13:27 clojurebot: compojure is http://github.com/weavejester/compojure/tree/master

13:28 slashus2: ~ring

13:28 clojurebot: ring is http://github.com/mmcgrana/ring/tree/master

13:28 combasa: ah right, compojure

13:28 Jomyoot: anything close to rails?

13:28 combasa: whats enclojure?

13:28 slashus2: A netbeans plugin for clojure.

13:28 combasa: ah right

13:28 Jomyoot: how is performance of enclojure vs. scala?

13:44 slashus2: Could count be made chunk aware?

13:58 quidnunc: cgrand: Can you give me an example of how to use the text-node selector?

14:00 cgrand: quidnunc: at last :-)

14:02 (select nodes [:abbr :> text-node]) should return a seq of string

14:03 quidnunc: cgrand: Sorry, different time zone + work makes it hard for me to catch up with you.

14:04 cgrand: and I'm sorry that today I have to run pretty soon

14:04 quidnunc: cgrand: Me too :)

14:04 cgrand: quidnunc: mail me

14:05 quidnunc: cgrand: :abbr is a placeholder for a tag name?

14:05 cgrand: yup but it's also a real tag-name

14:05 have to go

14:05 quidnunc: cgrand: Thanks

14:09 lisppaste8: slashus2 pasted "chunk count" at http://paste.lisp.org/display/82446

14:09 slashus2: What do you all think of this?

14:13 There are probably some improvements that could be made to the code, but you get the idea.

14:14 cemerick: wow, almost a 2x speedup.

14:14 slashus2: yup

14:14 cemerick: should I expect the chunked stuff to make all seq operations faster in general (map, filter, etc)?

14:14 slashus2: Range has taken a pretty significant performance hit from generating a chunked seq though.

14:14 Chouser: (count (range ...)) is constant time on master

14:16 slashus2: Chouser: I looked at the code in RT and it looked like it incremented a counter.

14:16 Chouser: slashus2: what you've got seems reasonable. I wonder if chunk producers other than range would see much benefit.

14:17 slashus2: Chouser: I guess range's performance will increase later..

14:18 Chouser: slashus2: RT.count uses a counter if the collection is not Counted.

14:18 If it's Counted, it asks the object to count itself -- for things like vectors and Range, this is constant time.

14:20 slashus2: I see.

14:20 I guess we could also make chunks Counted...

14:21 Chouser: but on the chunked branch, range does not use Range, so your chunk-count has benefit there.

14:24 (let [v (vec (range 1e6))] (time (chunk-count v)))

14:24 it's interesting to compare that with core/count.

14:25 oh, nm

14:25 that's just showing that chunk-count should check for 'counted?'.

14:26 (time (chunk-count (map identity (range 1e6))))

14:26 I think that's closer to what I meant to test. Looks like chunk-count still helps quite a bit.

14:27 slashus2: I think rhickey is accepting chunked versions of seq-processing functions.

14:30 rhickey: slashus2: counting non-counted things is a waste, making faster not that important

14:31 slashus2: range is work in progress, will be at least as fast as it was

14:31 slashus2: Point taken.

14:31 Just experimenting

14:31 rhickey: Counted implies constant-time, chunked seqs can't generally beCounted, though some specific ones can

14:32 Chouser: I thought writing a chunking 'iterate' might be fun.

14:33 rhickey: Chouser: you mentioned that before, one issue is the 'chunked' lazieness, might be ok for some usages but not others

14:33 Chouser: mm... good point.

14:33 rhickey: don't want to break those all important fib benchmarks :)

14:33 Chouser: heh

14:33 same thing with 'repeat' I suppose.

14:34 rhickey: repeat can cache the thing

14:34 not really doing more work like iterate would

14:34 Chouser: sorry, 'repeatedly'

14:34 rhickey: ah

14:35 Chouser: (repeatedly #(.readLine f))

14:36 rhickey: we'll have to see what people want most with chunks in place, I know for me I care much more about not fully realizing intermediate results than I do never moving ahean more than one, what matters is that there be a recipe for those that want the latter

14:37 there will have to be a seq1, e.g. to stream singular values from something that would otherwise be chunked

14:37 but iterate1, repeatedly1... I don't know

14:38 Chouser: well, repeatedly's specifically for side effects -- much more likely one extra step to be undesirable.

14:38 not sure about iterate

14:39 rhickey: also there's no inherent indexed structure behind readLine, and I/O time is likely going to dominate seq overheads

14:40 as will any other non-trivial work

14:41 the chunked seqs most benefit the very lightweight work people often want to do with HOFs, but usually get penalized there vs loops

14:46 name of *flag* for controlling pre/post asserts? (when false turn into no code at all)

14:47 Chouser: *check-conditions*

14:47 :-P nm.

14:48 rhickey: matbe to toggle all assert?

14:48 maybe

15:17 ctdean: It's been a long while since I updated my clojure.jar. Is there a version of clojure-contrib that matches clojure_1.0.0 or should I just pull the bleeding edge for both?

15:18 Chouser: ctdean: afaik, master contrib currently still works with clojure 1.0

15:19 ctdean: Is that just svn update from my clojure-contrib dir? or is there a better place for me to download it?

15:20 Chouser: contrib and clojure have moved to git

15:20 ctdean: aha, didn't know contrib had move also. Thanks so much

15:21 Chouser: http://github.com/richhickey/clojure-contrib/tree/master

15:21 ctdean: Perfect, got it

15:23 All that worked great.

15:25 rhickey: pre/post conditions are up - feedback welcome

15:30 *assert* false nils-out asserts

15:30 Chouser: % as post arg

15:32 Lau_of_DK: Hi everybody - I just want to let the people watching ClojureQL know that we're sorry that development has been so slow for the past 6 months - We are now up and running at full speed and have 2 working demos, 1 for MySql, 1 for Derby! We are now moving on to implementing JOINS, and that will but us at the very edge of version 1.0 :)

15:33 Chouser: Lau_of_DK: great!

15:33 rhickey: Lau_of_DK: cool - link?

15:34 kotarak: http://github.com/Lau-of-DK/clojureql

15:34 Don't look too closely. ;)

15:34 Lau_of_DK: http://github.com/Lau-of-DK/clojureql/tree/master

15:34 oh :)

15:38 Sidenote: We are implementing dbms-specific routines in backend/derby.clj for example. If anybody would like to contribute patches for PostgreSql, Oracle, etc, it would be greatly appreciated :) We are currently targeting MySql and Derby exclusively.

15:47 Jonathan-Smith: are there any tutorials on how to properly structure/build a clojure project?

15:47 for example if I have multiple source files with different name spaces, how do i tell clojure to load them in a certain order

15:49 markcol: You can take a look Stuart Holloway's Lancet project that goes with the book "Programming Clojure". The sources are on github at http://github.com/stuarthalloway/lancet/tree/master

15:49 ctdean: Also the http://clojure.org/libs is reference page about this subject

15:52 Jonathan-Smith: cool, thanks

17:01 bpattison: is there a function that returns a list of string delimited by line breaks? I tried (re-split #"\n" lines) but it throws away lines that only have a line break in them, i.e. empty string

17:02 I also tried (line-seq lines) but lines is a string and not a rdr

17:02 Chousuke: you could wrap it in a StringReader

17:03 kotarak: ,(with-in-str "a\nb\c\n" (line-seq *in*))

17:03 clojurebot: Unsupported escape character: \c

17:03 kotarak: pfff

17:04 Lau_of_DK: Is the Google Code SVN no longer updated, with the adoption of Git ?

17:04 kotarak: ,(with-in-str "a\nb\nc\n" (line-seq *in*))

17:04 clojurebot: java.lang.ClassCastException: clojure.lang.LineNumberingPushbackReader cannot be cast to java.io.BufferedReader

17:04 kotarak: -.-

17:06 ctdean: Yes, only github now

17:07 rhickey: svn, what's that?

17:07 hiredman: har har har

17:07 ctdean: ,(re-seq #".*\n?" "abc def\n123\n\n789")

17:07 clojurebot: ("abc def\n" "123\n" "\n" "789" "")

17:07 Chouser: bpattison: re-split shouldn't throw away empty strings.

17:08 Lau_of_DK: Cool :)

17:08 rhickey: What changed your mind ?

17:08 ctdean: Almost right on the regex

17:09 Chouser: ooh, instance is called "new"?

17:09 ,(re-split #"\n" "a\nb\nc\n\nd\n\ne")

17:09 clojurebot: ("a" "b" "c" "" "d" "" "e")

17:09 bpattison: (re-split #"\n" "l1\nl2\nl3\n\n\n") ---> ("l1" "l2" "l3") instead of ("l1" "l2" "l3" "" "" "") -- but I haven't update my clojure environment for a while

17:09 Chouser: ,(re-split #"\n" "a\nb\nc\n\nd\n\ne\n\n\n")

17:09 clojurebot: ("a" "b" "c" "" "d" "" "e")

17:10 rhickey: Lau_of_DK: it wasn't a changeof mind, it was finding the answers to a set of questions: hosting the code (github), tools (IntelliJ git support is good), collab services I could use for Clojure and commercial work (assembla)

17:10 Chouser: hm, trailing empty lines are tossed.

17:10 Lau_of_DK: rhickey: I see

17:10 ctdean: That is the perl split behavior

17:11 Chouser: huh. it seems rather unfortunate.

17:11 bpattison: no worries, now I know how it works - I'll just work around it

17:11 Chouser: ,(re-split #"_" "a_b_cd__ef___g___h_")

17:11 clojurebot: ("a" "b" "cd" "" "ef" "" "" "g" "" "" "h")

17:12 rhickey: Chouser: not sure about new, will need to be able to distinguish (new Classname ...) from (new instancename [bases] ...)

17:12 ctdean: try giving a limit, that might change it

17:12 Lau_of_DK: btw, rhickey, thumbs up on the pre/post conditions, thats awesome

17:12 rhickey: anyone try them yet? (pre/post)

17:12 ctdean: ,(re-split #"_" "a_b_cd__ef___g___h_" -1)

17:12 clojurebot: ("a" "b" "cd" "" "ef" "" "" "g" "" "" "h" "")

17:13 bpattison: ah! that worked

17:13 ctdean: yep, it's java copying the perl behavior

17:13 * rhickey still trying to muster up the courage to tackle new-new

17:13 bpattison: works perfect now -- thanks!

17:15 itistoday: rhickey: i was wondering if there was any way to improve closure's api docs?

17:15 rhickey: I come from newLISP, and I'd like to get to know Clojure too, but its api docs are far less easy to navigate and are much less indepth

17:15 rhickey: itistoday: improve how?

17:16 itistoday: rhickey: i.e. have functions grouped by area (string manipulation, list manipulation, file manipulation, etc)

17:17 Chouser: (defn re-split [p s] {:pre (instance? java.util.regex.Pattern p)} (seq (.split p s)))

17:17 itistoday: rhickey: this is how newLISP does it: http://www.newlisp.org/manual_frame.html

17:17 Chouser: then this should fail, right? (re-split "_" "a_b__c___d_")

17:18 rhickey: itistoday: newLisp has to implement a lot of fns Clojure doesn't, e.g. files, sockets etc

17:18 but what Clojure does implement is divided up along the left, with sections like http://clojure.org/sequences

17:18 Chouser: ah, need another vector.

17:18 rhickey: that have lists of sequence fns

17:19 itistoday: rhickey: ah, OK thanks I'll try to get used to that

17:19 Chouser: so this works: (defn re-split [p s] {:pre [(instance? java.util.regex.Pattern p)]} (seq (.split p s)))

17:20 rhickey: itistoday: you'll also want to keep this handy: http://java.sun.com/j2se/1.5.0/docs/api/

17:20 ctdean: itiistoday: If you have an idea for a different layout, you could write a program to generate it. All the api functions are self documenting

17:20 ,(doc subvec)

17:20 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."

17:21 itistoday: rhickey: yeah, thanks, I know of that from way back when I used to care about Java :-p (now it looks like I'll be getting back into it because of Clojure)

17:21 Chouser: rhickey: I don't yet understand why new-new has to be done before c-in-c

17:21 itistoday: ctdean: thanks!

17:21 hiredman: erm

17:21 new-new? I thought it was implement or whatever

17:22 rhickey: hiredman: or whatever

17:22 hiredman: ,or-whatever

17:22 clojurebot: java.lang.Exception: Unable to resolve symbol: or-whatever in this context

17:24 hiredman: whatever is host in parens?

17:24 rhickey: Chouser: I'd like to have the final model in place, i.e. if we need classes with best perf we need Java right now, that doesn't make newnew a requirement, but I wanted to see what it would take

17:24 we could use interfaces + proxy and have minimal code to change - proxy->newnew

17:24 clojurebot: proxy is <Chouser> proxy teases with its ease of use, then suddenly betrays.

17:25 Chouser: rhickey: ahh.. so if it turns out newnew isn't going to cut it, the work to make c-in-c hasn't been wasted yet.

17:25 rhickey: ?

17:26 Chouser: aren't you saying that the reason to do newnew first is to prove it's a good model before rewriting it all in clojure?

17:27 rhickey: no, newnew is a good model, I'd like to use it when writing c-in-c

17:27 I need newnew more than c-in-c right now, I still have to write classes or deal with perf issues, new range a case in point

17:27 Chouser: oh. yes, but I'd like to have c-in-c before trying to write newnew

17:28 hiredman: how metacircular

17:28 Lau_of_DK: I feel lost, what is this newnew and c-in-c, where do I go read ?

17:28 rhickey: agreed, I'd like to write newnew in c-in-c, and I need it yesterday :)

17:28 itistoday: how similar are clojure's sequences to SICP streams?

17:28 Chouser: Lau_of_DK: http://www.assembla.com/wiki/show/clojure/New_new

17:28 Lau_of_DK: Thanks

17:29 Chouser: c-in-c is just translating as much of clojure as possible from .java to .clj

17:29 rhickey: itistoday: same idea, but they (Clojure's) are much more powerful

17:29 itistoday: rhickey: i see that clojure has the delay/force functions, but they're not mentioned on the sequences page, are they used internally by the sequences?

17:30 Chouser: Lau_of_DK: my weak ugly and incomplete attempt at c-in-c: http://github.com/Chouser/clojure-compiler

17:30 rhickey: Clojure's seqs are defined in terms of interfaces, really a family of sequences, and are unified and interoperable with concrete seqs

17:30 Lau_of_DK: btw, where's clojure-script at Chouser ?

17:30 rhickey: the mechanism underneath is more involved then delay/force, but similar idea

17:30 Chouser: Lau_of_DK: contrib

17:31 rhickey: basically Clojure is full of production implementations of ideas you'll find in SICP

17:31 Lau_of_DK: Chouser: I meant in terms of maturity

17:31 Chouser: Lau_of_DK: but I have no intention of doing more work on clojurescript until c-in-c is done.

17:32 itistoday: rhickey: cool. still wondering about why delay/force is part of the api then, are they used somewhere else? or are they just there for the developer to use if they need to?

17:32 rhickey: itistoday: they are just useful library functions

17:32 clojurebot: They found no relationship between a programmer’s amount of experience and code quality or productivity.

17:33 Chouser: the move from lazy-cons to lazy-seq left clojurescript behind, and the thought of what would be required to keep it synced up with chunks, newnew, etc. is just exhausting.

17:33 itistoday: rhickey: k, thanks

17:33 rhickey: Chouser: while a direct attempt at cinc is possible, I have a large list of things I want to do differently

17:33 Lau_of_DK: I know the feeling, we just climbed that hill with ClojureQL :)

17:34 rhickey: e.g. not use reflection and concrete class instances during compilation, requires abstracting out type info provision

17:34 but maybe there's a layered approach, I'll try to knock some of my notes into the wiki

17:35 * rhickey hates the fact that 'tab' doesn't indent lists in the assembla wiki editor

17:36 itistoday: as Java is full of mutable objects, is there a document anywhere that discusses the considerations one should take if using it from a multi-threaded clojure program?

17:37 or is at as simple as simply treating it as you would with java?

17:38 Lau_of_DK: rhickey: tried emacs' assembla-wiki-mode ?

17:39 rhickey: itistoday: coarsely, use Clojure data structures and facilities for your models, use java for I/O

17:40 itistoday: rhickey: if that I/O though might be one that's accessed by multiple clojure threads at a time.. what do you do? can you just wrap it in a ref and then use sync on it?

17:42 Chousuke: can't do IO in transactions

17:42 you could use agents

17:42 itistoday: Chousuke: ah, so have an agent that's responsible for the IO?

17:42 Chousuke: something like that.

17:42 rhickey: itistoday: IO from multiple threads it outside the scope of Clojure, there are separate protocols for each IO library (swing event thread, sockets stuff, db connection pooling etc)

17:43 itistoday: thanks, i'll stop bugging you guys with questions now and do some more reading :-)

19:08 JAS415: does the -> operator only work for functions that are associated with a name?

19:09 hiredman: nope

19:09 but it isn't as pretty

19:09 ,(-> "foo" (#(.toUpperCase %)))

19:09 clojurebot: "FOO"

19:09 hiredman: you just double up on the parens

19:09 clojurebot: ΜΟΛΩΝ ΛΑΒΕ

19:10 hiredman: clojurebot: what?

19:10 clojurebot: what is java

19:10 JAS415: oh you have to do an extra set of parens

19:46 ozzilee: Compojure seems to include the path my application is deployed at when matching routes. Does anyone know if that's intentional?

19:47 i.e. if I deploy my app at "mysite.com/myapp", all of my routes have to start with "myapp/". Am I doing something wrong?

19:47 grrrt: "myapp" is your servlet's context path I assume

19:48 if you don't want that, you could deploy the servlet under the ROOT context, but I'm not sure how to do that with compojure

19:50 ozzilee: grrrt: I can do that in tomcat, but I'd only be able to have one app per domain in the root context, correct?

19:51 grrrt: that sounds plausible yes

19:52 ctdean: Do you mean when using defserver? I'm not following.

19:53 ozzilee: ctdean: Using defroutes. (defroutes app (GET "*" (str (params :*)))).

19:53 (defservice app)

19:54 Compile that to a .war file, deploy it at context myapp, visit myapp/foo, and get "myapp/foo" in the response. To me, it should be just "foo".

19:55 ctdean: I see. I've never put my stuff in a .war, so I have no idea.

19:56 The plain vanilla (e.g. from a repl) doesn't prepend a path

19:58 ozzilee: ctdean: Yeah, it's only an issue when deploying in a servlet container.

19:59 ctdean: Try the compojure mailing list, they're responsive

20:02 ozzilee: ctdean: I will eventually.

20:09 Drakeson: is it possible to insert break-points in function definitions in slime?

20:09 (e.g. the way you can C-u M-C-x a defun in elisp)

20:10 grrrt: Drakeson: I just tried that with cljdb - http://georgejahad.com/clojure/cljdb.html

20:10 it did work

20:10 Drakeson: thanks

20:10 grrrt: no worries

20:17 JAS415: is it a common problem for clojure-dev to crash if repl output is too large?

20:17 i keep having to force-quit eclipse it seems

20:38 Drakeson: Do you happen to know of a way to control firefox through java (and ultimately through a clojure repl)?

20:40 hiredman: Drakeson: are you just looking to webbrowser programaticly?

20:40 htmlunit works pretty well

20:40 Drakeson: hiredman: not just that.

20:41 there is this javascript console (firebug) that is great. it would be even better if I could use a similar clojure repl to control and debug pages

20:53 durka42: there is mozrepl but i think that's javascript

20:54 but you don't use clojure to script pages (unless you're using clojurescript), so how would it be as useful as firebug?

20:55 Drakeson: durka42: if there was (or hopefully is) a way to interface to firefox through java, I could potentially have a clojure repl to do that instead.

21:00 rhickey: ,(partition 3 1 nil (range 10))

21:00 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: core$partition

21:00 rhickey: hrm, new partition does:

21:00 user=> (partition 3 1 nil (range 10))

21:00 ((0 1 2) (1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7) (6 7 8) (7 8 9) (8 9))

21:03 seems to me partition with step 1 should never use the pad

21:03 user=> (partition 3 1 [42] (range 10))

21:03 ((0 1 2) (1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7) (6 7 8) (7 8 9) (8 9 42))

21:09 Chouser: it should include (9 42 42) as well?

21:10 shouldn't

21:10 rhickey: no, once it has produced a partition containing the last element of the coll it should be done

21:11 Chouser: hm... yes

21:11 (partition 3 2 nil (range 5)) should end with (2 3 4)

21:12 rhickey: I've kicked https://www.assembla.com/spaces/clojure/tickets/120 back to Dimitry

21:22 Drakeson: ~

21:22 clojurebot: what is java

21:22 Drakeson: ~paste

21:22 clojurebot: lisppaste8, url

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

21:22 Drakeson pasted "original partition" at http://paste.lisp.org/display/82474

21:23 Drakeson annotated #82474 "modified" at http://paste.lisp.org/display/82474#1

21:26 Drakeson annotated #82474 "better" at http://paste.lisp.org/display/82474#2

21:28 Chouser: if you use 'seq' as the opposite of 'empty?', then you can use if-let instead of repeating the drop expr

21:29 Drakeson: sorry, I didn't get it

21:30 which drop expression is repeated?

21:30 Chouser: (if-let [cont (seq (drop n s))] (cons p (partition n step pad cont)) (list (take n (concat p pad)))))

21:31 oh

21:31 nm.

21:31 :-) ignore me.

21:31 Drakeson: :p

21:32 seths: I wish the api, special_forms, and kin pages on clojure.org were wiki pages

21:33 Drakeson: kin pages?

21:33 seths: it's frustrating when things like nthrest are mentioned in multiple places but don't exist

21:33 Drakeson: how is the web site managed? is it under git, by any chance?

21:34 Chouser: it's a wikispaces site

21:35 seths: must be private, wikispaces.com says this: Your search - Clojure - did not match any documents.

21:37 Chouser: seths: you're welcome to write up a list of errors and post it to the google group.

21:37 seths: good point

21:37 Chouser: it would be great if it were in git

21:38 moc`: Hi, sorry to interrupt. I am just starting out with Clojure and can't figure out why this code doesn't work: (map #(apply % '(1 2)) '(+ -)) => (2 2). I was expected (3 -1). Any ideas anyone?

21:41 Chouser: moc`: by quoting the list '(+ -) you're preventing the evaluation of each of those symbols

21:42 you wanted a list of 2 functions, but instead you have a list of 2 symbols.

21:42 if you use [+ -] instead, each of those symbols will be evaluated, and you'll have a vector of functions.

21:42 moc`: Chouser: OK, I get it.

21:43 Chouser: ,('+ 1 2)

21:43 clojurebot: 2

21:43 moc`: Chouser: Thanks. It was doing my head in.

21:43 Chouser: you're welcome. It's why we're here. :-)

21:47 seths: ok, Rich renamed nthrest to nthnext on Feb 17th 2009

21:48 commit b8e333fb3437dca760f16136ed074a4dd463fe35

21:48 dreish: Extra confusing because a symbol acts as a function in the same way that a keyword does, taking a map as its first arg, and an optional not-found value as its second.

21:48 (That should have been to moc`)

21:49 But it doesn't throw an exception if the first arg isn't a map. It just returns the not-found value (or nil).

22:17 Chouser: anyone here used enlive on xml docs?

23:01 JAS415: gotta say

23:01 i love memoization as a primitive

23:04 Chouser: anyone used enlive at all?

23:04 grrrt: yes I have

23:04 just for tagsoup though

23:04 Chouser: well, that may still help me.

23:04 grrrt: I love the idea of enlive

23:05 Chouser: I just need a working example -- input html and 'select' call

23:05 for what I'm doing me zip-filter would be sufficient, but I suspect enlive is better in every way. ...I just can't figure it out.

23:05 clojurebot: for is not used enough

23:05 Chouser: I've got my xml parsed into a format I think enlive wants.

23:06 but (enlive/select xml [:description]) returns an empty seq

23:06 grrrt: I'll rummage through my clojure snippets for a bit, I must have something there

23:06 Chouser: in fact, anything I put in place of [:description] returns an empty list.

23:07 eh, I but that means xml is in the wrong format.

23:07 bet

23:08 grrrt: what format is it?

23:08 I could just load a plain text file as a resource: (html-resource "templates/my-template.html")

23:09 Chouser: yeah, but I'm trying to avoid needing tagsoup, since I just need xml.

23:09 if I were less stubborn this wouldn't be a problem

23:09 grrrt: ah sure, I see

23:09 Chouser: xml is fron (xml/parse foo)

23:09 grrrt: hm I think I have only ever used enlive's deftemplate macro

23:10 Chouser: (enlive/select (xml/parse input-stream) [:description])

23:12 woo! got it

23:13 (enlive/select [(xml/parse input-stream)] [:description])

23:13 grrrt: ah

23:28 holmak: Has anyone done much work with using Swing or another Java UI toolkit from Clojure?

23:28 More importantly, has anyone found a way to make it a tolerable experience?

23:28 grrrt: I'm working on something that makes using SWT easier

23:28 holmak: May I ask what approach you are taking?

23:29 grrrt: well (it's a work in progress still)

23:29 I have created an easy way to specify SWT widgets in a tree

23:29 holmak: aha

23:30 (I had given some thought to this problem as well.)

23:30 grrrt: you can basically say things like (shell {:outlet :my-shell} (menu-bar (menu "File" (menu-item "New" {:shortcut \N})))) etc

23:30 holmak: I never realized how incredibly procedural Swing is until I used it from Clojure

23:30 grrrt: I know - I'm fighting SWT because everything has to happen in the UI thread

23:31 holmak: Well, I think that problem is tolerable if you just make a queue that you deposit UI calls into

23:31 grrrt: I have a separate namespace with functions that actually create the widgets

23:31 holmak: in Swing, there's SwingUtilities/invokeLater, of course

23:31 grrrt: they do (in-ui (Shell. (display)))

23:31 holmak: handy

23:32 So, here is the tricky problem I have -- how do you handle events, and how do you handle changing state of widgets?

23:32 grrrt: SWT uses events like selection, keydown etc

23:32 holmak: I'm not familiar with SWT

23:33 hiredman: http://gist.github.com/107140 <-- EDT macro is very useful

23:33 grrrt: I can respond to a menu selection by doing (menu "New" {:on-Selection (fn [evt] (println "Menu selected!"))})

23:33 holmak: Seems solid -- so how would you mutate widgets, like, to append to a text field?

23:33 hiredman: generally I have (future do stuff) in an event listener

23:33 (to push stuff of EDT)

23:33 off

23:34 grrrt: well, the structure of widgets I mentioned earlier

23:34 all widgets support an :outlet option, such as {:outlet :my-label} for some text label

23:35 the whole widget structure returns a map with all widgets that have an outlet defined

23:35 if a button-push calls the "change-text" function, I can just do (.setText (:my-label *outlets*) "New Text")

23:36 holmak: nice

23:36 grrrt: because all UI stuff happens in the UI thread, this works, otherwise I could use agents (to go to other threads) or use in-ui

23:36 When it's slightly more polished I'm planning to put my efforts online somewhere

23:37 (I stole the term outlets from Mac OS X Cocoa)

23:37 holmak: It certainly seems like the Clojure community would benefit from a nice declarative GUI library/wrapper

23:37 grrrt: yes, it's tricky to combine functional programming with a gui

23:37 holmak: Your approach is similar to the thoughts I had

23:37 I started out thinking about Django templates

23:37 or really, and web framework template, take your pick

23:38 where you have little slots that you can plug your content in

23:38 grrrt: yes indeed

23:38 holmak: Because what I want to avoid above all else is keeping a big pile of widget objects around each with a dozen methods for mutating it

23:38 Sorry, that was a bit of a run-on

23:38 grrrt: :) no worries

23:39 holmak: The trick is that you don't want to recreate the GUI every update

23:39 unlike on teh web

23:39 grrrt: yeah, you need some kind of context to store your UI objects in

23:39 holmak: Right now I am doing horrific things with Swing in the name of getting another project done

23:40 grrrt: heh. I started out wanting to get a window going to do some graphics, then the "design the perfect world" syndrome kicked in

23:40 holmak: Ideally, you would have a pure Clojure data structure, like a map, that you could throw at your GUI "handle", and say, "update, GUI!"

23:40 and everything would drop into its slot

23:41 grrrt: hm, that sounds interesting

23:41 I don't see why you couldn't do that

23:41 holmak: Eh, there has to be some kind of compromise between performance and declarativeness

23:41 hiredman: oh god

23:41 foreclojure

23:41 :|

23:41 holmak: It's definitely an interesting problem

23:42 hiredman: where?

23:42 hiredman: the google group

23:42 grrrt: wow. just read the latest msg

23:43 holmak: hahaha

23:43 That's both witty and terrible

23:43 It's much harder to come up with good Clojure project names than, say, Python project names

23:43 grrrt: holmak: are you considering a situation where the UI is mostly updated in response to user actions?

23:44 hiredman: ~Xiphojura

23:44 clojurebot: 2009:Jan:29:16:03:17 <hiredman> I call Xiphojura

23:44 grrrt: or from a background process

23:44 holmak: "I'm making a spreadsheet, I'll call it, uhh, pySpreadsheet!"

23:45 grrrt: I don't really know where I was going with that thought. I didn't have a chance to think about it much.

23:46 But this entire thought process was triggered by trying to work with the Swing Tree widget.

23:46 Which is, in fact, a suite of about a dozen classes and a real nightmare.

23:46 hiredman: you could have an agent with a watcher

23:47 grrrt: hiredman: how does that work?

23:47 holmak: Oh, very interesting -- use the watcher to trigger changes, instead of validating changes?

23:47 hiredman: you alter the map in the agent, and the watcher updates the gui state based on the new values in the map

23:49 would make for an interesting toolkit design

23:49 grrrt: hm. that sounds good

23:49 holmak: I should write these things down.

23:50 grrrt: neh just implement it

23:50 holmak: About the watchers, though: asynchronous madness!

23:50 If only we had a language well suited to dealing with massive concurrency...

23:51 hiredman: well, updates will be serialized anyway

23:52 because the watcher will dump them on the edt

23:52 holmak: Oh I know. It's just that I would never devise a system using three parallel threads of execution in any other language.

23:52 But here, it practically makes sense!

23:53 hiredman: well, having gui stuff going on in multiple threads is a "dead dream" so you would need at least two threads anyway

23:53 grrrt: hiredman: does Swing's invokeLater work with "nested" calls?

23:54 i.e. could you do (EDT (EDT (....)) ?

23:54 holmak: I feel like that would just invokeLater some invokeLaters

23:55 grrrt: my SWT equivalent would block if I tried that.

23:55 hiredman: grrrt: invokelater just ques up Runnables on swing's Executor

23:55 grrrt: ah right

23:55 holmak: hooray queues

23:55 hiredman: if EDT used invokeandwait or whatever it's called, then you would have a problem

23:55 grrrt: yeah

23:56 holmak: So, how do you feel about SWT? Either of you? I'm using Swing because it was closer, but I'm open to conversion.

23:56 grrrt: I don't know much about swing, can't really compare

23:57 SWT seems reasonably straightforward, but I'd hate to do it in java

23:57 5 lines of code for a simple menu item...

23:57 hiredman: swt is full of native code :(

23:57 grrrt: true

23:59 but you can download or build it for many platforms

23:59 hiredman: would rather just depend on the jre

Logging service provided by n01se.net