#clojure log - Jun 19 2008

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

7:12 asbjxrn: yrb, I don't think so. That is what rhickey suggested I use.

7:23 yrb: asbjxrn: I am divided if I like it or not, on onehand it makes it explict that I am using a nested class

7:50 asbjxrn: I guess there have to be some sort of separator anyway as clojure need to find thr class

8:37 cemerick: Chouser: Yesterday you wrote "(Math/pow 2 10)" -- which I assume is treating the Math class as a namespace, and all of its static functions as functions in that namespace. How is that set up (just evaling that sexp on my end yields an exception)?

8:37 blackdog: it's new in svn

8:38 cemerick: ah-ha

8:38 blackdog: thanks

8:38 blackdog: there's no setup it just works :)

8:41 cemerick: Yeah -- Rich's checkin comment for r910 indicates that that feature is "experimental". Is there a discussion of it somewhere?

8:42 blackdog: yes http://groups.google.com/group/clojure/browse_thread/thread/bc005da4989468c7#

8:56 cemerick: feh, I don't know how I missed that.

9:34 cgrand: hmmm, good to know: sets can't be used to implement canonicalizing mappings

9:34 rhickey: cgrand: ?

9:35 cgrand: (meta (#{#^{:id "in set"} []} #^{:id "not in set"} [])) returns {:id "not in set"}

9:35 (contrived one liner)

9:37 I expectied taht a set would return the key and not the arg if found

9:42 rhickey: that's what I get for enabling get on sets, eh?

9:43 cgrand: ?

9:44 rhickey: sets as functions of their keys

9:44 cgrand: yup

9:48 * Chouser_ cannot make sense of that expression

9:49 Chouser_: aren't you passing two args to a hash-set?

9:51 rhickey: cgrand: fixed

9:53 drewr: In general, does a NPE signify a bug in Clojure, or could I be doing something wrong to cause it?

9:54 rhickey: the only thing that is certainly a bug in Clojure is a verify error, for all else check your code first :)

9:55 drewr: Let me rephrase the question. Even if my code isn't correct, should Clojure be handing out NPEs?

9:56 Isn't that akin to my writing something in Python and getting a segfault?

9:56 rhickey: Chouser: that's a set with a metadata-tagged empty vector member being used as a function of another metadata-tagged vector, yielded arg (broken) rather than set member (fixed)

9:57 drewr: I'm willing to spend the time writing bug reports if clojure could handle the situation more gracefully.

9:57 rhickey: drewr: no, NPEs are often user bugs, and they are catchable by user code - what should Clojure do with them?

9:59 Chouser_: drewr: python libs don't hand out segfault. Java libs often throw NPEs.

10:00 drewr: Chouser_: Ah, I didn't know that was a common failure for Java libs.

10:01 cgrand1: rhickey: thanks for the fix

10:01 Chouser_: Well, that's my impression anyone. Someone that actually knows Java may correct me. :-)

10:01 s/anyone/anyway/

10:02 rhickey: So in Python you get a TypeError thrown - what's the real difference?

10:03 Chouser_: don't we get type errors in clojure too?

10:03 ok, thanks for the set explanation. I get it now. :-)

10:03 rhickey: you can get all sorts of errors, my point is they throw exceptions, you get stack traces etc, there's no magic to Python here

10:04 neither dumps core

10:11 yrb: rhickey: have you got any plans to implement nested class access along the lines of the recent static member access?

10:17 and do you think it would be a good idea for import to load the nested classes into the namespace automatically?

10:33 rhickey: yrb: no, nested classes have composite names - why, don't like $ ?

10:37 cemerick: Train of consciousness: I've got an interface with methods foo and bar. My impulse is to use a map (or structmap) so I can do stuff like (:foo obj) rather than (. obj (foo)), and so that changes are easy and efficient. However, I then need a function that will pop off proxied instances that implement that interface so as to interoperate, and a function that will unpack instances coming in from Java into a map (or structmap). This basically sucks -- I a

10:37 I guess this is getting back to the data-design topic. I'm probably making this harder on myself than it needs to be.

10:39 rhickey: cemerick: you can say (.foo obj)

10:39 both Clojure and Java code create instances of this interface?

