#clojure log - Jul 23 2008

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

2:13 Chouser: I can't think of how to use any of the existing persistent structures as a queue efficiently.

2:14 a subvec keeps a reference to the original vector, right? Otherwise it'd be perfect.

2:17 Yep, SubVector has the original vector, a start index, and an end index.

2:19 So how can I let dequeued items be GC'ed without mutating or copying the whole queue?

10:02 meredydd: Out of interest, is there a Clojure-idiomatic HTTP client library about the place, for playing with RESTish stuff?

10:22 cemerick: it seems that in-ns doesn't have any effect within a do block, i.e. (do (in-ns 'blah) (def name 5)) throws: java.lang.Exception: Name conflict, can't def name because namespace: user refers to:#'clojure/name

10:23 The same thing happens if I use binding to set *ns* for the scope that the def is in. What am I missing here?

10:35 Chouser: cemerick: I wonder if the name is resolved compile time, such that you need to drop back up to the top level before any changes to *ns* take effect?

10:36 It's not clear to me why you can't use fully-qualified names in def.

10:36 cemerick: Chouser: Yeah, that's what I figured.

10:37 That would be nice.

10:40 The big fallout from the way those names are resolved is that you can't fiddle with any other namespace, short of evaling defs, etc.

10:41 Chouser: maybe that's the point. still, it doesn't really protect much since any file can drop into any namespace and start def'ing

10:43 cemerick: yeah, it only limits certain macros

10:43 Chouser: oh, I see. yeah, good point.

10:45 cemerick: allowing fully-qualified names in def is the maximally-effective solution. There may well be an implementation detail that makes that undesirable.

10:47 Chouser: the errors you get appear to be very specific, as if rhickey considered that option and explicitly rejected it

10:47 I don't think I've read an explanation anywhere though.

10:47 cemerick: we can tag-team him when he returns ;-)

12:11 is this the only way to get a reference to the class for Object[] (for example): (. Class (forName "[Ljava.lang.Object;")) ?

12:44 Chouser: (class (to-array []))

12:44 yours might be better, but there's another option anyway.

12:46 (class (into-array [0])) ==> class [Ljava.lang.Integer;

13:22 nchubrich: Hi, has anyone encountered problems using JLine with clojure?

13:22 Specifically, I followed all the instructions on the group:

13:22 java -cp jline-0.9.94.jar:clojure.jar jline.ConsoleRunner clojure.lang.Repl

13:23 in the directory with both jars:

13:23 CPL.TXT changes.txt jline-0.9.94.jar readme.txt target

13:23 build.xml clojure.jar pom.xml src

13:24 and get:

13:24 Exception in thread "main" java.lang.ClassNotFoundException: clojure.lang.Repl

13:27 Chouser: nchubrich: sorry, I don't know. I use rlwrap instead of jline

13:28 rhickey: have you explained somewhere why (def my-ns/foo) is disallowed?

13:29 nchubrich: Yes, rlwrap definitely works better; but for some reason JLine works better with Emacs

13:29 (I have a friend who got it on his system, but for some reason doesn't work on mine.)

13:32 fyuryu: nchubrich: you have svn version of Clojure?

13:33 rhickey: Chouser: there isn't a firm position there, mostly denied conservatively. One issue would be, locality of namespace definition - if anyone can inject into a namespace from any other it will be difficult for tools

13:33 nchubrich: I don't think so, but it's build 20080612

13:33 fyuryu: nchubrich: I remember having some problems with jline, but that was some time ago, it works now

13:34 Chouser: ok. cemerick was apparently trying to do something in a ns via a macro, but I'm not sure what.

13:34 nchubrich: fyuryu, do you think SVNing it would help for some reason?

13:35 fyuryu: nchubrich: yeah, that date sounds about right, try the svn version

13:35 nchubrich: I haven't put jline.jar in my system-wide extensions library; that seemed to cause problems so the group said.

13:36 rhickey: Chouser: you were looking for a queue? You could try clojure.lang.PerisistentQueue

13:37 * Chouser blinks. oh. Yes, I'll look at that.

13:37 fyuryu: nchubrich: I have jline in the same directory as clojure.jar. And use the scripts from the wiki

13:43 nchubrich: thanks for your help fyuryu, I'm going to try SVN....

13:49 cemerick: rhickey: what Chouser was referring to was a situation where a macro was looking to use gen-and-load-class, and also populate the necessary namespace that the gen-class'ed class would look in for method impls. Short of requiring the macro to be used from within the class namespace, the macro would either need to be able to def fully-qualified names, or be able to use in-ns in a try/finally so as to restore *ns* after populating the namespace.

13:52 rhickey: cemerick: you mean (bind [*ns* blah] ...) ?

13:56 cemerick: rhickey: I tried that; doesn't appear to work: (binding [*ns* (find-ns 'blah)] (def foo 5)) => #'user/foo

