#clojure log - Nov 16 2008

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

2:25 Lau_of_DK: Morning gents

2:29 Chouser: Hey, Lau, having some emacs/irc issues there?

2:29 :-)

2:34 Lau_of_DK: Hey Chouser

2:34 Im not sure what happend, suddenly the screen turned dark, smoke came out of the back of my laptop - I heard the hard-drives reader-head break off and destroy all my data. And sinking back into the couch I remember thinking "this still beats Vim"

2:35 Chouser: ha ha

2:37 Lau_of_DK: Chouser: but this actually rocks. Im sitting code, sending code directly to my Repl having it evaluated. And if I need your advice on something, I hit F1 type "Cho<tab>" and we're chatting

2:37 Any text you write, I can send to the Repl :)

2:37 Chouser: yes, that sounds nice.

2:38 Lau_of_DK: Isnt it around midnight where youare at ?

2:38 Chouser: 2:30 AM. I should definitely not be awake.

2:38 Lau_of_DK: Thats gonna hurt in the 'morning' :)

2:39 Chouser: indeed

2:39 Lau_of_DK: Did you produce some outstanding code tonight though ?

2:39 Chouser: I'm in the thick of it. Got ClojureScript spun up to work post-AOT, and now I'm writing a little C program.

2:40 Lau_of_DK: How does C fit into this ?

2:40 Chouser: I want something with very fast startup time to use as a little cgi bridge for a ClojureScript REPL in a browser.

2:41 Lau_of_DK: oh, so you start that on the webserver and then connect to it?

2:42 Chouser: yeah, pretty much.

2:42 Lau_of_DK: Sounds like an awesome idea

2:42 How far along are you ?

2:43 Chouser: the repl works pretty well locally, but I need this lame C program to get it all hosting nicely at n01se.net

2:43 Lau_of_DK: Considered ... I dare not say it... Perl for the job?

2:44 Chouser: yeah, but I want very fast lightweight startup.

2:44 and the requirements are pretty thin, so I thought I'd try C

2:45 I'm sure I'll regret it eventually.

2:45 Lau_of_DK: Fair enough

2:45 hehe

2:48 Lets say I want to store 500Mb of data in RAM - How do I go about this in Java?

2:57 Chouser: (make-array Byte/TYPE (* 500 1024 1024))

2:58 hiredman: is there an encoding for clojure source?

2:58 Chouser: hiredman: I think it defaults to UTF-8

2:59 hiredman: are there rules for vars?

3:00 the last release of clojure seems to think ? (the interrobang) is =

3:00 user=> (def I? I)

3:00 #'user/I=

3:26 Lau_of_DK: Never heard of any interrobang :)

3:31 hiredman: You've never heard of the interrobang?

3:31 Lau_of_DK: no

3:32 hiredman: well, now you have

3:32 Lau_of_DK: Yea, thanks

3:33 But all the Americans are sleeping now (presumeably) so you might gain more from posting your question to the ggroup

3:33 hiredman: I guess

3:33 user=> (def ? :heart)

3:33 #'user/e

3:48 Lau_of_DK: Do you see any special use for this?

4:05 kotarak: Hmm.. recur in a catch clause doesn't work?

4:10 Lau_of_DK: Whats your experience MR. Kota ?

