On Sep 29, 10:31 pm, Rich Hickey <richhic...@gmail.com> wrote:
> On Tue, Sep 29, 2009 at 4:04 PM, jon <superuser...@googlemail.com> wrote:
>
> Before leaping to implementation/performance issues, I think it is
> important to think about the semantics of this - what does it mean? I
> think you will get a lot of confusion, given:
>
> (defn foo []
>         (send-off-something-that-uses-env (fn [] ... (use-env))))
>
> (defn bar []
>         (establish-env env
>                 (foo)))
>
> If fns 'capture' these environments when created, and re-establish
> them when called, then foo itself will have captured the environment
> at *its* definition/creation point, and will re-establish that, thus
> the environment setup by bar will not be conveyed through foo to
> something-that-uses-env - *but*, if you substituted the body of foo
> for its call, it would. That's bad.

Hi Rich,

(Note - when I say 'environment' below I'm referring to one specially
designated 'environment Var', not the whole set of dynamically bound
Vars we are used to.)

I'm not sure whether you are taking into account the fact that the
semantics of my proposal are that each (fn ..) will only capture (and
later rebind) the environment if it is non-nil at the point it is
instantiated (in the java sense). The environment's root-binding is
nil, and all the user's code should be loaded in this state so that
the (defn ..)s themselves don't capture anything.. ie.no capturing
happens until the user code explicitly 'switches it on' with a (with-
env ..) and then only newly instantiated (fn ..)s will capture the
current environment.

For those kinds of environment data that don't require the fully
dynamic behavior of the regular Vars, wouldn't this be more intuitive
default behavior (ie.that all code "kicked-off" under a given
environment should be evaluated under that environment, even if that
happens later on) rather than the current situation in which any
eagerly evaluated code would see the current environment, and any
delayed-evaluation code would see 'whatever it happens to be at the
time', which would be harder to control?
For the (presumably rare) case that some library code (which may be
called under a non-nil environment) needs to create a (fn ..utilizing
*env*..) which is to be passed out and executed under some yet-to-be-
determined environment.. it could simply be wrapped like this:
  (with-env nil (fn ..utilizing *env*..))

-----
The example you gave doesn't behave badly (ie.differently) when
replacing the body of foo for its call.. as demonstrated below.

user=> (defn send-off-something-that-uses-env [f] (+ 100 (f)))
#'user/send-off-something-that-uses-env
user=> (defn foo [] (send-off-something-that-uses-env (fn [] (+ 10
*env*))))
#'user/foo
user=> (defn bar [] (with-env 1 (foo)))
#'user/bar
user=> (bar)
111
user=> (defn bar [] (with-env 1 (send-off-something-that-uses-env (fn
[] (+ 10 *env*)))))
#'user/bar
user=> (bar)
111

Could you elaborate a bit more on the bad behavior you see..?
Thanks,
Jon

--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to