13:56 maybe I'm missing something...?

13:57 Chouser: Is (conj (clojure.lang.PersistentQueue/EMPTY) ...) the Right Way to create one?

13:57 cemerick: (FWIW, namespace 'blah does already exist)

13:58 rhickey: you're not, that won't work because all the names involved are resolved at compile-time but the binding happens at run time, and is a common error

13:59 gen-class et al are a good example of where one ns is defining another

14:00 cemerick: Yeah, I see why that doesn't work; I could eval all of the defs, but that's pretty irritating.

14:01 rhickey: cemerick: but aren't you in a macro?

14:02 cemerick: rhickey: yes; its forms are still subject to *ns*, though, right? Perhaps my macro-fu is weak.

14:02 rhickey: Chouser: yes, then you can use the conj/pop protocol

14:02 Chouser: rhickey: ok, thanks.

14:02 * rhickey needs to expose queue

14:03 Chouser: it's count appears to including counting a seq -- not constant time?

14:03 its

14:05 rhickey: Chouser: no, many seqs have constant-time count, including vector's

14:07 cemerick: yeah being in a macro doesn't help

14:08 cemerick: rhickey: ok, glad I'm not losing it

14:09 rhickey: FWIW, I've got a first pass of a 'defbean' macro working that does what we discussed last night, but it's less than ideal. Having to coordinate the namespaced impl. as well as ensure that the class in question isn't loaded twice makes for a hairy mess, really.

14:09 rhickey: cemerick: does defbean generate a bean on disk or immediately loaded?

14:10 cemerick: rhickey: right now, it's immediately loaded. We have a build process and such that coordinates where and when gen-class stuff is saved off, but I've been trying to not use that so defbean could be generally applicable.

14:11 rhickey: cemerick: who could consume the named members of such a bean (unless there is an interface defining them)?

14:12 cemerick: Looking back over our use-cases this morning, always having a Java interface for each entity we're interested in is common, so I may just downshift into using proxy to build the PSM subclass off of a given interface.

14:13 rhickey: cemerick: for dynamic beans that's all that makes sense to me

14:13 cemerick: rhickey: no one, unless we're saving the classes

14:15 I'll have to go over our models and see whether simply referring to a concrete, gen-class'ed impl is something that would be beneficial. It's certainly irritating to have to have a pile of interfaces for every entity (compared to having the option of having them pop out concretely from clojure).

14:16 rhickey: cemerick: or do you want gen-interface?

14:16 cemerick: rhickey: I've *always* wanted gen-interface :-)

14:16 rhickey: cemerick: what were the loaded-twice issues?

14:17 cemerick: rhickey: Nothing super-complex -- the jvm would just throw a duplicate class def exception after a second eval of the defbean macro. Fixed with a check for the class that defbean emits via gen-class.

14:18 rhickey: FWIW, what I really want is a gen-class that carries method impl's around with it, a la proxy.

14:18 I know that opens up a whole other can of worms, tho.

14:19 rhickey: cemerick: but does defbean allow a change in signature, i.e. adding methods? if so people will expect it to be able to be run more than once

14:20 cemerick: rhickey: No. Another vote for either using proxy, or always saving the generated class.

14:22 rhickey: gen-and-load-class is very limited, because Java is limited in supporting static class names + dynamic signatures

14:24 cemerick: as I said to Chouser, the prohibition on defs of explicitly-qualified names is conservatism on my part

14:25 Chouser: consider yourself tag-teamed.

14:25 cemerick: Chouser: :-P

14:26 rhickey: one issue is the fact that all of the names in any such definition will be resolved in *ns*, not the ns of the def'ed var

14:26 cemerick: rhickey: Given some of the example code I've seen on the group of late, I don't blame you at all. I do think there has to be some mechanism for safely def-ing fully-qualified names, though.

14:27 maybe have a *def-ns* that we can bind, so that def-ed symbols are resolved there, but all others are resolved in *ns*?

14:28 rhickey: cemerick: still very confusing, for me too

14:28 cemerick: That feels over-complicated, though

14:28 * cemerick is searching for the middle ground :-)

