#clojure logs

2008-07-18

01:14mebaran151in the Netbeans plugin, can you access the current buffer to test it?
01:31mebaran151also, how do I convert a Java Hashmap to a Clojure hash?
01:31mebaran151any convenience method?
01:43hoeck``mebaran151: no, only `seq'
01:43mebaran151if I turn it into a seq, do I just get a list of tuples?
01:44hoeck``yes, a list of Hashmapentrys
01:44hoeck``(apply hash-map (mapcat #(list (.getKey %) (.getValue %)) (seq h)))
01:44hoeck``would then convert it to a clojure hash-map
01:47slavasounds like something that should be built-in
01:48hoeck``maybe it is already??
10:34meredyddOkay, this is a new one:
10:34meredyddjava.lang.ClassCastException: clojure.lang.PersistentHashMap cannot be cast to java.util.Map
10:35meredydd("...and why the hell not?")
10:38meredydduser=> (instance? java.util.Map {})
10:38meredyddfalse
10:42mebaran151I'm getting an incomprehensible class cast exception
10:42mebaran151I'm trying to create an httpservlet, following the guide online and using a proxy object, but it doesn't seem to want to play along...
10:44meredyddrhickey: aha, the very man I'm looking for.
10:44rhickeyhey
10:45meredydd(instance? java.util.Map {}) --> false.
10:45meredyddI'm fairly sure that shouldn't be happening.
10:45meredyddYou implement Collection in APersistentMap, but although you import Map, you never implement it
10:45rhickeyright now the Clojure collections only implement java.util.Collection
10:46meredyddUm...why?
10:47meredyddAny chance you could add basic Map support to APersistentMap, pretty please?
10:48rhickeyThat's all I've gotten to so far. Also, Map is a pain, in that several key functions require implementations of Set (entrySet/keySet)- I haven't determined what it takes to provide them efficiently
10:48rhickeymeredydd: you could submit a patch
10:49meredyddI am very willing to do so.
10:49meredydd(This one's something of a deal-breaker for this app :) )
10:49meredyddISTR there's some sort of licensing hoop I should jump through
10:49meredyddDoes it involve a paper transaction, or is "I hereby assign the rights to copy, reproduction and my firstborn child to rhickey" sufficient?
10:50rhickeyhttp://clojure.org/contributing
10:51meredyddAha - that's new. Thanks.
10:51rhickeyOne issue is that Map doesn't implement Collection
10:51meredyddHmm...so it doesn't. Do you have a particular objection to my leaving the existing Collection implementation in place, and just adding a Map implementation on top of it?
10:52rhickeythat would be the plan, but I don't know if there are issues
10:52meredyddOkay. I'll have a go.
10:52hoeckis it possible to get the class object of a class generated with gen-and-load-class by using Class.forName?
10:53rhickeyanother gotcha is that the easiest way to implement Map is by deriving from AbstractMap, but APersistentMap already derived from AFn, you you'll have to choose
10:53meredyddhoeck: Why don't you just use Object.getClass()?
10:54meredydd(Bah. Transatlantic snail mail - that's going to hurt. Better hope Subversion's merging is decent...)
10:54hoeckmeredydd: pivot (a java gui framework) requires you to give a classname as a string
10:54hoeckin order to start the desktop-app
10:55rhickeyhoeck: if you define a class ns.Foo with gen-and-load-class then just saying ns.Foo will give you the class
10:55rhickeyhoeck: ah, you may be into gen-and-save-class territory if you want Java clients to see it by name
10:56meredyddrhickey: All right to send you a patch for visual review before the agreement hits you? Best not build further code on top of something that's barking up the wrong tree.#
10:56rhickeymeredydd: yes, and you can email me a scan while the paper is en route
10:57hoeckrhickey: yeah right, that works pretty well, but a pivot desktop application is normally startet from the commandline and expects a classname as the app-object to start
10:58rhickeyhoeck: gen-and-save-class
10:58rhickeywas made for those scenarios
11:02meredyddrhickey: Ah, thanks for that. Read that just before I sealed the envelope :P
11:05hoeckrhickey: thanks!
11:48meredyddrhickey: Are you keeping source-level compatibility with a particular JDK version?
11:57rhickeymeredydd: yes, jdk 1.5 please
11:57meredyddrhickey: 1.5 has generics, right?
11:58rhickeyplease avoid generics
11:58meredydd(not that I'm actually using them, but there's a piece of API that wants a Set<Map.Entry>, where the 1.4-and-earlier ones just have a Set)
11:58rhickeyyour parameters will all be Object anyway
11:59rhickeyah, well then you'll be ok as Clojure's entries are Map.Entry
12:00meredyddSo I see. Makes life easier.
12:01meredyddOf course, they'll all be delivered to me as Objects, so there will be one unpleasantly-ugly cast at the return statement for that method
12:01meredydd(which, thanks to the magic of type erasure, will be completely removed for compilation. *sigh*)
12:23rhickeyanyone with Ant knowledge here? I'm looking at putting boot.clj etc in correct classpath-relative dirs in the jar, plus thinking about including contrib eventually, so need the ant script to find .cljs anywhere in the src tree and put them in the corresponding spot in the jar
12:23rhickeyright now it pulls .cljs from /src and pus them in the root, hard-wired
12:23rhickeyputs
12:25meredyddrhickey: Looking at your map implementations, I see what's obvious in hindsight, namely that map lookups are performed with Object.equals() semantics, rather than Util.equal()
12:26grahamfrhickey: hi Rich
12:26rhickeygrahamf: hi
12:26meredyddrhickey: Do you have a method for dealing with what happens if, say, an Integer and a BigInteger with the same numerical value are (assoc)ed onto the same map?
12:27grahamfthe 'copy' task in Ant is pretty flexible, you can provide an input filter (for cljs only) and specify a target dir, choosing whether to flatten or maintain the original structure
12:27grahamfhttp://ant.apache.org/manual/CoreTasks/copy.html
12:27rhickeymeredydd: this came up in - it's not something I can fix, as I don't own those classes and their definitions of hashCode
12:28meredyddyep, that's what I guessed
12:29meredyddand I'm presuming you're not willing to take the necessary performance penalty to put java.lang.Number checks into Util.hash() like you have with Util.equal()?
12:29rhickeypeople using mixed numeric keys will need to normalize with casts if they want to look up with different types, there's an aoutstanding todo to make sure reductions are always done in Clojure math
12:30rhickeymeredydd: not sure, the maps preceded the move to Java's boxed types
12:31meredyddHmm. Well, I'm going to vote for correctness over performance here, but I'm aware it's adding instructions to the lookup path
12:31meredydd(also, that it involves implementing a non-standard hash function on Numbers, which is icky, but at least it's an internal ickiness rather than an external ickiness)
12:32meredyddIf I'm feeling energetic, I'll lob you a patch on that one too - but as I can't branch'n'merge with someone else's repo, I'll probably stick to doing one at a time.
12:32grahamfrhickey: re: the ant job, what would relate a clj file to its destination dir? Do you need to analyze each clj file to determine its target dir, or it is just a matter of filtering and maintaing the right dir structure?
12:34meredyddRegardless, in the meantime I shall implement keySet() and values() with Object.equals() semantics, as that's what native Clojure sets do.
12:34rhickeygrahamf: the idea is for it to end up the same, x/y/z.clj shoud end up in /x/y/ in the jat
12:34rhickeyjar
12:35rhickeymeredydd: don't bother with the hash for now, too big a change, I'll need to think about it
12:36meredyddrhickey: Roger.
12:37rhickeygrahamf: if you look at Clojure's build.xml, I'm looking to replave the fileset entry for cljs, but don't know how copy job would fit in
12:38grahamfrhickey: heh. I'll take a quick look.
12:42grahamfrhickey: hm, that looks like it should already do what you want. I just added a src/graham/test.clj to my local copy, ran 'ant' and it added a graham/boot.clj to the new jarfile
12:44grahamfright, I see now that you don't need copy. I had assumed you were generating a temporary 'build' dir from 'src', and then jarring the 'build'.
12:47grahamfd'oh, and so you are, 'classes' is your 'build'. :-)
12:51meredyddThe 'remove()' function exists, incompatibly, in the two interfaces (Map and Collection).
12:52meredyddrhickey: Looks like the PersistentMap classes can be Maps or Collections, but they can't be both.
12:53rhickeymeredydd: all of the mutation methods are optional, can you not derive from both because of remove?
12:53meredyddUnfortunately not. They both take one Object arg, and Collection requires it to return boolean whereas Map requires it to return Object
12:53rhickeyaargh
12:54meredyddAnd "optional" just means "is allowed to throw UnsupportedOperationException"
12:54meredyddSo...how much internal mangling depends on *PersistentMap classes being Collections? :)
12:54rhickeyit's user code I'm concerned about
12:55meredyddHmm. Not to trivialise the concern, but I don't think that many people would expect a map to implement Collection
12:56meredyddthey'd expect it to implement, well, Map.
12:56meredyddUnless...do you document explicitly that a persistent map is a Collection rather than a Map?
12:56rhickeybut the only useful methods would have been iterator and size
12:56meredyddTrue...but we lose iterator() in Map.
12:57rhickeyI expect Java Maps to implement Collection and am pissed they don't
12:57meredydd(On the other hand, I'm guessing people haven't done too much hardcore Java interop work, otherwise someone would have been complaining about maps not being Maps before now...)
12:57meredyddrhickey: Agreed, entirely.
12:58meredyddUnfortunately, that, like so many things, is a poor decision long since fossilised by the weight of the Java platform.
12:58rhickeymaps are documented to implement Collection, but I think the key is that they be Iterable<Map.Entry>, which we could implement independent of Collection
12:58meredyddThis is what I'm thinking.
12:59meredydd(hmm...turns out IPersistentMaps are already explicitly Iterable)
13:00rhickeyah, there's more to it, contains and toArray
13:01rhickeywe seem to be getting to the point I've been at before with this...
13:02rhickeyoff to lunch, back soon
13:03meredyddk
13:17rhickeymeredydd: so I think for now you should just implement a class that wraps a Clojure map and implements Map
13:17meredyddHmm, define "for now"
13:17meredyddBecause I believe that to be an untenable long-term solution.
13:18rhickeyin what respect?
13:19rhickey(.someJavaMethod x (jmap m))
13:19meredyddIt's a huge mismatch between the languages if the data type you use and recommend as replacement for arbitrary data structures doesn't conform to the Collections API
13:20rhickeythat's a theoretical argument, being immutable they are hardly replacements
13:20rhickeyi.e. couldn't swap one for the other in existing code
13:20meredyddFair enough, but it's what you explicitly recommend everyone else uses instead.
13:21meredyddIt's not like immutable Maps aren't something Java's designed to cope with - there's a documented Right Way to do it
13:21rhickeyand so you might have to say (jmap m), doesn't seem prohibitive
13:22meredyddOkay, this will take a moment, because I'm trying to get to the little bit inside me screaming "It's ugly as sin!"
13:22meredyddHow about the other question: Why is it more important that a map be a Collection than that a map be a Map?
13:23meredydd(* trying to get to the rationale behind the little bit inside me...)
13:25rhickeyallows for most general code, non-reflective calls to size for instance
13:25rhickeytoArray
13:26rhickeyA map is a collection of entries
13:26rhickeyJava got that part wrong
13:26rhickeyJava got read-only wrong by not making it a base interface
13:26meredyddAre you talking about calls from Clojure code? Because it's very easy to keep those properties while still making it a map.
13:27meredyddI agree with you that Java got that part wrong.
13:27meredyddHowever, if you're talking about Java interop, which is what implementing the Collections API is all about
13:27meredyddthen making a map a Map is *vastly* more important for smooth working than making a map a Collection
13:27meredydd*smooth interworking
13:28meredydd(and if you do end up needing to something expecting a Collection of Map.Entrys - unlikely in java code, because of precedent - you could wrap that (uncommon) case in a fncall
13:29meredyddrather than the common one ("I have Clojure's native representation of a map, I want to pass it to Java code that's expecting its native representation of a map)
13:30meredyddYou seem to be concentrating on correcting an (admittedly bone-headed) decision in the design of an API...at the expense of actually conforming to it.
13:31rhickeythere are far more Java APIs that expect Collections
13:32meredyddTrue, but if you can find me one that's expecting a Collection of Map.Entries, I'll be very surprised
13:32rhickeyMany don't care what the element is
13:33rhickeythey need the size and to iterate
13:36meredyddHmm. I can't actually contest that argument (that you'll want use a map more often as a collection than as a map) - my impression and experience disagree with it, but I don't have hard figures to show it either way.
13:37meredyddDo you believe that you need to use it that way *so* much more that it's worth violating all these expectations, so you have to make the funcall in the Map case rather than the Collection case?
13:37rhickeyI'm not arguing against the utility of supporting the Map interface, but I also didn't create the incompatibility between Map and Collection that thwarts us here. Whether Clojure maps are more Maps than Collections is a philosophical debate, they are no more inherently one than the other
13:39meredyddHmm. There's a bit of practicality as well as philosophy here. By its nature, the only time the distinction is relevant is when doing Java interop.
13:39rhickeyGiven that they are already Collections, and it would be simply to make (jmap m) work, I think that's the way to go, and by 'for now' I mean until I can determine if switching is worth it
13:39meredyddWell, I see I'm not going to convince you, so I'll archive this patch and revert my tree.
13:40rhickeywhat tends to happen in these cases is switching from one to another exposes the costs of change in unanticipated ways
13:41meredyddI'll agree with that; the Argument from History is firmly on the side of Collections.
13:41meredyddIt's on the Argument from What's Nicer where we disagree.
13:41rhickeywell, toArray is used by Clojure, for instance
13:42meredyddThat's irrelevant; you can have a toArray without implementing Collection.
13:42rhickeyand access it via what type?
13:43meredyddI'd go for inventing a common superinterface for IPersistentMap and IPersistentCollection, myself
13:43rhickeybut it works on Collections too
13:45meredyddI guess I'm just upset by the inversion - in Java, it's a Map, and you call a function (entrySet()) to get a Collection of MapEvents
13:45rhickeyClojure supports treating all collections except Java Maps, pretty uniformly, making the change would add Clojure maps to the except column
13:45meredyddin Clojure, it's the other way around
13:45meredyddWorse - it puts Clojure maps *and* Java maps in the "except" column
13:45rhickey?
13:46meredydduhh...which comment was that ? to?
13:46meredyddthe "In Clojure it's the other way around", or "clojure maps *and* Java maps in the 'except' column"?
13:47rhickey"it puts Clojure maps *and* Java maps in the "except" column", to which it do you refer?
13:47meredyddOh - what I meant was that, currently, Clojure puts Java maps in the "except" column
13:48rhickeydepends on your perspective, not from the Clojure perspective
13:48cemerickIs there a concrete use-case for making clojure maps Java maps?
13:48rhickeyfrom there, only Java Maps are exceptions
13:48meredyddwhereas if you made Clojure maps into Java maps too, you'd end up with *both* in the except column
13:48meredyddwhich is pretty much what you'd said two lines earlier.
13:48rhickeyright
13:49meredyddcemerick: Well, I started with the Principle of Least Surprise - I'm using Clojure to drive Java code, and throwing Maps into Java methods, and got a nasty shock when I found out an IPersistentMap wouldn't go into a Map parameter
13:49rhickeyI tried to mazimize the genericity of code, for instance Clojure uses toArray, but others could use isEmpty or contains
13:50meredyddcemerick: I'm afraid I don't have the language-usage survey experience to say beyond "Passing them to things that expect maps", just as rhickey is saying "Passing them to things that expect collections"
13:51meredydd(and "using Collection methods on them locally")
13:51meredyddHmm. Here's a thought...
13:51rhickeyright now in Clojure if you say #^Collection x, x can be anything except a Java Map
13:52meredyddrhickey: Do you have a general mechanism for automatic coercion when you're looking up parameters for Java interop?
13:52cemerickI don't think having that survey would help, anyway. IMO, ensuring that clojure maps are collections is incredibly important. There has to be an overriding concern.
13:52meredydd(eg when you're converting a Number to an int to pass to an int-typed parameter)
13:53meredydd...actually, no, scrap that idea. It's an ugly hack, and an abstraction that can be made to leak like hell in a number of different ways.
13:53rhickeymeredydd: just special handling of primitives
13:54meredyddOkay. I've just spent a relatively enjoyable hour arguing with rhickey about language design, but it's time to get some actual work done.
13:54cemerickrhickey: do you still need ant assistance?
13:55meredydd(jmap) doesn't completely satisfy me, but I understand why you don't want to lose Collection compatibility from IPersistentMap
13:56meredyddso, when are we likely to see (jmap) in svn? (Not to rush you; just so I know whether to bother implementing one myself in the meantime)
13:56rhickeycemerick: I'll try grahamf's suggestion and call for help again when stuck, thanks
13:56rhickeymeredydd: if you implement jmap I'll add it
13:56meredyddokies.
14:10meredyddHmm...is there a sensible way of getting a lazy seq-backed Collection? So far I'm doing (apply list (vals map)), which is unpleasant and requires a complete eager traversal of the seq
14:11meredyddApart from that, here's a basic first draft: http://pastebin.com/m68e7610d
14:12cemerickmeredydd: (vals map) is already a lazy collection
14:12rhickeymeredydd: sets don't implement Set yet, but could
14:12meredyddcemerick: ha, so they do.
14:13meredyddNow why did I assume ISeqs weren't collections?
14:13meredyddrhickey: Do vectors implement List?
14:13cemerickno, they don't
14:14meredyddhttp://pastebin.com/m4c10e1af
14:15meredyddOh, argh.
14:15meredydd*That*'s why I wanted native Map support.
14:15meredyddBecause that's how Clojure does stuff, I'm passing a map of maps into my Java function
14:15rhickeylook, you need to go easy on me here, there are only so many hours in a day...
14:15meredyddnow I'm going to have to explicitly unpack them all from Clojure IPersistenMaps
14:16meredyddheh, sorry. I'll go away and write unpacking fns.
14:16rhickeyI'm not against support List or Set and there should be no problems doing so, but haven't had time to do that
14:16rhickeypatches welcome
14:17meredyddrhickey: Agh. Mind if I wing you a patch for a "getJavaMap()" in IPersistentMap? Cause I can't use (jmap) from inside my Java code
14:18rhickeyI had presumed you'd be doing this in Java and just calling from jmap
14:18meredydd(which of course now means that each time I unpack a Map in my Java code, I have to check whether it's a Map or an IPersistentMap, then either unpack or not, depending on whether it's Java or Clojure calling my method...
14:19rhickeywhat do you mean unpack?
14:19meredyddWell, I'm passing a complex pseudo-data-structure from Clojure to Java
14:19meredyddthe Java method expects a Map - that's fine, I can do that with (jmap)
14:20meredyddBut there are other maps stored within this map
14:22rhickeyJavaMapOnPersistentMap class, implements Map and IPersistentMap
14:22rhickey?
14:22meredydd(for example, {"meredydd" {"A-level" {"mark" 55} "GCSE" {"mark" 60}})
14:23rhickeywouldn't need to be unwrapped
14:23meredyddHow so?
14:23rhickeybecause (jmap m) would still be a Clojure map
14:23meredyddYes...but it's a pain going in the other direction.
14:23meredyddImagine I pass that blob above into my Java code.
14:24meredyddThe Java code wants to find out what mark I got in my A-level.
14:24rhickeyLook there ar eJava interfaces for all of the Clojure collections, use them in Java
14:24meredyddYep, I know.
14:25meredyddI didn't say it's impossible, just that it requires unpacking and forces bits of my Java code to know that the calling fn was written in Clojure rather than Java.
14:25meredyddAnyway, dinnertime.
14:25cemerickmeredydd: since the current impl of clojure maps doesn't line up with what your Java code is expecting, why not build Java maps in clojure?
16:32JamesIryGang, some nerd humor for your enjoyment: http://james-iry.blogspot.com/2008/07/java-is-too-academic.html
17:00cemerickJamesIry: Nice, is the 'academic' bit a slight riff on the dysinger episode? :-P
17:01JamesIrycemerick: inspired by it and similar discussions about many languages that I like
17:03cemerickYeah. The "academic" comments are rational coming from "trade" programmers, but it's almost always silly coming from anyone who's serious about it.
19:48slavaJamesIry: i never understood why 'academic' is used as an insult in some programming communities
20:13lisppaste8fyuryu pasted "Is it lazy?" at http://paste.lisp.org/display/63932
20:13fyuryucalling the defined function in list comprehension is lazy, right?
20:24JamesIryslava, me neither.
20:27Chouserfyuryu: yes, seek-left should only be called until it produces a non-nil
20:27Chouseryou can put a prn in there to see what it does
20:31fyuryuok, thanks. Doh!, I didn't think about prn, I just evaluated that in the REPL
20:32fyuryuChouser: so I always got what I wanted, but wasn't sure abt the rest