You already know this has been discussed a lot over the years.

I just wanted to cite the best reasoning that I've seen from Rich about why
Clojure does it the way that it does, which I believe is the argument that
surrounded an blog post fro Steve Yegge that Rich responded to and some
excellent discussion surrounding it on hackernews and the mailing list:
https://news.ycombinator.com/item?id=2466731

On hackernews, Rich made a post that I believe is the best "last word"
explaining his reasoning, which I'll quote here:

The issue is not single-pass vs multi-pass. It is instead, what constitutes
> a compilation unit, i.e., a pass over what?
>
> Clojure, like many Lisps before it, does not have a strong notion of a
> compilation unit. Lisps were designed to receive a set of
> interactions/forms via a REPL, not to compile files/modules/programs etc.
> This means you can build up a Lisp program interactively in very small
> pieces, switching between namespaces as you go, etc. It is a very valuable
> part of the Lisp programming experience. It implies that you can stream
> fragments of Lisp programs as small as a single form over sockets, and have
> them be compiled and evaluated as they arrive. It implies that you can
> define a macro and immediately have the compiler incorporate it in the
> compilation of the next form, or evaluate some small section of an
> otherwise broken file. Etc, etc. That "joke from the 1980's" still has
> legs, and can enable things large-unit/multi-unit compilers cannot. FWIW,
> Clojure's compiler is two-pass, but the units are tiny (top-level forms).
>
> What Yegge is really asking for is multi-unit (and larger unit)
> compilation for circular reference, whereby one unit can refer to another,
> and vice versa, and the compilation of both units will leave hanging some
> references that can only be resolved after consideration of the other, and
> tying things together in a subsequent 'pass'. What would constitute such a
> unit in Clojure? Should Clojure start requiring files and defining
> semantics for them? (it does not now)
>
> Forward reference need not require multi-pass nor compilation units.
> Common Lisp allows references to undeclared and undefined things, and
> generates runtime errors should they not be defined by then. Clojure could
> have taken the same approach. The tradeoffs with that are as follows:
>
> 1) less help at compilation time 2) interning clashes
>
> While #1 is arguably the fundamental dynamic language tradeoff, there is
> no doubt that this checking is convenient and useful. Clojure supports
> 'declare' so you are not forced to define your functions in any particular
> order.
>
> #2 is the devil in the details. Clojure, like Common Lisp, is designed to
> be compiled, and does not in general look things up by name at runtime.
> (You can of course design fast languages that look things up, as do good
> Smalltalk implementations, but remember these languages focus on dealing
> with dictionary-carrying objects, Lisps do not). So, both Clojure and CL
> reify names into things whose addresses can be bound in the compiled code
> (symbols for CL, vars for Clojure). These reified things are 'interned',
> such that any reference to the same name refers to the same object, and
> thus compilation can proceed referring to things whose values are not yet
> defined.
>
> But, what should happen here, when the compiler has never before seen bar?
>
>     (defn foo [] (bar))
>
> or in CL:
>
>     (defun foo () (bar))
>
> CL happily compiles it, and if bar is never defined, a runtime error will
> occur. Ok, but, what reified thing (symbol) did it use for bar during
> compilation? The symbol it interned when the form was read. So, what
> happens when you get the runtime error and realize that bar is defined in
> another package you forgot to import. You try to import other-package and,
> BAM!, another error - conflict, other-package:bar conflicts with
> read-in-package:bar. Then you go learn about uninterning.
>
> In Clojure, the form doesn't compile, you get a message, and no var is
> interned for bar. You require other-namespace and continue.
>
> I vastly prefer this experience, and so made these tradeoffs. Many other
> benefits came about from using a non-interning reader, and interning only
> on definition/declaration. I'm not inclined to give them up, nor the
> benefits mentioned earlier, in order to support circular reference.
>
> Rich
>

-- 
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
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to