#clojure logs

2008-08-18

04:10rhickey_I'll be traveling this week, checking in sporadically
09:58blackdogwhen using gen-and-load-class how do i specify a method returning void, if i miss it out i get a compilation error
09:59blackdog :methods [
09:59blackdog ['monitorSubscribe [Client Message] <what's here?>]
10:03Chousertry Void/TYPE
10:03blackdogah thanks
10:05blackdogyes, that works
10:06Chousergreat
10:52drewrAnybody know if JDBC takes some sort of Java collection for an IN operator?
10:52Chouseryou mean as opposed to a string?
10:53drewrFor a prepared statement. Like, "SELECT ... WHERE foo IN ?".
10:53drewrThen supplying an array for the parameter.
10:54drewrMy initial tests say "no" but I wasn't sure if I was at fault.
10:54Chouseran array works but other collections don't? (clearly it's not likely I'll be able to help you. ;-)
10:55drewrNo, arrays don't work. I think I'll just have to build up a string manually.
10:55Chouserah. ick.
10:55drewrClojure makes it bearable at least. :-)
10:56blackdogwhat's the quickest way of converting a clojure map to a java Map, i thought the clojure collections implemented the collection interfaces?
10:56blackdogbut it doesn't seem like i can pass a clojure map to a java function
10:56Chouserdrewr: did you try foo.setArray() ?
10:58Chouserdrewr: http://java.sun.com/j2se/1.4.2/docs/api/java/sql/PreparedStatement.html#setArray(int, java.sql.Array)
10:58drewrChouser: Ah, no. Didn't catch that in the docs.
10:58ChouserWell, I'm not sure it's right, but it looks like your best shot.
10:58drewrYep, thanks.
11:08Chouserblackdog: yeah, I'm not sure. Looking at the Clojure collections code I don't see them implementing many Java collection interfaces.
11:08ChouserMaybe just Collection.
11:10blackdogok, thanks Chouser, I have a little funciton to do it anyway, but I thought there had to be something better :)
11:11blackdoggiven there's into-array etc
11:13Chouserright. I'm a little surprised that PersistentMap doesn't implement Map -- it seems like it could.
11:14ChouserI wonder if I'm missing something
11:14Chouserblackdog: oh. Well, I wrote one for you too. ;-)
11:14Chouser(defn to-map [pm] (let [m (java.util.HashMap.)] (doseq [k v] pm (.put m k v)) m))
11:15blackdoggood enuff :)
11:18Chouserah, this is nice: (supers (class {}))
11:19Chouserso, no Map
11:20Chouserthough you do get Comparator, Serializable, and Collection
11:21blackdogyes, that's very useful
11:22Chouserhm, the Java Maps implement Map but not Collection. Clojure's Maps implement Collection but not Map. I wonder if that's on purpose.
11:27achim_pChouser: i'm a clojure beginner, and one of the first things i tried was converting a clojure map to a java.util.Map. i came up with this: http://snipplr.com/view/7734/ . it seems a little awkward, so i wonder whether this is the right (i.e. correct, most idiomatic, ...) way to do this. comments are very much appreciated!
11:28achim_pyour example cetrainly seems easier, but the whole map is being copied, as i understand it, right?
11:29Chouserachim_p: that's right -- mine is a copy. yours looks pretty good.
11:29Chousermakes me wonder even more if PersistentMap intentionally doesn't implement Map or if it's just an oversight.
11:30ChouserI think P-Maps use java.util.MapEntry -- do you really have to wrap them as well for entrySet?
11:32achim_phmm, probably not ... didn't know they already were MapEntries
11:35Chouser(class (first {:a 1}) ==> clojure.lang.MapEntry
11:35Chouserso that's not quite right...
11:35achim_palso shouldn't hava called the arg "map", this is really confusing :)
11:40Chouserheh, yeah, it's pretty easy to shadow builtin function names. "list" is another one I have to tiptoe around.
12:09cemerickChouser: the Map/Collection dichotomy is flaw in the collections lib -- and Rich chose to hew towards Collection. (the interfaces are incompatible because of the varying signatures of remove, so clojure maps can't implement both) There was a thread about this on the group about a month ago, I think. Can't find it right now, though.
12:10Chousercemerick: ah, now that you mention it, that does sound familiar.
12:10cemerickI've been away for a while -- has there been any discussion of AOT compiling of late?
12:10ChouserNot that I know of.
12:11ChouserIt was mentioned in passing on the group, but not in any way that would be helpful.
12:13cemerickwe're nearing the point where it would be extraordinarily helpful. Perhaps enough that we might have a run at it, or some kind of hacky obfuscation attempt at least.
12:13Chousersurely lisp isn't that had to obfuscate. Most of my code starts halfway there...
12:14cemerick:-) No, not hard at all. It's a little more complicated in Clojure, simply because you need to be careful of Java names.
12:14ChouserHere's that thread you mentioned. Thanks. http://groups.google.com/group/clojure/browse_thread/thread/64ae146a856e2291
12:16dhayaChouser, A more detailed thread on the same topic here. http://clojure-log.n01se.net/date/2008-07-18.html
12:18Chouserdhaya: thanks
12:19Chousercemerick: just over two months ago, rhickey: "I have thought about aot-compiling quite a bit, it may rise to the top of the todo list soon"
12:19ChouserI wouldn't hold my breath. :-)
12:20cemerickChouser: Yeah, I found that mention, too.
12:21cemerickHe's mentioned following the fasl model though, so an obfuscator + a custom classloader might end up leading to the same thing, at least in terms of usage.
13:51kotarakhmmm. How can I load a file (with absolute path) on Windows with load-file? (load-file "C:\\Foo\\bar.clj") throws an exception.
13:56Chousertry forward slashes?
13:56shooverHmm, the \\ syntax is working for me
13:56Chouserthat's a blind guess -- I don't have easy access to a Windows Clojure at the moment.
13:57kotarakHmmm.. maybe something else was messed. I have to check tomorrow. (Have only Win access at work)
13:57kotarakshoover: yep. will try again.
13:57shooverActually both slash styles work for me
16:27stuart_Hi all! dosync query. Is this the most idiomatic way to create a thread-safe counter in Clojure: http://pastie.org/255201?
16:27stuart_Compare with, e.g. a JRuby version: http://pastie.org/255134
16:28kotarakyou could use commute instead of alter
16:28stuart_with commute, couldn't two callers get the same value?
16:29kotarakno, but it doesn't matter whether you add one and then add one or the other way around. So it is more flexible than alter.
16:31stuart_the docs state that "commute allows for more concurrency than ref-set" but don't specify between ref-set and alter. Is it accurate to say that ref-set and alter allow equivalent levels of concurrency, but have different semantics?
16:32kotarakprobably. I have not much experience with concurrency.
16:36kotarakstuart_: say, you set the a ref to 5 in one thread and 7 in another one. Then you this does not commute. It matters which one comes last. But the counter will equal two 2. No matter which thread comes first. So it also doesn't matter in which order. This is exploited by commute as I understand.
16:39stuart_kotarak: I get that. What worries me (and I am rereading the docs now) is that in my case don't care about the final value after 4 calls (always 4!) but about the values returned to four callers
16:39Chouserkotarak: you might just use http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic/AtomicInteger.html
16:40stuart_Chouser: Good point!
16:41kotarakstuart_: then you probably don't want a ref, but some other means of syncronisation? Which is more deterministic.
16:41stuart_I am actually porting the examples from Goetz et al's Java Concurrency in Practice to Groovy, JRuby, Scala, and Clojure. For consistency with the other examples I don't wan't to use AtomicInteger, which the original example in Java didn't use, even though it was available.
16:42stuart_kotarak: Doesn't that just put me back to alter?
16:42kotarakstuart_: I'm not sure what you want to do. Actually.
16:43stuart_kotarak: Let me rephrase. :-) I don't want determinism. I want each integer to be doled out exactly once.
16:43ChouserFor what it's worth, I think your code is correct.
16:44kotarakstuart_: this will also work with commute. One thread gets 0, one 2, one 3 and one 4.
16:44Chouserkotarak: I hadn't thought about the difference in the return values of alter and commute -- I think you want alter in this case.
16:44kotarakoops: 0, 1, 2, 3 of course
16:44stuart_Chouser: with alter, or with commute?
16:44Chouserkotarak: oh, sorry -- addressing the wrong person. :-)
16:45kotarakChouser: :) np
16:45Chouserstuart_: I think alter will work. From the docs, I think commute may give you a different value in-transaction than what gets committed.
16:45stuart_Chouser: That's what I have convinced myself too. From the docs, commute sets the value at end-of-transaction to (apply fun most-recently-committed-value-of-ref args)
16:46Chouserstuart_: it's not obvious that the return value from the dosync would be the in-transaction value, but that's my guess.
16:46kotarakOk. I don't have a clue what's the use of commute then....
16:46stuart_Chouser: my reasoning exactly.
16:46stuart_kotarak: Commute is useful when you don't care about the intermediate states, only what's there at the end.
16:46ChouserI think commute is good for, say, assoc'ing on a hash map.
16:47stuart_Look how commute is used in the contribs
16:47kotarakOk. When I don't want to look at the value of the ref.
16:47stuart_load-one uses commute to manage namespaces.
16:47Chouseryou do your assoc, and you can look at the map and see it's there. some other thread may be doing the same thing, seeing its own version. At commit time they happen in whatever order and your map ends up with both values.
16:48kotarak... in case the keys are different
16:48stuart_I take it this IRC is not logged? I am going to grab a little bit of this conversation and post over on the mailing list.
16:48kotarakit is logged.
16:48stuart_kotarak: thanks
16:48Chouserkotarak: yes!! in the case of different keys. good point.
16:49kotarakChouser: so assoc doesn't really commute.
16:49Chouserstuart_: http://clojure-log.n01se.net/ -- log
16:49Chouserkotarak: assoc on maps don't commute in all cases. assoc on a set would though, right?
16:50kotarakSince there is no value (resp. key == value) I would think so, yes
16:50Chouserso just modify my example above to "set". :-)
16:50kotarak:)
16:51kotarakBut the counter does not work? Because two threads can get the same counter value.
16:51ChouserI think by using alter instead of commute, the counter should work.
16:52kotarakIs the rerun on conflict?
16:52kotarakthe code
16:53Chouseryes
16:53kotarakSo one better doesn't not do too complicated things in a transaction, I presume.
16:56Chousercomplicated sure, if necessary. But better not have side-effects.
16:57kotarakAnd no long-winded computations. Otherwise you may get a conflict and have to the computation again. So transactions should probably kept concise.
16:57Chouserok, this is fun:
16:57Chouser(def c (ref -1)
16:57Chouser(defn fast [] (dosync (prn :fast-from @c) (alter c inc)))
16:58ChouserNote the evil prn side-effect inside dosync. For testing only. :-)
16:58Chouser(defn slow [] (dosync (prn :slow-from @c) (Thread/sleep 2000) (alter c inc)))
16:59ChouserNow you run (slow) in another thread: (send-off (agent nil) (fn [_] (slow)))
17:00Chouseryou immediately see the :slow-from 0, but now you can run a few (fast)'s and watch as slow re-tries as needed to get through.
17:00Chouserand using alter, each int is being returned exactly once.
17:19stuart_Chouser: didn't Rich say something on the mailing list about prn behavior being ill-defined inside dosync?
17:24Chouserwell, it can be re-run, so you'll see it extra times. You don't want it for real code, hence the use of the word "evil" above.
17:34stuart_Chouser: I am afraid that even in debugging code, printing might not obey the transactional semantics
17:35stuart_So you might come to a conclusion about how Txs work that is really just an artifact of how print works
17:35Chouserit's the @ that's doing transactional stuff. But I guess you're right that it would be unwise to trust the results too much.
17:36ChouserAnyway, you can observe the return values from (slow) and (fast) above, which is valid. The prn's inside dosync are just to give a sense of when slow's dosync is re-running its transaction.