14:31 Chouser: I would be very surprised if *ns* was 'user and (def foo/bar baz) was refering to any baz other than user/baz

14:31 rhickey: cemerick: want to past defbean so I can see what you are up against?

14:32 Chouser: what about (def foo/bar bar) ?

14:33 Chouser: I really wouldn't expect any fully-qualified name to early in an expression to change the ns used by later symbols.

14:33 now if it was (def-in-ns foo bar bar) ... then I would start to wonder.

14:34 rhickey: Chouser: (defn foo/bar [] .... (bar))

14:35 Chouser: yeah, I would expect to have to say (foo/bar), though I'm sure that would be a common mistake.

14:35 rhickey: Chouser: I'm not disagreeing, just highlighting what are likely to be the points of confusion

14:36 cemerick: rhickey: Yeah, I'll paste it in 5 min. It's a pretty ugly baby. :-)

14:36 Chouser: maybe not as common as forgetting to (refer 'clojure) after my (in-ns ...), but still common.

14:37 cemerick: IMO, def-ing a fully-qualified name is definitely an edge case -- I wouldn't expect it to be available by default. This is how I came to my *def-ns* suggestion.

14:40 Chouser: this would be a possible solution for the gen-class namespace pollution as well.

14:40 as opposed to method function-name mangling.

14:40 rhickey: Chouser: how so?

14:42 Chouser: if I genclass namespace fooclass, instead of then wanting to do (in-ns 'fooclass) (refer 'clojure), I could stay in my 'user ns (or where-ever) and do (defn fooclass/methname1 ...)

14:43 did that make any sense?

14:44 rhickey: Chouser: except it's not fooclass, it's com.company.package.Classname, and there's no ns in which to alias it!

14:45 Chouser: why couldn't I alias it? but even without that, I'd rather use a long name for each method def, than sprinkle clojure/ all through my code.

14:46 granted mangling each method name with a leading . would be nicer than either. :-)

14:46 rhickey: Chouser: your straw man was function name mangling, which wouldn't require that

14:47 Chouser: also, you'd have to qualify all helper fns etc

14:47 Chouser: I didn't mean to claim fully-qualified def was better than mangling, just that it could also solve the problem.

14:47 indeed.

14:47 lisppaste8: cemerick pasted "defbean first cut" at http://paste.lisp.org/display/64107

14:49 cemerick: rhickey: so, it's a bit of a mess at the moment, but there are enough issues that I think it's worth not pursuing with the current state of things (in favor of an interface/proxy impl)

14:50 (it's also possible that I've made a hash of it)

14:54 rhickey: cemerick: so it create a class with the same name as *ns*?

14:54 cemerick: rhickey: yes; it seemed like the only reasonable approach given the fully-qualified def issue

14:55 rhickey: right, just trying to understand

14:55 you'd have preferred taking a class name too?

