eval and load-string behavior

25 views
Skip to first unread message

Jonathan Fischer Friberg

unread,
Jun 20, 2011, 7:45:40 PM6/20/11
to clo...@googlegroups.com
I got a very nasty bug from this behavior today

user=> (def a (fn [] "outside a"))
#'user/a
user=> (let [a (fn [] "inside a")] (load-string "(a)"))
"outside a"
user=> (let [a (fn [] "inside a")] (eval '(a)))
"outside a"

Is this really how these functions should behave?

Jonathan

Sean Corfield

unread,
Jun 20, 2011, 7:54:55 PM6/20/11
to clo...@googlegroups.com
On Mon, Jun 20, 2011 at 4:45 PM, Jonathan Fischer Friberg
<odys...@gmail.com> wrote:
> user=> (def a (fn [] "outside a"))
> #'user/a
> user=> (let [a (fn [] "inside a")] (load-string "(a)"))
> "outside a"
> user=> (let [a (fn [] "inside a")] (eval '(a)))
> "outside a"
>
> Is this really how these functions should behave?

Since let provides a lexical binding rather than a dynamic binding,
I'm not too surprised by the result.

Would the following do what you want?

(def ^{:dynamic true} *a* (fn [] "outside a"))
(binding [*a* (fn [] "inside a")] (load-string "(*a*)"))
(binding [*a* (fn [] "inside a")] (eval '(*a*)))

(FWIW, those yield "inside a" in both cases)
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/
Railo Technologies, Inc. -- http://www.getrailo.com/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)

David Nolen

unread,
Jun 20, 2011, 8:49:48 PM6/20/11
to clo...@googlegroups.com

Jonathan Fischer Friberg

unread,
Jun 21, 2011, 6:51:51 AM6/21/11
to clo...@googlegroups.com
Thanks, but I think I'll simply input the let in the string, i.e

(load-string "(let [a (fn [] "inside fn")] (a))")

But I still think it's odd behavior. I've always thought of eval as equal to putting that code there.

(eval '(a)) is equal to (a)

Which I think would be much more intuitive.

Jonathan

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Jonathan Fischer Friberg

unread,
Jun 21, 2011, 6:43:35 PM6/21/11
to clo...@googlegroups.com
It seems like the following macro would work as well:

(defmacro load-string-here [string] (read-string string))

=> (let [a (fn [] "inside fn")] (load-string-here "(a)"))
"inside fn"

Jonathan

David Nolen

unread,
Jun 21, 2011, 7:04:31 PM6/21/11
to clo...@googlegroups.com
If Clojure was interpreted this behavior would be simple to support.
It seems like you'd have to complicate the compiler for little
benefit.

Meikel Brandmeyer

unread,
Jun 22, 2011, 2:20:26 AM6/22/11
to clo...@googlegroups.com
Hi,

note that this breaks down as soon as you don't provide a literal string. And if you provide a literal string, you can provide the form directly anyway...

Sincerely
Meikel

Jonathan Fischer Friberg

unread,
Jun 22, 2011, 6:16:46 AM6/22/11
to clo...@googlegroups.com
Yes, unless you wrap it in another macro.

(defmacro a [] (vec (map (fn [x] `(load-string-here ~x)) ["1" "2" "3" "4"])))

=> (a)
[1 2 3 4]

But it's still pretty useless, unless macros are to replace functions...

Jonathan

Reply all
Reply to author
Forward
0 new messages