<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 17 October 2017 at 03:00, Guido van Rossum <span dir="ltr"><<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="gmail-">On Mon, Oct 16, 2017 at 9:11 AM, Yury Selivanov <span dir="ltr"><<a href="mailto:yselivanov.ml@gmail.com" target="_blank">yselivanov.ml@gmail.com</a>></span> wrote:<br></span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span></span><div><div class="gmail-h5"><span>> I agree, but I don't see how making the type a subtype (or duck type) of<br>
> MutableMapping prevents any of those strategies. (Maybe you were equating<br>
> MutableMapping with "subtype of dict"?)<br>
<br>
</span>Question: why do we want EC objects to be mappings?  I'd rather make<br>
them opaque, which will result in less code and make it more<br>
future-proof.<br></div></div></blockquote><div><br></div><div>I'd rather have them mappings, since that's what they represent. It helps users understand what's going on behind the scenes, just like modules, classes and (most) instances have a `__dict__` that you can look at and (in most cases) manipulate.<br></div></div></div></div></blockquote><div><br></div><div>Perhaps rather than requiring that EC's *be* mappings, we could instead require that they expose a mapping API as their __dict__ attribute, similar to the way class dictionaries work?</div><div><br></div><div>Then the latter could return a proxy that translated mapping operations into the appropriate method calls on the ContextVar being used as the key.</div><div><br></div><div>Something like:</div><div><br></div><div>    class ExecutionContextProxy:</div><div>        def __init__(self, ec):</div><div>            self._ec = ec</div><div>            # Omitted from the methods below: checking if this EC is the</div><div>            # active EC, and implicitly switching to it if it isn't (for read ops)</div><div>            # or complaining (for write ops)<br></div><div><br></div><div>        # Individual operations call methods on the key itself<br></div>        def __getitem__(self, key):<div>            return key.get()<br></div><div>        def __setitem__(self, key, value):</div><div>            if not isinstance(key, ContextVar):</div><div>                raise TypeError("Execution context keys must be context variables")<br></div><div>            key.set(value)<br></div></div>        def __delitem__(self, key):<div>            key.delete()</div><div><br></div><div>        # The key set would be the context vars assigned in the active context<br></div><div>        def __contains__(self, key):</div><div>            # Note: PEP 550 currently calls the below method ec.vars(),</div><div>            # but I just realised that's confusing, given that the vars() builtin</div><div>            # returns a mapping<br></div><div>            return key in self._ec.assigned_vars()</div><div><div>        def __iter__(self):</div><div>            return iter(self._ec.assigned_vars())</div>        def keys(self):</div><div>            return self._ec.assigned_vars()</div><div><br></div><div>        # These are the simple iterator versions of values() and items()<br></div><div>        # but they could be enhanced to return dynamic views instead<br></div><div><div>        def values(self):</div><div>            for k in self._ec.assigned_vars():</div><div>                yield k.get()<br></div>        def items(self):</div><div>            for k in self._ec.assigned_vars():</div><div>                yield (k, k.get())<br></div><div><br></div><div>The nice thing about defining the mapping API as a wrapper around otherwise opaque interpreter internals is that it makes it clearer which operations are expected to matter for runtime performance (i.e. the ones handled by the ExecutionContext itself), and which are mainly being provided as intuition pumps for humans attempting to understand how execution contexts actually work (whether for debugging purposes, or simply out of curiosity)</div><div><br></div><div>If there's a part of the mapping proxy API where we don't have a strong intuition about how it should work, then instead of attempting to guess suitable semantics, we can instead define it as raising RuntimeError for now, and then wait and see if the appropriate semantics become clearer over time.<br></div><div><br></div><div>Cheers,</div><div>Nick.<br></div><br>-- <br><div class="gmail_signature">Nick Coghlan   |   <a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>   |   Brisbane, Australia</div>
</div></div>