14:57 cemerick: well, that's not really settled yet -- I've seen a lot of code around that keeps all of the gen-class stuff in one file, in one namespace, and our approach is to put any gen-class in its own -gen.clj file (which makes the build process identify what generates classfiles, and what just needs to be loaded as a sanity check and to see about reflection warnings). Providing a classname to defbean certainly makes it clearer what's going on under the covers.

14:59 kotarak: is there a way to use apply with . besides (eval `(. ~obj foo ~@args))?

15:02 rhickey: kotarak: (defn jcall [obj name & args]

15:02 (clojure.lang.Reflector.invokeInstanceMethod

15:02 obj

15:02 (str name)

15:02 (if args (to-array args) (clojure.lang.RT.EMPTY_ARRAY))))

15:02 (defn jfn [name]

15:02 #(apply jcall %1 name %&))

15:03 kotarak: wow. thanks :)

15:44 rhickey: so who's gonna write the macro's to gen gxp? http://code.google.com/p/gxp/

15:49 cemerick: rhickey: since we have Class/field access (i.e. Math/PI), can we reclaim '.' so that it invokes methods on java.lang.Class? i.e. this doesn't work (.getMethods String)

15:55 Chouser: Compile-time type checking, lightweight runtime system -- is this a template or programming language?

16:17 rhickey: cemerick: (macroexpand '(Math/random))

16:18 Chouser: it's your typical server pages thing except:

16:18 it's functional

16:18 it's compiled

16:19 the resulting compiled classes can be consumed from Java/Clojure

16:19 cemerick: rhickey: OK, I deserved that :-)

16:21 however, I'm confused in general. (.getName String) => Exception, and (.getName (class String)) => "java.lang.Class"

16:21 rhickey: cemerick: just wanted to show it is still not syntax, just a transformation. Making it first class could complicate code walkers etc, which for now can just call macroexpand and get the canonic form. I agree, (. classname static-member) is not otherwise preferable in any way to classname/static-member

16:22 . has special evaluation rules, if its first argument looks like a classname, it's considered a static call

16:22 (. String getName) - static call to getName method on String (doesn't exist, error)

16:23 (. (class String) getName) -> the class of the String class object is Class

16:23 cemerick: heh, this works: (defn foo [c] (.getName c)) (foo String)

16:24 yeah, I see what was going on there, I was just assuming that there was something more complicated going on

16:28 rhickey: (. classname member) predated class object literals, but the fundamental problem is Java's, which uses class names as scopes - I guess I could force everyone to use String.class to name the class object, like Java does

16:29 (just kidding)

16:30 cemerick: but only a little, right? :-)

16:30 rhickey: cemerick: that's how it started out, no class literals, and (class String) meant String.class

16:31 cemerick: yeah, I was mostly winking towards the "it's Java's fault"

16:31 rhickey: now (class String) means (.getClass String) and String means String.class

16:31 oh, it's definitely Java's fault

16:31 :)

16:32 cemerick: :-)

16:32 rhickey: I've been meaning to ask you about future generics plans (if any)...

16:34 rhickey: cemerick: my plan is to pray they never move away from type erasure for generics. Without it lots of Clojure's interop would be horribly type-burdened. This was a major factor for me in dropping .Net. Generics are bad for dynamic languages, after all, they are only about types.

16:38 cemerick: I've spent some not-inconsiderable amount of time in scala-land, so I'm not averse to types (and like them on occasion). I wouldn't mind eventually seeing a dynamic-friendly type system in clojure (perhaps implemented as a plugin for a future componentized clojure compiler). I'm obviously not asking you for this, though.

16:54 rhickey: cemerick: I'm not likely to settle for types - I just don't think they give the required benefits. If you look at something like the PLT contracts, Eiffel pre/post conditions, predicate dispatch, Qi's superimposable sequent-calculus based system etc, there are some cool ideas.

16:55 I am in favor of programmers being able to assert things about their code and the compiler/runtime system assisting them.

20:24 I've added validators for vars/refs/agents - an optional second arg for agent and ref, get/set-validator, also shutdown-agents

Logging service provided by n01se.net