10:39 cemerick: Yeah, potentially.

10:40 The nice thing about using simple maps is that changes are so efficient. Copying on changes is not something I want to do (although I guess that'd be required if I subclassed PStructMap).

10:42 A bunch of multimethods would essentially give me everything I want, except it'd require more code than what seems reasonable for this case.

10:43 * cemerick is probably just rambling at this point :-P

10:44 yrb: rhickey: it isn't the $, (I actually like the distinction) it is more not having to explictly import the nested classes of an class already imported

10:45 thought I am not sure if I would want that now...

10:47 I have mostly finished my awt/scene graph wrapper, and I don't think that style of java is very common outside the gui libs

10:48 rhickey: cemerick: so you want to use this interface functionally?

10:49 Java implementations of the interface are unlikely to be functional

10:49 cemerick: rhickey: well, this particular interface is read-only, so that's something

10:49 rhickey: but you can implement an imperative interface with a ref to a map as its state

10:50 cemerick: Further, the interface is ours, so that helps, too :-)

10:51 rhickey: that's good, I guess my 2 cents is, don't hide/avoid/wrap the interface, use Clojure goodness in your implementation of it

10:51 cemerick: rhickey: Sure, and considering the general case, where we implement the interface and use a ref and map as a backing store -- it's obviously preferable to touch that ref and map when you're on the clojure side of things.

10:52 The tricky part is being able to route and process instances that are implemented differently -- which brings me back to multimethods, I guess.

10:52 rhickey: caring about how they are implemented is a warning sign

10:53 cemerick: I know -- that's why I'm floundering a bit here :-)

10:54 I could just not care how anything is implemented, and always copy on every mutation. Of course, that sucks -- perhaps an eager optimization, but perhaps not.

11:00 rhickey: ah, I see, your interface is read only and you'd like to treat instances persistently?

11:00 cemerick: indeed

11:01 rhickey: I'm running now, perhaps can follow up later...

11:01 cemerick: Yeah, we'll see how the rest of the morning goes. :-)

11:17 This is (mostly) spurious, but shouldn't reduce take the initial value first, then the function and sequence? The way it is now, the (typically concise) initial val is in between two (potentially) verbose sexps.

11:22 cgrand1: cemerick: the current args order is mnemonic (at least for me :-) )

11:23 cemerick: cgrand1: it's just the opposite for me, but it's all moot now :-)

11:24 does the literature generally use [fn, val, seq] order, or is that ordering typical from other lisps, or...?

11:24 Chouser_: the initial value is immediately before the seq that forms the rest of the values. it does make a kind of sense.

11:25 (reduce list 0 [1 2 3])

11:25 cemerick: Chouser: Yeah, I can see that. I always think of seed values as binding more to the fns that they travel with. A totally personal mental model sort of thing.

11:26 Chouser_: I admit I generally have to look it up.

11:27 cemerick: From a totally practical standpoint, if you've got a fn of any complexity, finding that lonely initial value that follows it requires a little squinting.

11:27 At what point does a hash map tip over into a tree map?

11:27 Chouser_: never, I think.

11:28 PTreeMap is sorted, PHashMap is not, and I don't think there's any automatic conversion from one to the other.

11:29 cemerick: My apologies -- I forgot that PHashMap is a tree, internally.

11:31 Chouser_: I thought that might be it. I don't know how quickly it grows to what kinds of depths.

11:34 it'd be interesting to ask a particular hash what it's shape and depth is.

11:35 cemerick: One of Rich's screencasts goes into a couple of details about height and big-O guarantees.

11:39 cgrand: max depth: 6 (or 7, not sure of the details), 32 chlidren per node

11:40 Chouser_: but surely being a hash means the first node won't have a full 32 before it starts getting sub-nodes, right?

12:56 (double 2) is not equal to 4

12:57 drewr: Heh.

13:15 Chouser_: and so far I've had friends guess that it returns: 22, (2 2), and T

13:16 abrooks: 2.0?

13:16 :)

13:16 Chouser_: cheater.

13:17 abrooks: Not at all. I hadn't been in #noise yet. I just started here.

13:18 Chouser_: well, I guess I have to take your word for it, don't I? ;-)

13:18 abrooks: Indeed you do, unless you're snooping my gnu screen sessions.