4:11 kotarak: (try ... (catch Exception e (loop [x e] .... (recur (do-something-to x)))) complains

4:13 Lau_of_DK: If possible, maybe you should just wrap the execution of that whole func in a try/catch ?

4:13 kotarak: (try :x (catch Exception e (loop [x e] (if (.getCause x) (recur (.getCause x)) x))))

4:13 java.lang.UnsupportedOperationException: Cannot recur from catch/finally (NO_SOURCE_FILE:1)

4:14 I think, this is a valid use of loop.

4:14 Lau_of_DK: k, so do what I said

4:14 Its quite clear "Cannot recur from catch"

4:14 I have to jet, bubye

6:02 AWizzArd: Clojure lists know their length, yes? (count list) ==> O(1)

6:04 Pupeno: Hello.

6:04 AWizzArd: Hi Pup

6:05 Pupeno: AWizzArd: I haven't been called Pup in quite a while :)

6:06 AWizzArd: I would expect count to be O(n) on lists, but O(1) on vectors, but there might be some optimization.

6:12 polli: AWizzArd: for PersistentLists it's O(1)

6:14 judging from scimming through its implementation

6:24 kotarak: AWizzArd: according to clojure.org count is O(1) for lists, vectors and maps

6:33 AWizzArd: kotarak: thx

8:09 pjb3: So with the latest clojure, if I have some directory on my classpath, and in that directory I have a foo directory that has a bar.clj file in it, that file should declare (ns foo.bar) at the top, correct?

8:09 rhickey: pjb3: yup

8:10 pjb3: and then I should be able to do (require 'foo.bar), right?

8:11 rhickey: yes

8:13 pjb3: ah, I got it now, had a typo in my classpath, thanks

8:20 rhickey: poll - if you enter (cast 4 String) at the repl, do you get a CastClassExceptionMessage naming both types or only Integer, and if both, what message do you get and what VM are you running?

8:20 I get: java.lang.ClassCastException: java.lang.Integer

8:21 pjb3: java.lang.ClassCastException: java.lang.Integer (NO_SOURCE_FILE:0)

8:21 kotarak: java.lang.ClassCastException: java.lang.Integer

8:21 rhickey: would prefer: java.lang.ClassCastException: had java.lang.Integer wanted java.lang.Class orsomething

8:21 pjb3: The 1.5 JDK that comes with Mac OS X Leopard

8:21 kotarak: mac 10.5.5 stock java 1.5

8:21 rhickey: I'm only interested if it's different from mine

8:22 I know I've seen messages with both types in stack traces from users, but didn't ask then

8:23 mehrheit: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Class (NO_SOURCE_FILE:0)

8:23 on Sun JDK 1.6

8:23 rhickey: mehrheit: what OS?

8:24 mmcgrana: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Class (NO_SOURCE_FILE:0)

8:24 mehrheit: ubuntu 8.10

8:24 rhickey: mmcgrana: what JVM/OS?

8:24 mmcgrana: 1.5 OS X leopard

8:25 rhickey: ok, so maybe fixed in JDK 6, same here on JDK 6

8:26 mmcgrana: o wait sorry rhickey i'm actually 1.6

8:27 i had switched back and forth yesterday trying to get the core precombile thing to work. sorry about the confusion

8:27 *precompile

8:30 pjb3: I jut noticed the REPL prints the expression that you entered as well as the value the expression evaluates too

8:30 Has it always done that or is that a recent thing?

8:31 kotarak: I had this with a broken rlwrap.

8:31 rhickey: pjb3: it doesn't do that

8:32 pjb3: Ah, that is an aquamacs thing I guess

8:32 rhickey: your right, doesn't do that when I run the REPL from the command line

8:32 does it when it is the inferior-lisp in aquamacs

8:45 rhickey: pjb3: not for me, but I haven't updated my clojure-mode in ages

8:46 pjb3: rhickey: weird, maybe that's just another setting somewhere in aquamacs

8:47 rhickey: pjb3: you type 42 enter and get 42 newline 42?

8:47 user=> 42

8:47 42

8:48 pjb3: rhickey: yeah, I get it twice

8:48 user=> 42

8:48 42

8:48 42

8:48 rhickey: yikes

8:48 pjb3: user => (+ 1 2)

8:48 (+ 1 2)

8:48 3

8:48 yeah, it's annoying, what did I do! :)

8:48 kotarak: pjb3: I had this with an old version of rlwrap. Maybe this effect is similar. How do you start clojure?

8:50 pjb3: kotarak: http://github.com/pjb3/clojure-bin/tree/master/clojure

8:50 I set that script as the inferior-lisp-program

8:51 then press C-C C-Z when I'm in a .clj file

8:51 kotarak: Do you have jline somewhere in your cp? Maybe this interferes?

8:51 pjb3: it does it in aquamacs only, not if I start that command line

8:51 Yeah, I do have JLine, let me try to take that out

8:53 kotarak: Yeah, jline seems to be the problem

8:53 kib2: \join #lyx

9:15 pjb3: What's up with this?

9:15 user=> (contains? [\b \y] \b)

9:15 false

9:15 user=> (contains? #{\b \y} \b)

9:15 true

9:16 oh right, contains is has-key?, that confuses me every time :/

9:17 Is there a function for "does this sequence has this value in it?"

9:18 mmcgrana: includes? in seq-utils in contrib

9:18 rhickey: user=> (some #{\b} [\b \y])

9:18 \b

9:19 Chousuke: nifty use of sets, that :P

9:19 mmcgrana: btw rich what was the inspiration for the name some - does that come from another lisp?

9:19 rhickey: plus you can put in more than one search item

9:20 mmcgrana: CL has some

10:02 duck1123: if I want a param with a default optional param, I need to use multimethods? or something else?

10:03 kotarak: duck1123: (defn foo ([x] (foo x 5)) ([x y] (+ x y)))

10:03 duck1123: ok, thanks

10:10 Chouser: or: (defn foo [a & [b]] (+ a (or b 5)))

10:24 mibu: I have two questions regarding future development of clojure: 1. I saw there are plans to deprecate the . function - has it become too late to drop it anytime soon and nip it in the bud? 2. What is the plan with the contribs? Is it going to be a repository like system, or are there inclusive intents to get anything good into clojure core like in python and java?

10:25 Chousuke: mibu: some stuff from contrib might end up in core. nothing has been decided yet, though.

10:25 I don't know about .

10:25 Personally I'd like to see it disappear, though.

10:26 Chouser: The namespace loading stuff (use, require, alias, etc.) started off in contrib

10:27 kotarak: there is vote going on for extensions from contrib to be included in core

10:27 rhickey: The value of . is that all of the other sugar just turns into that at macroexpand time, so code analyzers need only deal with . and not static/member, .member, ctor. etc

10:27 mibu: chousuke: I also don't like it. But its presence is just calling for people to use. Has clojure reached the point where it can't be just be removed because of concerns of breaking code?

10:28 kotarak: then almost all my code will break

10:28 Chousuke: maybe people should just be encouraged not to use . outside of macros :p

10:28 duck1123: Once nobody ever sees use of . they'll never think to use it like that

10:28 mibu: rhickey: so will . remain for macros?

10:28 rhickey: Chousuke: yes, I just need to change the docs to emphasize the other forms

10:28 Chouser: oh, I was under the impression . was going away for statics

10:29 rhickey: Chouser: undecided on that, in fact there is a new need for it to disambiguate calls to static members of classes corresponding to namespaces

10:30 admittedly rare, but my.ns/foo will not resolve to the class my.ns

10:32 Chouser: yeah, I've noticed related issues for ClojureScript. I can't use the Class/member syntax for JS classes because the compiler assumes they're namespaces.

10:32 mibu: rhickey: I'm confused. what are the long-term plans for . ?

10:32 Chousuke: maybe I should remove uses of . from the clojure wikibook... to manipulate new users into not using it.

10:33 rhickey: mibu: there are no plans to change .

10:33 mibu: oh ok.

10:35 Chouser: any plans to make StructMap$Def implement IFn? :-)

10:36 rhickey: Chouser: I dont know if you saw my comment to cemerick on structmaps in the light of AOT (will try to find it)

10:38 mibu: rhickey: about the contribs issue, what's your take on the core library in general - an inclusive battery-included kind of core with plenty of common use facilities or a more compact core which is supplemented with 'require'd extensions?

10:41 rhickey: mibu: the latter. OTOH, you shouldn't have to require anything for basics, so some of what is in contrib (i.e. case) can move in. Maybe contribs could have those things that are proven separated somehow from those that are gestating, the former being included with the distribution.

10:41 Chouser: rhickey: I saw it, but I suppose I didn't understand the implications.

10:42 rhickey: the implications are you have to wait for me to figure that out before I do any more enhancements to structmaps :)

10:44 mibu: rhickey: is there some kind of plan for a standard repository and install mechanism? you know, to avoid a fiasco like we have with CL library installation...

10:45 rhickey: mibu: AOT and the solidification of the directory structure serve as a basis for library management mechanisms, including some of those successful in Java-land.

10:48 mibu: rhickey: yeah, but will there be a standard to avoid making it a chore to figure out how to quickly install depended extensions? Something as simple as (install 'sql)

10:48 Chousuke: mibu: I don't think that's going to be a problem

10:48 rhickey: mibu: the community will figure that out

10:48 Chousuke: mibu: you can just download a jar, add it to classpath, and use it

10:49 duck1123: We have all the options open to java available to us

10:49 rhickey: there are a lot of models, and Clojure has the benefit of a community with knowledge of those of CL/Scheme/Ruby/Python/Java etc

10:49 duck1123: has anyone tried Ties yet?

10:50 Chouser: if structmap basis become named classes and structmaps instances of those, people will immediately begin dispatching multimethods on basis type.

11:07 rhickey: Chouser: I'm not sure that is bad vs everyone reinventing their own metadata-based mechanism for his common case - the main problem with real classes here is their lack of dynamism - can't add a field without a restart

11:07 this common

11:08 I don't have a solution for this yet, but would like structmaps to be 'serializable' at some point

11:09 mibu: there is a mention in boot.clj that import is not the preferred way to import, yet in every example I see there is import. what am I missing?

11:11 rhickey: mibu: a) those examples may have predated ns having :import capability, or b) for a one-off script you might not have a ns

11:11 kotarak: (ns (:import ...)) is preferred over (import '(...)), as I understand it.

11:11 rhickey: if you have a ns, don't use import

11:12 kotarak: rhickey: but I found it necessary sometimes: (when *compile-files* (gen-class-stuff-here)) (import '...) because ns assumes that everything is already there.

11:13 rhickey: kotarak: gen-class should become much better when integrated into AOT

11:13 * rhickey gets back to it

11:13 kotarak: rhickey: hopefully. :)

11:13 mibu: rhickey: the distinction of uses (import,:import) is not clear in the docs.

11:14 kotarak: Although: *compile-files* eliminated a separate compilation step for gen-class.

11:15 mibu: rhickey: if you add "if you have a ns, don't use import" to the docs. it'll solve a lot of headaches later :-)

11:17 kotarak: Is it possible to get the remaining string out of a string reader? (def x (new java.io.StringReader "hello")) (.read x) (.read x) (??? x) => "llo" ?

11:20 danlei: em

11:20 miss

11:36 Drakeson: Is there a simple way to import and rename java camelCase classes and methods into dash-seperated names?

11:49 like, can I ship an fn to :rename? (e.g., as in (refer ... :rename (fn [x] ..)))

11:50 the API only says "map"

11:51 rhickey: Drakeson: rename fn is interesting, a concrete map is expected right now

11:52 but the rename of Java API is likely to be a bad idea because: other people can't read your code, IDEs can't help you etc

11:58 Drakeson: it is not an arbitrary/hackish renaming. It is to make all the names in clojure and libraries consistent. Currently the names seem ... a bit funny.

12:01 also it slightly improves readability. something-or-the-other can be read easier than SomethingOrTheOther, IMHO.

12:04 danlei: how do i get a string of a seq of chars?

12:04 rhickey: Drakeson: I prefer dash-separated-names too, but we didn't name these things, someone else did, and I'm now in the camp that says it's best to leave them as named by their owners - all conversion strategies have problems, difficult-to-guess transformations, need to be supported by all tools etc

12:04 danlei: (??? (seq "hello")) -> "hello"

12:04 kotarak: danlei: (apply str (seq "Hello"))

12:05 danlei: kotarak: ah, thanks

12:40 pjb3: testing...1...2...3...

12:42 rhickey: pjb3: testing what?

12:42 pjb3: rhickey: just some IRC thing, plz ignore, sorry

12:43 rhickey: np

12:43 pjb3: specifically http://mibbit.com

12:43 web-based IRC thing

12:43 that's what all those mib_* join/left messages were about

12:47 kotarak: Chouser: thanks for the discussion yesterday. I have now a working vim repl with multiple expression send. Ugly, but working. :)

12:50 Chouser: kotarak: sounds just like vim itself. :-)

