#clojure log - Sep 02 2008

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

7:50 parth_m: Hello

7:52 If I am to write a print-decorator http://groups.google.com/group/clojure/msg/cb7a45124bbf92f5 what would be a good way to get the name of the function being decorated at runtime?

7:53 In the method suggested, having to switch namespaces seems a little weird.

7:53 If I don't switch ns, there is stack overflow.

8:01 hoeck: parth_m: why not just taking the functions classname at runtime?

8:02 parth_m: hoeck: as (class f)?

8:03 This works, actually just a print also works but it shows the compiled form .. e.g user.foo__2372@5388b5

8:03 I was wondering if I can get "foo"

8:03 hoeck: of course, with some string and regex matching

8:04 and it has the advantage of working with (named) anonymous functions (which i use very often) :)

8:05 parth_m: Yes .. I could do that.

8:05 I am not too clear on using meta data. I know the info exists ... just not sure how to get it.

8:05 user=> (meta (var foo))

8:05 {:arglists ([]), :file "NO_SOURCE_FILE", :line 9, :ns #<Namespace: user>, :name foo}

8:06 So, "foo" is definitely there somewhere ... but in the decorator scenario it doesn't seem to work. Throws an exception: http://groups.google.com/group/clojure/msg/91b028c63ec440d6

8:10 Its not a big thing ... I was just wondering in case there is a idiomatic way of doing this.

8:11 hoeck: mhh, aren't vars resolved at compile-time?

8:12 parth_m: I suppose so.

8:14 But if we pass "foo" to "print-decorate" isn't the meta-data attached to "foo"? This may be a silly question but I still don't understand clojure meta-data fully.

8:15 hoeck: no, metadata is only attached to vars and a few clojure data-structures

8:16 parth_m: Ah. I think I get it now. So what gets passed is a function ... so there is no metadata attached. Right?

8:17 hoeck: yes, the metadata you create with defn gets only attached to the var holding the function object

8:18 but the AFn Class actually has a withMeta method, but it throws an unsupported operation exception, so in theory, you could attach metadata to functions too

8:19 parth_m: Having metadata with functions would be nice ... I suppose that needs to fit into the overall introspection picture.

8:20 Thanks hoeck. I understand this much better now.

8:20 So when we do #'foo its a var. and just 'foo' is a function being passed.

8:25 hoeck: yeah, #'foo is a shortcut for (var foo), and foo evaluates to the value of foo (in this case a function)

8:26 parth_m: Common Lisp had me confused ... I thought #'foo was a function as with CL :)

8:26 Thanks hoeck. Will use the class for now.

8:27 hoeck: me too, but clojure has only one namespace for functions and values, which I find pretty handy btw

8:28 parth_m: I agree. Its much nicer to say (map foo ..) rather than (map #'foo ..)

9:23 cemerick: rhickey: it turns out that the NB profiler chokes on clojure in general (though your genclass patch stops it from tossing a hard error); the process being profiled "hangs" (for lack of a better term) as soon as clojure.lang.RT is statically referenced.

9:24 rhickey: cemerick: that's bad, last time I tried it it ran no problem but only profiled the Java bits of Clojure

9:24 cemerick: I see you got the 18-arg patch

9:25 cemerick: yeah I did; so, you set up the profiler to instrument only clojure.lang.*?

9:26 rhickey: I don't remember too well, but I think I asked for everything but standard Java libs, got only Java calls

9:27 cemerick: FWIW, dumping profiling data via -hprof options works just fine (which I load up in hpjmeter) -- crude, but effective.

9:31 rhickey: soneone suggested JiP at one point: http://jiprof.sourceforge.net/

9:31 someone

10:11 cemerick: rhickey: thanks for the link; I think I'll try yourkit next, just to see if NB is the problem, or if clojure/asm/whatever is somehow at odds with JVMPI itself.

11:42 yourkit profiles the same NB project without a problem; however, a super-small project I put together that contains only clojure.jar and a main class that references clojure.lang.RT is successfully profiled by NB....so, now I'm pretty confused.

15:13 lisppaste8: jamii pasted "qt-repl" at http://paste.lisp.org/display/66213

16:19 jgracin: rhickey, hi! how come there are no tests in Clojure's implementation?

16:19 I'm obviously asking about your opinion on automatic testing. :-)

16:32 rhickey: jgracin: no one's written any yet

16:32 abrooks_: Heh.

16:33 rhickey: a test suite would be a welcome contribution

16:35 Chouser: people have talked some about how a test suite would be structured. It'll happen eventually.

16:36 rhickey: until then I'll just keep trying to get it right the first time :)

16:40 jgracin: rhickey, nice strategy. :-)

17:36 lisppaste8: jamii pasted "qt repl and slots in action" at http://paste.lisp.org/display/66224

17:44 jamii: How do I create instances of generic classes?

17:44 eg Signal1<Object>

17:44 Chouser: ignore the generic part

17:44 so, just Signal1

17:44 jamii: Hmmm. Qt might not like that. Ill give it a try

17:51 How do I use a nested class? I would have thought (import '(com.trolltech.qt.QSignalEmitter Signal0)) would work

17:52 kotarak: Try QSignalEmitter$Signal0

17:53 jamii: Yep, that worked.

17:53 Is the $ specific to imports?

17:53 kotarak: No, it's for nested classes.

17:53 jamii: Ok. Cheers

18:11 Damn, I wish new wasnt a macro.

18:14 kotarak: It's not. It's a special form, AFAIK. What do you want to do?

18:18 jamii: kotorak: I need to create one of Signal0 to Signal10 depending on the argument number

18:19 something like: (defn signal [n] (new (sym "Signal" (str n))))

18:20 I dont think its possible with new though. Is there another primitive for constructing objects?

18:20 kotarak: Not that I am aware of...

18:21 jamii: Oh well. cond it is then

18:21 kotarak: You could resolve to ugly anti-features:

18:21 (let [c TheClassYouNeed] (eval `(new ~c)))

18:23 jamii: That'll do. It doesnt have to be pretty

18:23 kotarak: cond is probably the better solution. Also not pretty, but one has a good conscience.

19:42 Chouser: is it any prettier to do the evals up front?

19:43 jamii: Is there a way to add java fields to a class using proxy? Signals can only appear as a field of a subclass of QSignalEmitter. Which is a little annoying. I've been trying to do this using gen-and-load-class but the :state option is causing problems

19:43 Chouser: (def sigs (vec (for [i (range 10)] (eval `(fn [] (new ~(symbol (str "Signal" i))))))))

