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