12:50 kotarak: yeah, in some way :)

13:24 Lau_of_DK: Good evening gents =)

13:31 Design question for those of you who like agents. I have a swing program, which runs several agents (in the 100s). All these pile up some type of data. I have another agent, which in a transaction reads the queue, outputs the data to a visual log, and clears out the global ref which they all log into.

13:31 Is this the correct way to handle that type of thing?

13:34 AWizzArd: Is that all to have a user not waiting? Or do you just want to write logs?

13:52 Lau_of_DK: Noone here likes agents?

13:53 SnowBuddy: When you see an agent, you run.

13:54 Lau_of_DK: Not me - I bend backwards really fast, making a clear statement

13:55 But doesnt anyone here have a take on my design question?

13:56 arbscht: Lau_of_DK: is the read-clear routine atomic?

13:57 Lau_of_DK: I was thinking about that earlier, because for accuracy it needs to be ofc. How could I accomplish that?

13:57 arbscht: is it in a single transaction?

13:59 Lau_of_DK: Yes

13:59 I mean, theres really no need to do the reading in a transaction, but it can be done ofc

14:18 In practical terms, how do I choose between alter/commute, they seem very similar

14:18 Or, rephrase: When do I prefer one above the other?

14:22 mortis`: humbly requesting help...going through the PP book, trying to get lancet to load

14:22 I have added what I think is the correct path to the classpath: (add-classpath "file:///home/mortis/personal/projects/clojure/lancet")

14:23 though, when I: (require 'lancet)

14:23 Lau_of_DK: PP??

14:23 gnuvince_: PragProg

14:23 mortis`: I get: Could not locate Clojure resource on classpath: lancet/lancet.clj (NO_SOURCE_FILE:0)

14:23 PP => pragmatic programmers book

14:23 the PDF

14:24 ...and this returns true: (. (new java.io.File (str "/home/mortis/personal/projects/clojure/lancet/" "lancet/lancet.clj")) exists)

14:24 which is what I think it'd be doing when I attempt to use lancet

14:24 Lau_of_DK: Never heard about the book Im afraid, but if its free and you have a link I can have a look

14:24 mortis`: er, it's not

14:24 Lau_of_DK: k

14:25 mortis`: the books is irrelevant to the issue I"m having, it was just a bit of context

14:25 Chousuke: mortis`: I think the classpath needs the final /

14:25 mortis`: I'll try that

14:25 ok, that worked, thanks

14:25 all classpath-urls have to end w/a filesep?

14:25 well, I suppose that's teh case