13:19 I did know that the unboxed numbers made their recent debut and you eliminated several alternatives above.

14:01 Chouser_: If I want to refer generically to a sequential collection, including things like Java array, Clojure vectors, Clojure lists, etc. what's the best word to use?

14:02 I would use "list" but that has specific meaning in Clojure.

14:03 rhickey: Chouser: 'sequential collection' ?

14:04 Chouser_: and so my variables can be named seqCollA, seqCollB. ;-)

14:04 rhickey: these are Java variables?

14:04 Chouser_: well, I was trying to use the same name in both. Maybe I shouldn't bother.

14:05 rhickey: fred/ethel/ricky/lucy works for me :)

14:05 Chouser_: yeah.

14:06 abrooks: littlericky gets a bit long though.

14:06 jmbr: hi

14:06 Chouser_: hi

14:22 cgrand: chouser_: about hashmap depth, I remembered I had a heap dump somewhere, so I ran some queries on it: hashmaps of ~400 elements seems to have nearly no (ie 1-3 per map) node of depth 4

14:22 Chouser_: cgrand: cool, thanks.

14:23 rhickey: if hashes are good, depth should be roughly log32N

14:23 never more than 6

14:26 Chouser_: if two things hash the same, is there a linear bucket at the bottom of the tree?

14:26 rhickey: yes

14:26 Chouser_: I'm looking at the code and still can't tell. :-)

14:27 ok, thanks.

14:27 rhickey: sorry the persistent data structure code is lean and, well, mean

14:28 Chouser_: hm, but probably only if the hash is fully identical, right? You get more depth in the tree before you get the linear bucket?

14:28 rhickey: right, that's the 'trie' aspect

14:40 * abrooks wants to start a movement to call "tries" "retries" since TREE and TRY have horrible homophone collisions in the domain of computer science.

14:41 abrooks: This has bugged me since I came across JudyArrays long ago. Unfortunately, I'm not getting any traction. :-)

14:41 rhickey: yes, it's very annoying

14:42 Chouser_: can we also rename map or map, and perhaps double?

14:43 other sciences go and invent new latin-like words, don't they?

14:56 Lau_of_DK: Everything needs to stay exactly the way it is

14:57 Ive had enough trouble learning Clojure, coming from Lisp

14:57 abrooks: :)

14:58 Lau_of_DK: Perhaps we could use Danish terms instead of Latin?

15:07 Lau_of_DK: haha - you obviously dont know Danish

15:07 Speaking 100% objectively: Its one of the most disgusting languages on earth

15:10 abrooks: Lau_of_DK: You are correct. My Danish vocabulary is (). :)

15:11 Lau_of_DK: user> (. Integer (toString 11121231230000))

15:11 "1560900656"

15:11 This is not what I expected...

15:12 rhickey, is this your doing? Something is broke in the BigInt module?

15:15 Chouser_: Lau_of_DK: I think your BigInteger is being converted to an Integer in order to be passed to Integer/toString

15:15 Perhaps you wanted (.toString 11121231230000)

15:16 abrooks: Lau_of_DK: I thought English held the record for "Most Disgusting Language on Earth" (or maybe it was Klingon...).

15:16 Lau_of_DK: Chouser, ... Sure - so .toString is related to what.. if not Integer?

15:16 abrooks, I think it might actually be Perl, then Danish :)

15:17 Chouser_: .toString is being called on whatever the actual type of its argument is -- in your example, BigInteger

15:17 rhickey: user=> (int 11121231230000)

15:17 1560900656

15:17 Lau_of_DK: Aah I see

15:17 So as I was just about to complain about Dynamic typing, its just because I dont really understand it, Clojure is a bit more clever than I had anticipated

15:19 rhickey: user=> (str 11121231230000)

15:19 "11121231230000"

15:20 Lau_of_DK: thanks rhickey

15:41 rhickey, would it be possible to compare the speeds of C, Python and Clojure for some computations? Have anything along those lines been done?

15:50 rsynnott: Lau_of_DK: there was a python/clojure one on reddit recently,I think

15:52 Lau_of_DK: Thanks rsynnott , I'll go look

