Why are symbols resolved when a function is defined?

156 views
Skip to first unread message

Paul Barry

unread,
Nov 11, 2008, 12:24:49 AM11/11/08
to Clojure
In Common Lisp and Scheme, if you have an expression that evaluates a
symbol, it doesn't evaluate it until you call the function, not when
you define it. So you can do this:

Common Lisp:
[1]> (defun b () a)
B
[2]> (defvar a 5)
A
[3]> (b)
5

Scheme:
1 ]=> (define (b) a)
;Value: b
1 ]=> (define a 5)
;Value: a
1 ]=> (b)
;Value: 5

But you can't do this in Clojure:
user=> (defn b [] a)
java.lang.Exception: Unable to resolve symbol: a in this context
(NO_SOURCE_FILE:1)

But if you def a to something, you can then redef it and it will use
the value defined later:
user=> (def a nil)
#=(var user/a)
user=> (defn b [] a)
#=(var user/b)
user=> (def a 5)
#=(var user/a)
user=> (b)
5

So is there a reason that Clojure tries to resolve symbols when you
define a function? The downside of this is that when you have a file
with multiple functions in it that call each other, you have to make
sure they are defined in order of dependency.



mac

unread,
Nov 11, 2008, 7:18:38 AM11/11/08
to Clojure
I may not be the right person to answer you because I don't know the
exact reason.
It probably has something to do with interop with JVM calling
mechanism and the fact that Java does not allow calling of undefined
functions?

But like you discovered yourself you can do a forward declaration and
then redef your function so I guess that is the workaround I would
suggest.

And unless you have a circular dependency it's not really a problem,
just define them in order.

/Markus

Rich Hickey

unread,
Nov 11, 2008, 9:16:10 AM11/11/08
to Clojure
I can't speak for Scheme, but CL resolves symbols earlier than does
Clojure - at read time. This causes a number of problems and a lot of
complexity [1].

In Clojure, I had to solve the Lisp-1 vs defmacro problem, and did so
by separating symbols from vars. That means that symbols are simple
when read, and only get resolved when compiled. Were compilation to
auto-create vars for never before seen symbols, many of the problems
of packages would remain, so I decided that vars and other name
resolutions needed to be created intentionally, via def/import/refer.

This leads to many fewer errors, and avoids the problems identified in
[1]. There is now a declare macro that makes it simple and obvious to
intentionally claim names for later use:

(declare a b c)

; ...def a b c in any order

This expands into (def a) (def b) (def c). Note that no initial values
are supplied, so they are unbound, and you will get a runtime error if
you use them before subsequently defining them, unlike your (def a
nil) above, which I don't recommend.

So, you don't need to define things in any specific order - use
declare.

Rich

[1] http://www.flownet.com/gat/packages.pdf

Daniel Renfer

unread,
Nov 11, 2008, 10:13:34 AM11/11/08
to clo...@googlegroups.com
Rich,

Would you recommend using declare even if you are able to arrange your
code to avoid dependency issues, or only if you can't work around it?

Rich Hickey

unread,
Nov 12, 2008, 10:06:22 AM11/12/08
to Clojure


On Nov 11, 10:13 am, "Daniel Renfer" <d...@kronkltd.net> wrote:
> Rich,
>
> Would you recommend using declare even if you are able to arrange your
> code to avoid dependency issues, or only if you can't work around it?
>

I think it's a personal preference thing, certainly not necessary.

Rich
Reply all
Reply to author
Forward
0 new messages