14:25 Chousuke: and please use .method syntax instead of . ;( . is difficult to read

14:26 mortis`: any chance we could have add-classpath do that for file:// urls?

14:26 Chousuke: mortis`: java thinks they are jars if they don't

14:26 mortis`: ah ok

14:26 is there a difference between the jscheme style (.method instance args) vs the (. instance (method args))?

14:27 Chousuke: no. except that the latter is not as nice.

14:27 rhickey: mortis`: the former is preferred

14:27 Chousuke: .foo also works for fields, not just methods.

14:27 mortis`: oh, great

14:28 Lau_of_DK: rhickey: Can you answer my design-question above, is it the correct use of agents, and can it be done atomic, the print/clear log ?

14:29 rhickey: if you want a queue, use j.u.concurrent queues

14:29 Lau_of_DK: I think I cant avoid having a queue when its a log we're talking about, but I'd much prefer to use the wrappers if thats at all possible ?

14:30 rhickey: Clojure doesn't wrap, j.u.concurrent, but works with it

14:30 AWizzArd: Would that be also the right thing for something that is just a side effect and needs no data itself? Say, my app wants to write every minute some data into a file, then an agent would feel a bit artificial, as I would have no data that needs a change.

14:31 rhickey: AWizzArd: agents make fine thread wrappers, or you can use Thread

14:31 AWizzArd: agents also encapsulate thread pools

14:31 Lau_of_DK: rhickey: works with it? Just to avoid misunderstandings: I consider the whole agent setup as wrapers of Javas threads, correct? So when you say that Clojure works with java queue class, do you mean something beside the usual java interop?

14:32 rhickey: I mean java.util.concurent queues - these are data structures, not threads - agents can communicate through queues

14:33 i.e. don't use STM to implement anything proved by j.u.concurrent

14:35 Lau_of_DK: k, thanks rich

14:36 Now about agents, without thinking too much about it, all repetive agent-funcs end with the line (send-off *agent* self) right? My agent for some reason becomes an error after the first cycle, where do I look for a more precise error message?

14:37 rhickey: Lau_of_DK: I will eventually provide a wrapper API for j.u.concurrent since so few people know about it

14:37 duck1123: just saw that #! is now a comment. Very cool

14:37 quuuux_: hi, while making my first steps with clojure i stumbled upon the following maybe-problem... calling "with-in-str" in r1106 fails with "java.lang.IllegalArgumentException: with-open now requires a vector for its binding". Wrapping name and init in the call to "with-open" (core.clj, line 2397) in a vector seems to fix the problem for me.

14:38 Lau_of_DK: rhickey: thats very kind of you =)

14:39 Chousuke: quuuux_: it seems with-in-str has a bug :)

14:40 rhickey: quuuux_: got it, thanks

14:41 quuuux_: np

14:41 Chousuke: hmm

14:43 would it make sense to extend with-open to support multiple bindings? like (with-open [a (File.) b (File.)] ... ? currently with-open will not complain about that, but only the first file will actually be closed :/

14:43 Lau_of_DK: You wouldn't need it that often would you? But on the other hand, it couldnt really hurt?

14:44 Chousuke: it might hurt if people assume with-open supports multiple bindings but doesn't actually close anything but the first...

14:44 Lau_of_DK: rhickey: Now I understand that using j.u.concurrent is the correct approach, but just out of pure interest in agents/STM - Can I make 2 transaction be virtually atomic? (like f.i clearing a log and outputting the data)

14:46 rhickey: Lau_of_DK: nest transactions join the enclosing transaction

14:46 nested

14:48 Lau_of_DK: rhickey: Normally I have absolute no problem understanding Americans, but for some reason you sometimes come across almost cryptic. Can you further explain "join the enclosing transaction" ? Does it mean that the STM locks down the I/O while comitting everything in the dosync?

14:49 rhickey: (dosync ... (dosync ...) (dosync ...)) is one atomic transaction

14:50 Chousuke: If I want to map a function that has side-effects, the correct way to do that is (dorun (map ...), right?

14:51 rhickey: i.e. if you have two functions that themselves are transactions and call them within another dosync, they become part of that outer transaction and all occur together

14:51 AWizzArd: Chousuke: dorun or doseq?

14:51 rhickey: Chousuke: yes, if you don't need the resulting seq

14:51 Lau_of_DK: oooh :) Thats fantastic, thanks rhickey

14:51 Chousuke: AWizzArd: I don't think I want to use doseq for this

14:51 AWizzArd: can one make circular structures in Clojure?

14:53 Chousuke: going to experiment with changing the finally block in with-open to do (dorun (map #(.close (first %)) ~(partition 2 bindings))) instead of just (.close ~(first bindings))

14:53 astor: I've seen that I need async lazy sequences - kind of producer/consumer, but where the consumer is in the form of a lazy sequence. To me, a channel abstraction of some sort would be natural for this, and the produer/consumer example I've seen is kind of cumbersome. Is a channel something that should be built on top of agents, or where does this fit into the clojure world?

14:57 rhickey: astor: you could look at seque

14:57 (doc seque)

14:58 Lau_of_DK: I think (ref-set alter and commute) are a bit confusing. If I have a ref to a vector [1 2] and I want to conj 3 onto that vector, whats the recommended approach?

14:58 rhickey: Lau_of_DK: (alter aref conj 3)

14:59 Lau_of_DK: Thanks

15:03 gnuvince_: What's the difference between setting the value of ref and setting the in-transaction-value of ref?

15:06 THe number of people in here just keeps growing, doesn't it?

15:07 Lau_of_DK: gnuvince_: I presume in the first example you speak of the value which is commited once the transaction closes, and the other is visible within the transaction ?

15:12 astor: rhickey: thanks

15:16 Lau_of_DK: I just want to share this with you Emacsers. Most of you have got slime working so that you can eval code directly from your buffer. But did you know that with ERC you can also have #Clojure scrolling right in a buffer, so that you can copy/eval code directly from the channel without ever leaving emacs? I think this is great, so I just wanted to share :)

15:17 AWizzArd: it's nice, but for lot's of code it is even nicer to post it online somewhere, instead of spamming the channel :-)

15:19 Lau_of_DK: Its a matter of taste, for debugging I prefer lisp.paste, for sharing cool snippits, I prefer in chan, but thats just me

15:25 Chousuke: hmm

15:26 my multiple-binding with-open appears to work. yay

15:26 Lau_of_DK: yay :)

15:26 danlei: Lau_of_DK: also beware that you could end up like me: sending random snippets and stuff to unrelated channels, because you keep hitting the wrong buffer from time to time ;)

15:26 Chousuke: it's a ~one-line change though :p

15:26 Lau_of_DK: danlei: oh my - you do that too ? :)

15:26 * danlei nods.

15:27 Lau_of_DK: Chousuke: Thats Lisp for you :)

15:29 Chousuke: can't send a patch though as I have no CA.

15:32 blarfo: wha is ~ ? gensym? or @ in common lisp

15:32 Chousuke: ~ is unquote

15:32 Lau_of_DK: blarfo: I think gensym is var#

15:35 Chousuke: wonder if I could just release my patch as public domain to circumvent the need for a CA :P

15:36 fanda: Hello! Just a question about 'symbol' fn

15:36 user=> (symbol "abc")

15:36 abc

15:36 user=> (symbol nil)

15:36 java.lang.NullPointerException (NO_SOURCE_FILE:0)

15:36 What would you expect to return (symbol nil)? Is this an expected behavior?

15:36 Thanks!

15:38 rhickey: fanda: symbol takes a name string, nil is not a name

15:38 so, yes, NPE

15:39 fanda: rhickey: hm... so exception is pretty much ok

15:39 just thinking about different tests for functions

15:42 leafw: if one has a vector [1 2 3] .. what is the proper way to check if number 'a' is contained in the vector?

15:42 (some #{a} v) is failing for me

15:45 Lau_of_DK: (some #(= 5 %) [1 2 3 4 5])

15:45 danlei: leafw: if i understand you right: (let [a 1] (some #(= % a) [2 3 1]))

15:46 rhickey: user=> (some #{2} [1 2 3 4])

15:46 2

15:46 blarfo: can i shorten this: (fn [x] (= x true )) ?

15:46 Lau_of_DK: Guys, if you check out the macro time in core.clj - I would like to modify it, so that instead of just printing the execution time, that it actually attaches it as meta-data, but Im having some difficulty - Can anybody see how that could be accomplished?

15:47 rhickey: leafw: what didn't work?

15:47 leafw: never mind. Extra tick in macro.

15:47 thanks guys.

15:47 debuging macros is hard.

15:47 Lau_of_DK: blarfo: #(= true x) ?

15:48 hiredman: I have the latest clojure release, and if I try to def ? to :x it binds :x to the symbol e similar thinsg happen when trying to use other unicode entities as symbols

15:48 rhickey: blarfo: true? does that

15:48 hiredman: the interrobang ? turns in the symbol =

15:49 ? seems to work ok though :P

15:53 Lau_of_DK: Come on guys, its a very simple macro, any takers? :)

15:55 AWizzArd: Lau, what exactly did you try so far, and what happened?

15:56 rhickey: hiredman: did that work in the past?

15:57 Lau_of_DK: AWizzArd: Im trying to return (with-meta ret# (calculus)) instead of prn then ret#

15:57 But Im not sure if I can still get an accurate time

16:01 AWizzArd: In principle the timing should be over before you attach the meta data and/or print it out into the repl. So I guess the timing would stay as accurate as your current hardware allows.

16:02 Lau_of_DK: user> (timer (take 10 primes))

16:02 (clojure/let [start__4753 (System/nanoTime) ret__4754 (2 3 5 7 11 13 17 19 23 29)] (clojure/with-meta ret__4754 {:time (clojure/str (clojure// (clojure/double (clojure/- (. java.lang.System (user/nanoTime)) start__4753)) 1000000.0))}))

16:02 This looks funny

16:03 AWizzArd: Oh, clojure// is division yes? :-)

16:03 Lau_of_DK: But the timing here is pretty important since its a benchmarking/stress-testing program Im writing

16:03 yes

16:04 AWizzArd: What I find very strange is that there are still no complex numbers in the standard java lib.

16:06 Lau_of_DK: In a macro like (defmacro test [expr] (let [ret# ~expr]).. Does ret# already at the point hold the return value of expr?

16:07 hiredman: Lau_of_DK: you may have already run into this, but (with-meta ret# {:x :y}) as the tail of the macro raises and exception

16:08 but (with-meta [ret#] {:x :y}) does not

16:10 Lau_of_DK: I cant even get a result, I just get a macro-expansion

16:10 hiredman: huh?

16:10 huh?

16:11 Lau_of_DK: hehe

16:11 user> (timer (take 10 primes))

16:11 (clojure/let [start__4817 (System/nanoTime) ret__4818 (2 3 5 7 11 13 17 19 23 29) user/benchmark (clojure/str (clojure// (clojure/double (clojure/- (. java.lang.System (user/nanoTime)) start__4817)) 1000000.0))] (clojure/with-meta [ret__4818] {:time user/benchmark}))


16:11 Like this - This is not what I paid for

16:12 In a macro like (defmacro test [expr] (let [ret# ~expr]).. Does

16:12 ret# already at the point hold the return value of expr?

16:12 hiredman: `(let

16:12 Lau_of_DK: I have that

16:13 hiredman: I think yes, but it sort of depends on what you mean by "that point" and the quote

16:13 Lau_of_DK: I mean, does ~expr = evaluation

16:13 hiredman: yes

16:15 http://www.thelastcitadel.com/clojure/time-meta returns a vector with the metadata associated to vector, and the result in the vector

16:15 if I try it without a vector it throws an error

16:16 in fact, the same error I get from (with-meta 5 {:x :y})

16:16 so nums don't get metadata

16:17 and the function I was testing it on, returns a num

16:17 danlei: just symbols or collections, afaik

16:18 Lau_of_DK: hiredman: I dont quite understand your code. You define tim#, but in the map you use :time and :a, which are defined nowhere, what gives?

16:20 hiredman: oh

16:20 I think I made a bug

16:21 :a should be tim#

16:22 Lau_of_DK: k

16:24 Chousuke: hmmh

16:24 is there a reliable way to determine whether a symbol is a gensym or not?

16:24 hiredman: seems like you almost might as well just have it evaluate to a hash {:time n :result output}

16:24 if you need a collection to attach metadata to anyway

16:25 Chousuke: 5 can't have metadata, it's a constant :/

16:25 hiredman: yeah

16:25 I figured that out :P

16:28 danlei: my shot: http://paste.lisp.org/display/70520

16:28 Lau_of_DK: thanks danlei

16:28 danlei: np

16:29 still gotta lookup things all the time ...

16:29 Lau_of_DK: Im really starting to like the Clojure-community

16:30 In the early days answers were much harder to come by

16:30 danlei: oh

16:30 ,'s sneaked in ...

16:33 Lau_of_DK: that's better: http://paste.lisp.org/display/70521

16:33 Lau_of_DK: thanks alot danlei, its an interesting approach

16:33 notice: You can annote your own pastes to keep the history

16:35 danlei: Lau_of_DK: just saw it after i pasted the 2nd one =), thanks

16:40 Lau_of_DK: danlei: that fancy (or (and (or (...)))) thing you got going on, thats just to check if its a symbol, if so attach meta, if not, just return it

16:40 ?

16:41 danlei: Lau_of_DK: yes, could've used if, or some other conditional

16:41 Lau_of_DK: No no, (or (and (or))) looks good, its original :)