15:57 cemerick: I *think* the data-design issues I was going on about earlier *might* be more general than I thought -- similar issues arise if one were to implement (for example) a tree data structure in Clojure whose interface is defined in Java, but should ideally have a richer interface in Clojure. This might just be the cost of doing business with Java callers and callees, I suppose.

16:00 lisppaste8: Lau_of_DK pasted "Java Heap...?" at http://paste.lisp.org/display/62507

16:00 Lau_of_DK: Gents- Simple task. Euler style. Find the first x that produces an x! that has 7^20 trailing zeroes... My code fries the Java Heap in about 5 - 7 minutes, so I assume Im doing something wrong ?

16:11 (14 minutes actually)

16:13 Chouser_: thats a lot of zeros

16:13 Lau_of_DK: Yes ma'am

16:15 rhickey: cemerick: one option is to offer persistent 'mutation' in the interface, e.g. like IPersistentMap does

16:15 Lau_of_DK: Maybe its not supposed to be bruted though - There's a pretty clear pattern showing in the number of trailing zeroes

16:17 cemerick: rhickey: Yeah. Over time, we'll be doing exactly that for those interfaces we control and we can change in that way without freaking out our users.

16:20 In the general case though (or simply when you don't have that option), it feels like there should be a relatively direct way to pass around proxied maps (for example), and when you get such an object back, be able to dereference the proxy to get a hold of the underlying map again. Totally doable with a couple of macros and multimethods (and probably an interface to allow the dereferencing bit). We'll see how motivated I get as I go along.

16:20 rhickey: Any further suggestions you have are certainly welcome. :-)

16:21 rhickey: define and implement another interface for access to that implementation stuff

16:23 (ah, you got that already, nevermind)

16:26 cemerick: rhickey: times like these, I wish clojure had a gen-and-save-interface ;-)

16:27 rhickey: I might consider that

16:28 cemerick: In a year or so, clojure will be the best interface to asm around.

16:36 Lau_of_DK: (gen-and-save) = (save-lisp-and-die) ?

16:38 drewr: Lau_of_DK: No. It's for created a (non-proxy) Java class.

16:39 Lau_of_DK: Ah ok

16:40 drewr: It's actually GEN-AND-SAVE-CLASS now.

16:41 The -SAVE part refers to the fact it actually writes the bytecode to a .class file.

16:41 Pretty cool. Check out genclass.clj.

16:42 * drewr wishes all Java programmers were rhickey

16:42 drewr: The world would be a different place.

16:42 Lau_of_DK: drewr, did you know that rhickey is an alias for Skynet ver. 1.0 ?

16:44 drewr: Lau_of_DK: Surely he's at least r2 or r3.

16:55 cemerick: Is there a way to install a method by referring to an existing fn that I'm missing somewhere?

16:56 rhickey: cemerick: a proxy method?

16:57 cemerick: hrm, no -- for multimethods. So as to say (defmethod foo :bar some-fn)

16:58 Just if I happen to have an appropriate fn floating around that is independent as well as useful as a multimethod.

16:58 rhickey: not right now, you'll have to forward to it

17:39 meredydd: Hey

17:39 Who's responsible for the 'set namespace?

17:40 Chouser_: rhickey himself

17:40 meredydd: I just discovered it today, and it's The Shit.

17:40 Ah.

17:40 That...doesn't surprise me at all.

17:41 It's that beautiful :)

17:41 Chouser_: :-) Gotta run.

17:42 meredydd: In any case, I'd like to *beg* rhickey to make more noise about that feature. It's really something.

18:55 shizzy0: I have a weird idea, that I'm trying to do. Can I make an anonymous macro? (mac [x] ...)

18:56 rhickey: shizzy0: no, how would it be called?

18:57 shizzy0: (let [m (mac [x] ...)] (m stuff...))

18:57 ?

18:58 rhickey: ah, local macros like CL macrolet, and symbol-macrolet - nope, don't have those yet

