Hello Rich, It's been a long time since I've not hijacked a thread, so let's get back to this bad habit exceptionally :)
While the example provided by jon may not be the best ones, as you pointed out below, I feel there still is a problem: dynamic scopes and threads. I don't know how it can be correctly addressed (or if it can - theoretically, and then practically -, has it been adressed in other languages ?), but here is how I would state the problem: When reusing libraries made by others, one could rely on dynamic bindings on some functions (a classical case may be having an *db* dynamic var -though it is arguable- ?). But without knowing too much details concerning the internals of the used libraries, one can not know whether the library uses parallel computing some times to speed things. In those cases, one may have weird "bugs" because some bindings have been "reinitialized" to the root binding by switching to technical threads. Where should the responsability be placed ? Should the user of the library, in doubt, place everywhere in his code bind-fn calls to protect it ? Should the library author use bind-fn before dispatching to other threads (with the problem that the library author may not know which dynamic vars are relevant) ... Thanks in advance for even more insightful comments on this problem, -- Laurent 2009/9/29 Rich Hickey <richhic...@gmail.com> > > On Tue, Sep 29, 2009 at 4:04 PM, jon <superuser...@googlemail.com> wrote: > > > > Hi.. long post.. it's a Request For Comment :) > > > > Clojure's "thread local binding facility" for Vars has always seemed > > like > > a useful (but of course misusable) feature to have available in our > > toolbox.. > > However it soon becomes apparent that Var bindings don't play nice > > with > > laziness - and since laziness can creep in all over the place > > (eg. using standard sequence functions, direct use of (lazy-seq ..), > > using (delay ..), perhaps from any (fn ..) you create) > > that renders them of much less value.. almost too unsafe to tangle > > with > > in my opinion. > > To quote Rich, "there is a fundamental tension between laziness and > > dynamic > > scope, combine with extreme caution." > > > > The underlying problem is that when each (fn ..) gets created it > > doesn't > > capture the current dynamic environment so that it can subsequently be > > made > > available when it is eventually invoked. > > This is not a 'problem', this is what dynamic means. > > > To quote Rich once more, "The overhead for capturing the dynamic > > context > > for every lazy seq op would be extreme, and would effectively render > > dynamics non-dynamic." > > > > To help alleviate the problem somewhat, a (bound-fn ..) helper macro > > has > > been created (https://www.assembla.com/spaces/clojure/tickets/170) > > but my guess is that its use would be impractical/ugly/risky.. > > it would need to be used "all over the place" and forgetting to use it > > in any of those places could introduce a bug. > > > > I don't think so. There are people who are sending off jobs to agents > that they know will used the dynamic environment for which bound-fn > will work perfectly. And most code need never consider it. If you need > it all over the place you have too much use of dynamic vars and > laziness + side-effects. The person who needs to think about this is > the person using send/future etc with context-sensitive work. If there > were to be generic capturing points, it might be macros wrapping > those. > > > I've been thinking about an alternative to (bound-fn ..) and would > > like your opinions on the following tweak to Clojure: > > > > > ...Implementation details elided... > > > With a better integrated, better designed implementation, I'm > > certain this could be improved further. > > In that case, would this be a worthwhile enhancement to Clojure? > > Seems like it could be a win-win situation, since it rescues > > (semi-)dynamic bindings from the gnashing jaws of laziness > > for those that want to use it, but shouldn't impact negatively > > upon those that don't? > > Or is there something fundamentally wrong with the idea? > > > > 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. > > 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 -~----------~----~----~----~------~----~------~--~---