16:42 Chousuke: hmm

16:42 functional programmin really is fun :)

16:43 I wrote a neat little function to return a seq of all the names bound by a destructuring binding form.

16:43 Lau_of_DK: Paste it!

16:44 Chousuke: I was fortunate enough to find 'destructure from core.clj so I didn't actually have to write the destructuring myself...

16:47 http://paste.lisp.org/display/70524

16:47 might be useful if you're writing macros.

16:48 the problem is though that it ignores gensyms for now (because destructure generates gensyms)

16:49 Lau_of_DK: looks nice, as concise as can be

16:49 Chousuke: also I notice there's an error

16:49 should be (destructure binding-form), not (destructure bindings)

16:51 that doesn't necessarily find all gensyms either :/

16:51 Pupeno: Hello.

16:52 Lau_of_DK: Hello MR. Pupeno

17:01 pjb3: Is this a bug?

17:01 user=> (for [i (range 0 2)] (do (println i) i))

17:01 (0

17:01 0 1

17:01 1)

17:01 I would expect

17:01 user=> (for [i (range 0 2)] (do (println i) i))

17:01 0 1

17:01 1)

17:01 oops, not that

17:01 user=> (for [i (range 0 2)] (do (println i) i))

17:01 0

17:01 1

17:01 (0 1)

