#clojure log - Aug 18 2008

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

4:10 rhickey_: I'll be traveling this week, checking in sporadically

9:58 blackdog: when using gen-and-load-class how do i specify a method returning void, if i miss it out i get a compilation error

9:59 :methods [

9:59 ['monitorSubscribe [Client Message] <what's here?>]

10:03 Chouser: try Void/TYPE

10:03 blackdog: ah thanks

10:05 yes, that works

10:06 Chouser: great

10:52 drewr: Anybody know if JDBC takes some sort of Java collection for an IN operator?

10:52 Chouser: you mean as opposed to a string?

10:53 drewr: For a prepared statement. Like, "SELECT ... WHERE foo IN ?".

10:53 Then supplying an array for the parameter.

10:54 My initial tests say "no" but I wasn't sure if I was at fault.

10:54 Chouser: an array works but other collections don't? (clearly it's not likely I'll be able to help you. ;-)

10:55 drewr: No, arrays don't work. I think I'll just have to build up a string manually.

10:55 Chouser: ah. ick.

10:55 drewr: Clojure makes it bearable at least. :-)

10:56 blackdog: what's the quickest way of converting a clojure map to a java Map, i thought the clojure collections implemented the collection interfaces?

10:56 but it doesn't seem like i can pass a clojure map to a java function

10:56 Chouser: drewr: did you try foo.setArray() ?

10:58 drewr: http://java.sun.com/j2se/1.4.2/docs/api/java/sql/PreparedStatement.html#setArray(int, java.sql.Array)

10:58 drewr: Chouser: Ah, no. Didn't catch that in the docs.

10:58 Chouser: Well, I'm not sure it's right, but it looks like your best shot.

10:58 drewr: Yep, thanks.

11:08 Chouser: blackdog: yeah, I'm not sure. Looking at the Clojure collections code I don't see them implementing many Java collection interfaces.

11:08 Maybe just Collection.

11:10 blackdog: ok, thanks Chouser, I have a little funciton to do it anyway, but I thought there had to be something better :)

11:11 given there's into-array etc

11:13 Chouser: right. I'm a little surprised that PersistentMap doesn't implement Map -- it seems like it could.

11:14 I wonder if I'm missing something

11:14 blackdog: oh. Well, I wrote one for you too. ;-)

11:14 (defn to-map [pm] (let [m (java.util.HashMap.)] (doseq [k v] pm (.put m k v)) m))

11:15 blackdog: good enuff :)

11:18 Chouser: ah, this is nice: (supers (class {}))

11:19 so, no Map

11:20 though you do get Comparator, Serializable, and Collection

11:21 blackdog: yes, that's very useful

11:22 Chouser: hm, the Java Maps implement Map but not Collection. Clojure's Maps implement Collection but not Map. I wonder if that's on purpose.

11:27 achim_p: Chouser: 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:28 your example cetrainly seems easier, but the whole map is being copied, as i understand it, right?

11:29 Chouser: achim_p: that's right -- mine is a copy. yours looks pretty good.

11:29 makes me wonder even more if PersistentMap intentionally doesn't implement Map or if it's just an oversight.

11:30 I think P-Maps use java.util.MapEntry -- do you really have to wrap them as well for entrySet?

11:32 achim_p: hmm, probably not ... didn't know they already were MapEntries

11:35 Chouser: (class (first {:a 1}) ==> clojure.lang.MapEntry

11:35 so that's not quite right...

11:35 achim_p: also shouldn't hava called the arg "map", this is really confusing :)

11:40 Chouser: heh, yeah, it's pretty easy to shadow builtin function names. "list" is another one I have to tiptoe around.

12:09 cemerick: Chouser: 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:10 Chouser: cemerick: ah, now that you mention it, that does sound familiar.

12:10 cemerick: I've been away for a while -- has there been any discussion of AOT compiling of late?

12:10 Chouser: Not that I know of.

12:11 It was mentioned in passing on the group, but not in any way that would be helpful.

12:13 cemerick: we'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:13 Chouser: surely lisp isn't that had to obfuscate. Most of my code starts halfway there...

12:14 cemerick: :-) No, not hard at all. It's a little more complicated in Clojure, simply because you need to be careful of Java names.

12:14 Chouser: Here's that thread you mentioned. Thanks. http://groups.google.com/group/clojure/browse_thread/thread/64ae146a856e2291

12:16 dhaya: Chouser, A more detailed thread on the same topic here. http://clojure-log.n01se.net/date/2008-07-18.html

12:18 Chouser: dhaya: thanks

12:19 cemerick: 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:19 I wouldn't hold my breath. :-)

12:20 cemerick: Chouser: Yeah, I found that mention, too.

12:21 He'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:51 kotarak: hmmm. How can I load a file (with absolute path) on Windows with load-file? (load-file "C:\\Foo\\bar.clj") throws an exception.

13:56 Chouser: try forward slashes?

