Hi Alex, OK, I agree. Dynamic vars are not the same as traditional dynamic scoping.
For what I'm doing (making functions durable), it raises the question: If you persist a function that points to a var, restart the JVM, and deserialize/load the function from a data store, what should happen? 1) In the loading thread, if a var exists with the same namespace and symbol, set the internal reference to that var. a) If the function is then passed to a different thread that has a different var with that same namespace and symbol, the function will still point to the one that was in the loader thread at the time the function was deserialized/loaded. 2) In the loading thread, if a var does not exist with that same namespace and symbol: a) Throw an exception saying that the var doesn't exist. b) Create the var with no namespace and symbol and no value. Wait until the function is called to throw an exception saying that the var is unbound. c) Create the var with no namespace and symbol but with the value that the var had in the persisting thread. There's no way to access the var to modify it. d) Create the var with no namespace and symbol but with the value that the var had in the persisting thread. It's accessible somehow (maybe the meta map), so the user can recover it and dynamically bind over it. e) Create the var with the namespace and symbol in the function, modifying the RT var-space of the loading thread. Don't initialize the var. This gives the user a chance to dynamically bind over it. If the function is called before binding the var to something, throw an exception saying that the var is unbound. f) Create the var with the namespace and symbol in the function, with the value that the var had in the persisting thread. The normal case (1) is straightforward, and (1a) is what would happen without se/des anyways. (2) is tricky. (2f) is most robust, but really violates least surprise. I think Meikel's comments lean towards (2a). Also, the thread-local nature of vars raises the question of what should happen when deserializing the same function from different threads. If I create durable refs from different threads pointing to the same store/key combo, does the thread that gets there first control which var the deserialized function references? Or does each thread get it's own ref? If so, how do you reconcile that there are multiple refs being stored under the same store/key? That's untenable, but it seems totally arbitrary to simply say that the first thread that gets there determines which var the function is bound to for the duration of the JVM instance. What do you think? Thanks, Alyssa Kwan On Nov 17, 8:20 pm, Alex Osborne <a...@meshy.org> wrote: > Alyssa Kwan <alyssa.c.k...@gmail.com> writes: > > I understand exactly why this situation exists. I just think the > > behavior is unexpected. When I create a function with a dynamic > > binding, I expect the function to keep a reference to the *name*, not > > the var that the name resolves to at compile/clinit time. > > Oh, I see what you mean. I guess you're expecting something more like > Python's behaviour: > > >>> x = 5 > >>> def foo(): > ... return x > ... > >>> foo() > 5 > >>> del x > >>> foo() > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > File "<stdin>", line 2, in foo > NameError: global name 'x' is not defined > > In the case of Python, globals are a mutable map of names directly to > values and are presumably looked up at runtime. Python doesn't have > Clojure's concept of "vars". > > >>> globals() > {..., 'x': 5, 'foo': <function foo at 0xb775b7d4>, ...} > > > I guess the question is: what do other people expect? Am I alone in > > thinking that this is unexpected and undesirable? > > It makes sense to me. I have a mental picture of functions closing over > the (lexical) environment as it existed when the function was defined > and that includes the dynamic vars as they were named at that moment. > > Similarly in Python you can do this: > > def foo(): > return bar() > > def bar(): > return 5 > > Whereas in Clojure you would need to declare bar before foo. > > That may mean dynamic vars are not exactly the same thing as traditional > dynamic scoping, but I don't see anything obviously unexpected or > undesirable about it. In fact quite the opposite, it's an intentional > design choice. It's consistent with the Clojure philosophy of > identities being first class. One of the major themes that distinguishes > Clojure's programming model from traditional languages is that names, > identities and values are distinct concepts. > > A single var can be mapped into different namespaces under different > names (for example using the :rename argument to "use"). So the same > identity (var) may be referred to by multiple names (symbols), but it's > the identity you are dynamically binding a value to, not the name. -- 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