17:02 What happens is that somehow the values that are printed are mixed in with the return value

17:03 Lau_of_DK: Its not a bug, println doesnt return anything, it just mangles the output

17:03 (for [i (range 2)] (do i))

17:03 (0 1)

17:03 This is the return, and in that, you have printed first 0, then on the next line 1

17:03 pjb3: Lau_of_DK: so why isn't the result

17:03 0

17:03 1

17:03 (0 1)

17:04 Shouldn't the first println happen, then the second, then expression is finished evaluating and the REPL prints the return value

17:04 ?

17:05 rhickey: pjb3: for is lazy, use dorun on the result or switch to doseq which now takes all the options of for, but is eager

17:05 Chousuke: hmm

17:06 apparently destructure only generates gensyms prefixed vec__ and map__... maybe I could use that to filter them out :/

17:06 ugly, though :(

17:07 Lau_of_DK: Regex is ugly...Perl is regex....I'll stop here :)

17:07 pjb3: rhickey: both of those print, but return nil

17:09 Pupeno: How do you quit Slime?

17:09 Other than by manually killing all its buffers?

17:09 danlei: Pupeno: ,sayoonara

17:10 Pupeno: danlei: cryptic! thanks.

17:10 pjb3: (let [x (for [i (range 0 2)] (do (println i) i))] (doall x))

17:10 that works

17:11 Pupeno: And when you get errors, is there a way to dismiss them without killing the window?

17:11 danlei: Pupeno: q

17:11 pjb3: or I guess just (doall (for [i (range 0 2)] (do (println i) i)))

17:11 danlei: Pupeno: if you're in the debutter

17:12 *bugger

17:12 Pupeno: danlei: I used to do that with CL, but that is killing with the window.

17:13 danlei: Pupeno: hm, for me, q works the same with clojure and cl

17:15 Pupeno: danlei: I don't know about CL as I haven't used it in a long time, all I know is that q kills the (Emacs) window here.

17:16 danlei: hm, i don't think i can help you, works fine here. (ends the debugger, but doesn't kill the buffer)

17:16 Pupeno: ok.

17:16 probably my unstable emacs playing tricks on me... who knows.

17:17 danlei: Pupeno: but then, i'm not sure if i understand you right. do you mean 1. 2 buffers, 2. error -> debugger -> q 3. only one buffer open?

17:21 Pupeno: danlei: not buffers, windows. But the answer is probably yes (Emacs terminology is weird).

17:21 pjb3: wow, duck streams FTW

17:22 (with-open [rdr (reader "http://www.google.com")] (doseq [l (line-seq rdr)] (println l)))

17:22 danlei: Pupeno: hm. in my case, there is no debugger buffer after q, but the window buffer stays open. (in emacs terminology)

17:22 pjb3: (with-open [rdr (reader "/etc/passwd")] (doseq [l (line-seq rdr)] (println l)))

17:23 I remember things like that being a major PITA when I was doing a lot of Java programming

17:24 Pupeno: danlei: in my case, the emacs window gets destroyed, like if I did C-x 0.

17:24 danlei: pup: hm

17:25 hiredman: pjb3: word

17:26 Chousuke: I improved my bound-names function somewhat, but still it could be made more robust. any ideas? http://paste.lisp.org/display/70528

17:26 danlei: Pupeno: then maybe it's your emacs. 2 window stays open here, if there was one, before the debugger popped up

17:27 Pupeno: danlei: yes, maybe it is.

17:28 Chousuke: is that binding form even correct :/

17:28 meh, anyway. you should get the idea :)

17:29 Pupeno: Anyway... anyone working on 1094+ compatibility for compojure?

17:50 Ok, done.

17:54 meredydd: Pupeno: Excellent. Does anyone have integration with more recent Jetty versions, too?

17:55 I tried to play around with the Comet stuff a while ago, but the docs are really thin on the ground for the two-iterations-behind version they're using

17:56 Pupeno: meredydd: you mean jetty 7? not sure.

17:56 dthomas: I'm a Python programmer learning Clojure. I'm doing a simple little web scraping exercise, and I'm having trouble converting the idea of a generator to something in Clojure. Could anyone point me in the right direction for doing something like http://paste.lisp.org/display/70530 in Clojure?

17:57 Pupeno: meredydd: you can check the compojure network: http://github.com/weavejester/compojure/network

17:57 walters: dthomas: i think the rough equivalent is lazy-cons

17:57 meredydd: That's wicked cool.

17:57 I think I need to learn git.

17:58 pjb3: If you want to find the first element in a seq that meets a predicate, do you have to do (first (filter pred coll)), or is there a different function that does that?