13:56 shoover: Hmm, the \\ syntax is working for me

13:56 Chouser: that's a blind guess -- I don't have easy access to a Windows Clojure at the moment.

13:57 kotarak: Hmmm.. maybe something else was messed. I have to check tomorrow. (Have only Win access at work)

13:57 shoover: yep. will try again.

13:57 shoover: Actually both slash styles work for me

16:27 stuart_: Hi all! dosync query. Is this the most idiomatic way to create a thread-safe counter in Clojure: http://pastie.org/255201?

16:27 Compare with, e.g. a JRuby version: http://pastie.org/255134

16:28 kotarak: you could use commute instead of alter

16:28 stuart_: with commute, couldn't two callers get the same value?

16:29 kotarak: no, 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:31 stuart_: 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:32 kotarak: probably. I have not much experience with concurrency.

16:36 stuart_: 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:39 stuart_: 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:39 Chouser: kotarak: you might just use http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic/AtomicInteger.html

16:40 stuart_: Chouser: Good point!

16:41 kotarak: stuart_: then you probably don't want a ref, but some other means of syncronisation? Which is more deterministic.

16:41 stuart_: 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:42 kotarak: Doesn't that just put me back to alter?

16:42 kotarak: stuart_: I'm not sure what you want to do. Actually.

16:43 stuart_: kotarak: Let me rephrase. :-) I don't want determinism. I want each integer to be doled out exactly once.

16:43 Chouser: For what it's worth, I think your code is correct.

16:44 kotarak: stuart_: this will also work with commute. One thread gets 0, one 2, one 3 and one 4.

16:44 Chouser: kotarak: I hadn't thought about the difference in the return values of alter and commute -- I think you want alter in this case.

16:44 kotarak: oops: 0, 1, 2, 3 of course

16:44 stuart_: Chouser: with alter, or with commute?

16:44 Chouser: kotarak: oh, sorry -- addressing the wrong person. :-)

16:45 kotarak: Chouser: :) np

16:45 Chouser: stuart_: I think alter will work. From the docs, I think commute may give you a different value in-transaction than what gets committed.

16:45 stuart_: 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:46 Chouser: stuart_: it's not obvious that the return value from the dosync would be the in-transaction value, but that's my guess.

16:46 kotarak: Ok. I don't have a clue what's the use of commute then....

16:46 stuart_: Chouser: my reasoning exactly.

16:46 kotarak: Commute is useful when you don't care about the intermediate states, only what's there at the end.

16:46 Chouser: I think commute is good for, say, assoc'ing on a hash map.

16:47 stuart_: Look how commute is used in the contribs

16:47 kotarak: Ok. When I don't want to look at the value of the ref.

16:47 stuart_: load-one uses commute to manage namespaces.

16:47 Chouser: you 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:48 kotarak: ... in case the keys are different

16:48 stuart_: 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:48 kotarak: it is logged.

16:48 stuart_: kotarak: thanks

16:48 Chouser: kotarak: yes!! in the case of different keys. good point.

16:49 kotarak: Chouser: so assoc doesn't really commute.

16:49 Chouser: stuart_: http://clojure-log.n01se.net/ -- log

16:49 kotarak: assoc on maps don't commute in all cases. assoc on a set would though, right?

16:50 kotarak: Since there is no value (resp. key == value) I would think so, yes

16:50 Chouser: so just modify my example above to "set". :-)

16:50 kotarak: :)

16:51 But the counter does not work? Because two threads can get the same counter value.

16:51 Chouser: I think by using alter instead of commute, the counter should work.

16:52 kotarak: Is the rerun on conflict?

16:52 the code

16:53 Chouser: yes

16:53 kotarak: So one better doesn't not do too complicated things in a transaction, I presume.

16:56 Chouser: complicated sure, if necessary. But better not have side-effects.

16:57 kotarak: And no long-winded computations. Otherwise you may get a conflict and have to the computation again. So transactions should probably kept concise.

16:57 Chouser: ok, this is fun:

16:57 (def c (ref -1)

16:57 (defn fast [] (dosync (prn :fast-from @c) (alter c inc)))

16:58 Note the evil prn side-effect inside dosync. For testing only. :-)

16:58 (defn slow [] (dosync (prn :slow-from @c) (Thread/sleep 2000) (alter c inc)))

16:59 Now you run (slow) in another thread: (send-off (agent nil) (fn [_] (slow)))

17:00 you 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:00 and using alter, each int is being returned exactly once.

17:19 stuart_: Chouser: didn't Rich say something on the mailing list about prn behavior being ill-defined inside dosync?

17:24 Chouser: well, 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:34 stuart_: Chouser: I am afraid that even in debugging code, printing might not obey the transactional semantics

17:35 So you might come to a conclusion about how Txs work that is really just an artifact of how print works

17:35 Chouser: it'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:36 Anyway, 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.

Logging service provided by n01se.net