19:44 jamii: Chouser: Im using almost exactly that code :-)

19:44 Chouser: jamii: no, you'll have to use gen-class to add a field.

19:44 jamii: So i need to use :state and :init

19:45 How does the scoping work in :init - it keeps complaining that my init function isnt defined

19:45 This is what I have at the moment:

19:45 (defn- make-signal-holder [n]

19:45 (gen-and-load-class

19:45 (symbol (str "slot.SignalHolder" n))

19:45 :extends QSignalEmitter

19:45 :constructors {[(eval (symbol (str "QSignalEmitter$Signal" n)))] []}

19:45 :init 'signal-holder-init

19:45 :state 'signal))

19:46 Chouser: you're running the last release, or latest SVN?

19:46 jamii: Somewhere in between... svn 1-2 weeks old

19:47 Chouser: ok, your defn probably needs to use the name SignalHolder-signal-holder-init

19:49 rhickey: jamii: for no-arg dynamic new - (.newInstance (Class/forName str))

19:49 jamii: rhickey: Thanks

19:52 Hang on, that needs to be (.. (Class/forName str) (getConstructor types) (newInstance))

19:53 rhickey: jamii: are there args? your examples didn't have any

19:54 jamii: Sorry. The examples didnt have any because the jambi docs are wrong. There is in fact a single mystery arg

19:55 rhickey: (clojure.lang.Reflector/invokeConstructor (Class/forName str) (to-array args))

19:56 jamii: cool

19:57 rhickey: better still, use RT.classForName which will leverage Clojure's classpath stuff

19:59 (resolve (symbol "java.util.ArrayList")) is another way to look at it

20:06 jamii: It seems that jambi is not fooled by gen-and-load-class: "java.lang.RuntimeException: Signals must be declared as members of QSignalEmitter subclasses"

20:06 rhickey: jamii: are you extending that class?

20:07 jamii: Yes

20:07 And putting the signal in the :state slot

20:09 google has nothing. Does :state produce a real field. Maybe I should try a property instead

20:10 rhickey: http://doc.troll.no/qtjambi-4.3.4_01/doc/html/com/trolltech/qt/qtjambi-signalsandslots.html says: All normal member methods can be used as slots, so there are no specific requirements for a method to function as a slot.

20:11 jamii: Signals and slots are not the same. I've managed to wrap clojure functions as slots quite easily. The trouble is that new signals have to be created as members of a QSignalEmitter

20:18 rhickey: jamii: :state does produce a public final field of type Object.

20:19 but it seems like you can define accessor methods for signals, rather than use fields, as implied by "It is customary to declare signals as public rather than to provide access methods for them."

20:20 jamii: I'll try using :exposes

20:21 rhickey: jamii: that's just for exposing an existing protected field of a superclass

20:21 jamii: Damn

20:31 Chouser: does final mean everything inside that object will be immutable, or is it just that the top-level value of that field cannot change?

20:36 rhickey: Chouser: the latter

21:09 jamii: To import a java file in clojure do I have to do anything beyond compile it and set the classpath?

21:18 shoover: jamii: That should do it. If the file is compiled to a .class, put the directory on the classpath. If the .class is part of a jar, put the jar on the classpath.

21:20 jamii: Ok, i probably have a typo buried deep in the folder hierarchy

21:34 rhickey: Turns out signals have to be declared inside the scope of the QSignalEmitter subclass. Dropping into java seems to be the way forward

21:34 s/declared/instantiated

21:35 public Signal0 signal = new Signal0(); is the single only way it will be accepted

22:05 Chouser: no way to get to "this" from the init function?

22:27 wouldn't matter anyway -- Qt's using getDeclaredFields to poke through the Emitter's parentage looking for a matching Signal member.

22:43 jamii: Chouser: I have it sort of working. It gives me an exception the first time I use a signal and works fine thereafter. I'm tempted to just have the wrapper force and catch that first exception before returning the signal. A little hacky though

22:43 Chouser: hm...

22:47 that's with Java code for the signals?

22:48 jamii: I hava a java class that looks like:

22:48 public static class QField extends QObject {

22:48 public QField() {

22:48 super();

22:48 }


22:48 public Object field;

22:48 }

22:49 Because I couldnt figure out how to do fields properly from withing clojure

22:49 Then I set! field with a new signal. The mystery arg in the signal turned out to be because they're non-static inner classes - they need an instance of their container class which in this case is QField

23:03 svn ~2 weeks out of date

23:04 oops

23:12 java.lang.RuntimeException: Signal initialization failed

23:12 Thats a new on

23:12 *one

23:15 Chouser: All signals are failing on the first emit with "Signals must be declared as members of QSignalEmitter subclasses". Zero arity signals work fine afterwards but others fail with "Signal initialization failed". I have no idea whats going on

23:17 Chouser: I'm looking at the source for resolveSignal() in QSignalEmitterInternal -- but I'm don't really understand it.

23:38 jamii: fetchSignal is native. im getting the qt source now

23:59 I think I have it

Logging service provided by n01se.net