18:02 dthomas: walters: That was my first guess. Will returning the results in a lazy sequence mean that all the members of the sequence are going to hang around until the whole sequence becomes eligible for garbage collection?

18:03 walters: dthomas: you're talking to a python expert but a total clojure newbie, so we've about exhausted my clojure knowledge =) but my guess is yes

18:03 hiredman: in the irc log someone mentions some "agents and refs in use" slides of rhickey's, does anyone know if those are around somewhere?

18:03 Chousuke: dthomas: hmm, no.

18:04 hiredman: as long as you don't have onto the head, right?

18:04 dthomas: walters: Yeah, my guess too. That led me to think that lazy sequences aren't 100% the right solution.

18:04 Chousuke: dthomas: as long as you don't hold on to the head, previous parts may be freed.

18:07 meredydd: pjb3: (some pred coll) does the trick

18:07 dthomas: Chousuke: Ah, so (doseq x (lazy-make-a-lot-of-stuff) (prn x)) won't eat up more memory than the biggest item in the lazy sequence (ideally)?

18:08 meredydd: uhh, wait, no

18:08 pjb3: meredydd: some returns the value of the pred

18:08 meredydd: oh, rats.

18:09 pjb3: this does the trick: http://gist.github.com/25589

18:09 dthomas: Chousuke: (Sorry, that's actually not very good phrasing on my part, but I hope my intention was clear.)

18:10 meredydd: pjb3: Or just (defn find-first [pred coll] (some #(when-let x (pred coll) x) coll)

18:11 Oh, what am I talking about? (defn find-first [pred coll] (first (filter pred coll))) is simple, easy and efficient.

18:11 pjb3: meredydd: oh, filter is lazy?

18:12 meredydd: of course

18:12 pjb3: right

18:13 rhickey: dthomas: if you (lazy-cons first-expr rest-expr) neither expr is evaluated until needed. If rest-expr in turn is lazy, then the result is that the only part of the sequence that exists at any point is the part you are using. Can definitely substitute for generators, albeit with a less imperative approach. You can make infinite sequences etc

18:15 pjb3: that would be cool if first had a two argument version that let you avoid the filter

18:15 dthomas: rhickey: Cool, "only part of the sequence that exists at any point is the part you are using" is what I was looking for.

18:15 pjb3: or maybe that would just be overloading that method name too much

18:15 but (first even? [1 2 3]) makes sense to me

18:16 dthomas: Thanks walters, Chousuke, rhickey.

18:16 rhickey: dthomas: keep in mind the caveat about holding onto the head though, as doing so will keep all of the realized seq alive

18:16 dthomas: Now I just have to figure out how to translate that Python to a lazy-cons where I can't rebind page.

18:17 rhickey: Dumb question: by "head" you mean the head of the lazy-cons itself, not the first value in the lazy sequence, right?

18:18 rhickey: dthomas: right

18:25 Chousuke: meh. I just can't figure out a reliable way to determine what symbols are generated by 'destructure :/

18:26 I suppose the only way to determine what symbols it actually binds (other than its own gensyms) would be to write my own 'destructure clone that keeps track of the names. :(

18:26 Something that, looking at the implementation of 'destructure, I don't want to do.

18:27 gnuvince_: Where is it defined that things like Strings and arrays implement seq?

18:28 meredydd: dthomas: I can't get lisppaste.org to work

18:29 Chousuke: gnuvince_: they don't. (seq? "foo") returns false

18:29 meredydd: don't use the paste-to-channel feature.

18:30 it seems to be broken

18:30 hiredman: seq knows how to make seqs out of strings and arrays

18:30 meredydd: aha

18:30 In any case, it's a one-liner:

18:30 (filter result-is-relevant? (reduce concat (pages-from-search query)))

18:30 then just make (pages-from-search) return a lazy seq of the pages, etc

18:30 hiredman: most functions that operate on seqs call seq on the args first

18:30 gnuvince_: Chousuke: I meant the Seq interface: you can do (first "hello") and (rest (to-array [1,2,3]))

18:31 dthomas: meredydd: I like reduce + concat. But how do you stop the first time result-is-relevant? returns false?

18:32 Chousuke: gnuvince_: as hiredman said, 'first calls 'seq on its argument

18:32 dthomas: that version doesn't doesn't stop.

18:32 dthomas: you'll have to use the find-first defined above

18:32 meredydd: dthomas: change that (filter) into a (take-while)

18:32 Chousuke: or that. :p

18:33 meredydd: That will give you the seq up until the first non-relevant result.

18:33 dthomas: take-while, awesome. That's exactly what I needed and didn't want to figure out how to write myself.

18:34 Chousuke: no-one can help me with my problem? :(

18:34 meredydd: What are you trying to do, Chousuke?

18:35 Chousuke: figure out what names are bound by a binding form

18:35 meredydd: Why?

18:35 Chousuke: http://paste.lisp.org/display/70528 here is something that "works", but is prone to failure

18:35 dthomas: Oh, OK, take-while's implementation is embarassingly simple.

18:36 Chousuke: meredydd: it might be useful for macros that create context.

18:36 meredydd: I'm trying to figure out if I can make with-open support destructuring :)

18:37 I did it for simple [a b c d] binding forms but full destructuring support is more difficult. :/

18:37 meredydd: How so? Give me an example of the fantasy syntax you want to implement.

18:38 And does the version you posted there not work? Seems no more ugly than is necessitated by what you're trying to do.

18:39 My only comment is that this is tripping my "this is a question to which all the answers are ugly; are you sure you're asking the right question?" sense

18:41 rottcodd: it would be nice if into-array had an optional type arg for cases where coll is potentially empty

18:42 hiredman: uh

18:42 wha?

18:42 rhickey: rottcodd: it does now, (doc into-array)

18:43 rottcodd: ah, thanks

18:44 Chousuke: meredydd: http://paste.lisp.org/display/70528#1

18:45 meredydd: Oh, and rhickey? A belated thank-you-very-very-much for AOT.

18:46 Chousuke: meredydd: my question is simple: how do I get a list of the names bound by a given binding form?

18:46 rhickey: meredydd: you're welcome!

18:46 Chousuke: the answer, as you can see, is not as simple :(

18:46 unless there's some magic I'm unaware of.

18:58 meredydd: Chousuke: Well, the simplest way would be to separate a binding list into assignees (first element, third, fifth, etc) and values (second, fourth)

18:58 then descend into the assignees and pull out everything that's a symbol.

18:59 I think that should work.

18:59 (rather than relying on (destructure), which isn't very official or supported IIRC)

19:05 hiredman: hwa

19:06 my unicode issues are a reult of using jline

19:06 result

19:09 Chousuke: meredydd: but that would mean rewriting destructure :P

19:09 danlei: how would one just run a simple function in a thread? i tried things like (.start (Thread. (pr 'hello))), but that won't do

19:09 Chousuke: meredydd: which is not simple at all

19:09 meredydd: Chousuke: No, it wouldn't. You just ignore the keywords, and pick out *all* the symbols.

19:09 danlei: + #

19:10 Chousuke: meredydd: but what if someone wants to bind a symbol as the value of another symbol? :/

19:11 hiredman: last I checked the printing functions did not work in other threads, I think you need to explicitly bind *out*, or something

19:11 meredydd: You just want the bound symbols' names, right? You don't want to actually get their value expressions. So you can safely ignore all the keywords, and the values in map binding expressions, etc

19:11 danlei: hiredman: thanks

19:11 Chousuke: hmm, right.

19:12 binding always happens in pairs, right?

19:13 hiredman: danlei: nm

19:13 danlei: is there an equivalent to cl's #. ?

19:13 hiredman: danlei: forget that about binding *out*

19:13 danlei: or how would i bind *out*?

19:13 hm

19:13 ok

19:14 hiredman: (.start (java.lang.Thread. #(prn :x))) prints :x here

19:14 danlei: not for me

19:14 but i'm is slime, in cl i've got do bind *standard-output* with sharpdot-reader (#.)

19:15 how would i do that in clojure/slime?

19:15 hiredman: danlei: try prn instead of pr

19:15 pr doesn't print here

19:15 danlei: (.start (java.lang.Thread. #(prn :x)))

19:15 will just output nil, prints nothing here

19:16 i guess it'll work on the blank command line, i'll check

19:16 yes, it does

19:17 so it boils down to binding clojures equivalent to *standard-output* to slimes

19:17 it gets printed in the inferior-lisp buffer

19:18 is there a way to access a value at read-time?

19:23 rottcodd: danlei: I use M-x slime-redirect-inferior-output

19:24 danlei: rottcodd: perfect, thank you!

19:30 Chousuke: hmmh

19:30 (remove #(or (keyword? %) (= '& %)) (flatten (map #(if (map? %) (seq %) %) (map first (partition 2 form)))))) <- not very clean, but that should leave me with just the symbols in a binding expression.

19:31 anyone spot anything fishy? :p

20:29 Chouser: Chousuke: does that handle :keys, :syms, :strs ?

21:42 scgilardi: Chousuke: in my patch to allow destructuring in the "binding" form, I distinguished the generated symbols by attaching metadata to them. Of course that required modifying destructure, but I thought I'd mention that the need has come up before. http://tinyurl.com/5uyke5

21:55 grkz: /part


22:26 jtoy: hi guys, im coming from ruby, how do you build larger programs in clojure? I onyl know about oop systems, is there papers/articles i can read that relate this to clojure?

22:38 gnuvince_: jtoy: with functions and macros and multimethods and the rich data structures.

23:18 topo: oh

23:18 theres a lot of people in this channel

23:18 hello

23:19 Chouser: hi

23:30 topo: hello

23:30 i just download clojure for macosx

23:30 how can i make it work?

23:30 theres a .jar archive but nothin happens when i run it

23:30 Chouser: add clojure.lang.Repl to your command line

23:30 albino: how are you running it?

23:31 Does java -jar /path/to/clojure.jar still work?

23:31 that's how I'm used to invoking it

23:31 topo: just click 2 times in the .jar

23:32 so i do program in my command line?

23:32 oh

23:32 i need java?

23:33 albino: topo: yes, clojure runs on the java virtual machine

23:33 topo: albino do you have macosx?

23:33 albino: topo: no, I'm on linux

23:33 topo: but java kind of takes the os out of the equation after you figure out how to get it for your specific platform

23:35 topo: i got this:

23:35 toppos-computer:live-coding-lisp topo$ java -jar /users/topo/desktop/clojure/clojure.rar

23:35 Unable to access jarfile /users/topo/desktop/clojure/clojure.rar

23:35 oh jar

23:35 haha

23:35 danlei: and capital U

23:36 topo: oh i got user==>

23:36 cool

23:36 whats that?

23:36 can i program lisp there?

23:36 like the repl?

23:36 Chouser: topo: you're going to have to go read some docs or watch a screencast or something.

23:36 danlei: it's called a repl, you can type expressions, it will evaluate and print the result

23:36 try (+ 1 2)

23:36 topo: oh nice

23:36 it works

23:36 cool

23:36 yes

23:37 Chouser: topo: do you know lisp?

23:37 topo: can i port my opengl app from common lisp to clojure?

23:37 is that possible?

23:37 and making java applets?

23:37 is that possible?

23:38 chouser yes i been experimenting with common lisp

23:38 Chouser: topo: ok, Clojure is not CL. There are many differences, some subtle, some not. Don't expect CL code to just work.

23:39 there are OpenGL libs for Java, so Clojure can use those easily. That should be possible.

23:39 topo: does it have macros?

23:39 danlei: yes

23:39 topo: cool

23:39 im gonna read a tutorial

23:39 looks interesting

23:43 danlei: everytime i do some sort of (.get (... (.invokeAll pool ...))) threr is a reflection warning. (reference to get ...), can i ignore that? if yes, can i surpress it?

23:44 Chouser: danlei: you must be using slime

23:44 danlei: Chouser: yes, i am

23:44 Chouser: You can ignore it. The reflection warning indicates a performance hit at runtime.

23:44 danlei: ah, ok

23:45 can i avoid getting it printed every time?

23:45 Chouser: I don't have slime, but you can try (set! *warn-on-reflection* false)

23:45 danlei: ah, that did it. thanks, chouser

23:46 Chouser: I think it's a mistake for slime to have in on by default -- the regular REPL doesn't.

23:46 danlei: ok, thanks

23:46 Chouser: To avoid the runtime hit, look into type hints. But don't bother unless you really need the performance -- they're ugle.

23:46 ugly

23:47 danlei: ok. i'll just ignore it, for the time being

23:48 Chouser: good choice. :-)

23:48 danlei: =)

Logging service provided by n01se.net