On Mon, Oct 16, 2017 at 10:02 PM, Nick Coghlan <ncogh...@gmail.com> wrote:
> On 17 October 2017 at 14:31, Guido van Rossum <gu...@python.org> wrote: > >> No, that version just defers to magic in ContextVar.get/set, whereas what >> I'd like to see is that the latter are just implemented in terms of >> manipulating the mapping directly. The only operations for which speed >> matters would be __getitem__ and __setitem__; most other methods just defer >> to those. __delitem__ must also be a primitive, as must __iter__ and >> __len__ -- but those don't need to be as speedy (however __delitem__ must >> really work!). >> > > To have the mapping API at the base of the design, we'd want to go back to > using the ContextKey version of the API as the core primitive (to ensure we > don't get name conflicts between different modules and packages), and then > have ContextVar be a convenience wrapper that always accesses the currently > active context: > > class ContextKey: > ... > class ExecutionContext: > ... > > class ContextVar: > def __init__(self, name): > self._key = ContextKey(name) > > def get(self): > return get_execution_context()[self._key] > > def set(self, value): > get_execution_context()[self._key] = value > > def delete(self, value): > del get_execution_context()[self._key] > Why would we need this extra layer? I would assume that the key can just be the ContextVar object itself, e.g. return get_execution_context()[self] or get_execution_context()[self] = value > While I'd defer to Yury on the technical feasibility, I'd expect that > version could probably be made to work *if* you were amenable to some of > the mapping methods on the execution context raising RuntimeError in order > to avoid locking ourselves in to particular design decisions before we're > ready to make them. > > The reason I say that is because one of the biggest future-proofing > concerns when it comes to exposing a mapping as the lowest API layer is > that it makes the following code pattern possible: > > ec = get_execution_context() > # Change to a different execution context > ec[key] = new_value > > The appropriate semantics for that case (modifying a context that isn't > the currently active one) are *really* unclear, which is why PEP 550 > structures the API to prevent it (context variables can only manipulate the > active context, not arbitrary contexts). > But why on earth would you want to prevent that? If there's some caching involved that I have overlooked (another problem with the complexity of the design, or perhaps the explanation), couldn't mutating the non-context simply set a dirty bit to ensure that if it ever gets made the current context again the cache must be considered invalidated? > However, even with a mapping at the lowest layer, a similar API constraint > could still be introduced via a runtime guard in the mutation methods: > > if get_execution_context() is not self: > raise RuntimeError("Cannot modify an inactive execution context") > > That way, to actually mutate a different context, you'd still have to > switch contexts, just as you have to switch threads in C if you want to > modify another thread's thread specific storage. > But that sounds really perverse. If anything, modifying an EC that's not any thread's current context should be *simpler* than modifying the current context. (I'm okay with a prohibition on modifying another *thread's* current context.) -- --Guido van Rossum (python.org/~guido)
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com