Hi Rich,

Thanks for the quick reply! I'm probably just being slow here, for which
I apologise, but some questions remain:

Rich Hickey wrote:
> On Oct 26, 3:49 pm, Phil Jordan <[EMAIL PROTECTED]> wrote:
>> First of all, is the breakage intentional?
> 
> Yes. You can no longer embed unreadable objects in code, in this case
> fn constants. This is to support ahead-of-time compilation - every
> constant must have a readable print representation.

Okay, I *think* I understand what you're saying. Those fns are instances
of a class which has been compiled while processing the (def mylocals
..) form, but at compile time, the mylocals var hasn't been
*initialised* - that happens at load time, where instances of those fn
classes are created. Those instances could be closures which have local
state and can't be baked in.

It works for symbols because they're stateless, unique atoms.

Am I on the right track here?

> I've added an unreadable #<...> form, made it the default for print-
> method, and added a check for unreadable forms in in-code constants
> and throw during compilation, in order to move the detection of this
> problem to compilation time vs. class initialization time.

Okay, I'm now getting the more sane error of:

java.lang.RuntimeException: Can't embed unreadable object in code:
#<[EMAIL PROTECTED]>

which certainly helps to localise the issue should it crop up again in
future. However, I'm still not clear on how to best ("correctly",
"idiomatically") write this sort of macro where locals named elsewhere
are bound to functions defined at compile time. I currently see these
possibilities:


(1) let the macro expand into an eval on the block's body. This works
for anything of course, but I view runtime eval as a kind of last resort.


(2) expand into var lookups, like so:

(defmacro letlocals [names fns & body]
        (list*
                'let
                (vec (mapcat
                        #(list %1 (list fns %2))
                        (eval names)
                        (iterate inc 0)))
                body))
(def mylocal-names ['A 'B])
(def mylocal-fns [(fn [] "I'm A") (fn [] "I'm B")])

so that
(letlocals mylocal-names mylocal-fns (str (A) (B))
macroexpand-1s into
(let [A (mylocal-fns 0) B (mylocal-fns 1)] (str (A) (B)))


(3) expand the fn form bodies literally into the local definitions. This
has three downsides: no closures, code bloat, potential for bugs if the
surrounding code defines locals that override vars that are used in the fns.


Right now, (2) looks like the most attractive option to me, although I
kind of preferred the original version's clarity. The macro can of
course be made cleaner than my quick-and-dirty idea above, for example
by utilising let's destructuring features.

If I've missed anything, and anyone has any other (better!) suggestions,
I'd like to hear them of course! :)

Thanks,
~phil

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to