Self-referential gen-class usage

86 views
Skip to first unread message

Chas Emerick

unread,
Jun 26, 2008, 10:56:18 AM6/26/08
to Clojure
At some point, I came to need to define a generated Java class that
had methods that returned instances of the class being generated. The
gen-and-save-class form looked like this:

(gen-load-save-class
"."
'pkg.Foo
:implements [Bar]
:init 'new-foo
:constructors {[(. Float TYPE)] []}
:methods [['union [java.util.Collection] 'pkg.Foo]] ;<---
:state 'state)

The problem is with the usage of 'pkg.Foo in the union method
signature def. gen-class expects classes for those signature
definitions, and since the pkg.Foo class doesn't exist yet, I can't
reference it in the signature.

On a lark, I thought I'd try a macro that would generate and load a
class (without any references to the generated class), and then
generate and save that same class with all of the method definitions,
etc. (By no means efficient, since the bytecode is being generated
twice, but this is mostly fun and I didn't want to futz with using gen-
class directly and then handling writing out or loading the bytecode.)
The result is this:

(defmacro gen-load-save-class [path name & options]
(let [optmap (apply hash-map options)
save-only-opts #{:methods :constructors}
trimmed-opts (reduce #(if (save-only-opts %2) %1 (concat %1
[%2] [(optmap %2)])) [] (keys optmap))]
`(do (gen-and-load-class ~name ~@trimmed-opts)
(eval '(gen-and-save-class ~path ~name ~@options)))))

gen-load-save-class has the same signature as gen-and-save-class. It
pulls out the options to gen-class that can contain self-references
(only :methods and :constructors at the moment, I believe), generates
and loads the result of that trimmed-down option set, and then
generates and saves the full class definition.

One interesting wrinkle is that the gen-and-save-class form needs to
be wrapped in an eval; otherwise clojure will attempt to resolve
references to the generated classname in the options to gen-and-save-
class before it even gets to the point of evaluating the gen-and-load-
class call.

I know Rich is aware of this use-case (referring to the generated
classname when using gen-class), so a real solution will probably be
forthcoming sooner or later, but this was an interesting exercise in
the meantime.

- Chas

Beau Fabry

unread,
Nov 25, 2015, 6:22:11 PM11/25/15
to Clojure, ceme...@snowtide.com
Forgive me for resurrecting a 7 year old thread, but is this still the solution?
Reply all
Reply to author
Forward
0 new messages