On Jan 23, 11:22 am, "John Cowan" <
johnwco...@gmail.com> wrote:
> On Jan 23, 2008 9:30 AM, Rich Hickey <
richhic...@gmail.com> wrote:
>
> > If locals were variables, i.e. mutable, then closures could close over
> > mutable state, and, given that closures can escape (without some extra
> > prohibition on same), the result would be thread-unsafe. And people
> > would certainly do so, e.g. closure-based pseudo-objects. The result
> > would be a huge hole in Clojure's approach.
>
> FWIW, although Scheme supports mutable locals, it's quite common for
> compilers to treat that as syntax sugar, and to replace references to
> mutable variables with immutable references to mutable boxes on the
> heap. This is called "assignment conversion".
I'm fully aware of that conversion - prior to its move to primarily-
functional Clojure had mutable locals and did exactly that (using
clojure.lang.Box :) . But whether locals live on the heap or stack
isn't relevant here (they have to live on the heap in the JVM in order
to escape), what matters is the mutability. As long as it can be
shared, which it must be in order to support closure semantics, a
mutable 'box' has the same threading problems.
Note that by problems I don't mean that meaningful multithreaded
semantics couldn't be assigned - they could just be last-one-in-wins
volatiles. What I mean is that they would be awful as primitives for
multithreaded programs, with no read-modify-write or coordination
capabilities.
> AFAICT, though, a
> Clojure Var can't be the value of a local variable -- it can only be
> referred to by its name.
>
Vars are first class, although there aren't any helper functions yet.
Here's how they work:
(import '(clojure.lang Var))
(def x (. Var (create)))
;x is a var that holds a var, could just as easily be a local
(. x (get))
-> java.lang.IllegalStateException: Var null is unbound.
(. x (bindRoot "fred"))
(. x (get))
-> "fred"
(try
(. Var (pushThreadBindings {x "ethel"}))
(. x (get))
(finally (. Var (popThreadBindings))))
-> "ethel"
(. x (get))
-> "fred"
There's also a set method, which throws if the var is not thread-
locally bound.
Note that if one were to use a Var as the value of a local variable it
still wouldn't be the same as a true mutable local, as it would have
different behavior were any capturing closure to be run outside the
dynamic scope of the binding.
Rich