18:59 shizzy0: (defmacro mac [parameters & body]

18:59 `(let [f# #^{:macro true}(fn ~parameters ~@body)]

18:59 (. (var f#) setMacro)

18:59 f#))

18:59 rhickey: it's not that simple

19:00 shizzy0: That's what I was playing with, but it doesn't like (var f#).

19:00 Right, it seems like a good opportunity to understand more of how things work.

19:01 rhickey: the compiler needs to participate in macroexpansion, right now there are no local macros

19:02 shizzy0: [nods] ok.

19:02 I'm just trying to stretch out in clojure, and see what I bump into.

19:02 rhickey: global vars can be tagged as macros, and their global definitions treated as macroexpanders, but local functions are not available to the compiler as macroexpanders

19:03 It's something I would have to add, not something you can do with macros

19:04 the concept is sound - I particularly miss symbol-macrolet

19:06 shizzy0: good to hear.

19:09 that the concept is sound. I hadn't used it in CL. :)

19:13 btw, rhickey, I really like what you've done. I haven't done anything with Java for a long time now, but I could see myself actually working in the JVM now.

19:14 rhickey: great!, thanks

19:22 meredydd: rhickey: By the way, I just discovered the 'set namespace, and am very impressed.

19:22 Although I am somewhat confused by the (->) macro. The docstring is a bit, um, opaque.

19:22 rhickey: cool, I don't think anyone else has looked at it

19:23 meredydd: Yeah...I'm really hoping you'll change that - write it up as one of the pages in the sidebar, perhaps?

19:23 rhickey: -> threads the argument and successive returns as the first arg of subsequent forms

19:23 meredydd: I really think that having the relational algebra expressible natively is a really powerful thing

19:23 rhickey: yeah, I hope to do more with it

19:24 meredydd: (plus, it provides something I can point to and say - "Look! Native sets and maps in a Lisp is a beautiful thing"

19:25 rhickey: personally I think it is a shame that Lisp has been tied to lists for so long

19:26 shizzy0: ok, I don't know if this was intended, but I think this is pretty neat.

19:26 (map eval (map and '(true false) '(true true)))

19:26 meredydd: rhickey: right...so if I did (-> 1 (- 2) (+ 1)) it comes out as 3

19:27 shizzy0: The fact you can apply and map macros, and you'll get something weird out of them, but if you eval them, you get the actual results you'd naively expect.

19:27 meredydd: Oh, yeah...actually, that was something I wanted to say, too.

19:27 I tried to do (map) with (and), and got some *mighty* funny results.

19:27 rhickey: meredydd: 0, no?

19:28 meredydd: Took me quite a while to figure out what went wrong. Any chance we could have a warning when some stupid programmer tries to do that kind of thing?

19:29 shizzy0: I got 0 for meredydd's expression.

19:29 meredydd: It's not always obvious which ops are macros and which are fns, and I could conceive of certain calls changing from one to another, say, between library releases

19:29 (Yes, sorry. I meant 0, which is what the interp gave me)

19:29 rhickey: and is a macro, so can't be mapped, but you can do (map #(and %1 %2) ...)

19:29 (map #(and %1 %2) [true true] [true false])

19:29 meredydd: I know - that's what I did. Trivial change, once I figured it out.

19:30 But as it stands, if you try to use a macro as a fn value, it lets you

19:30 rhickey: I might be able to catch attempted use of macros as values...

19:30 meredydd: It just uses the macro's code-munging function instead

19:30 rhickey: right

19:31 meredydd: which caught me somewhat by surprise.

19:31 shizzy0: rhickey: but if you eval the expression you get from using a macro as a function, you get the right value it seems like. I actually kind of like that unification of macros and functions.

19:31 meredydd: Any chance of a molly-guard for the rest of us? I agree with shizzy0 that it might be cool to be able to throw macros around and do interesting things with them

19:32 rhickey: something being a macro or function is part of its interface

19:32 in practice things don't toggle between

19:32 shizzy0: For instance, (apply and '(true false)) doesn't work but, (eval (apply and '(true false))) does.

19:32 rhickey: yes, as I said above, I might be able to flag it

19:32 meredydd: Perhaps like the reflection warnings - some explicit flag to say "I know what I'm doing, don't warn me about the fact that I'm taking this macro"

19:32 That'd be great AFAIC.

19:33 Oh, and one more, while I have you here. Looking at the doc for (->), I understand why I was so confused.

19:34 ...oh, no, scrub that. The doc's right, my brain's wrong. Ignore.

Logging service provided by n01se.net