On Mon, Jul 23, 2018 at 1:28 PM Steven D'Aprano <st...@pearwood.info> wrote:
> There's the first bug right there. foo.bar.blim ought to raise > AttributeError, since there is no blim attribute defined on foo.bar. > Note my observation that this is deliberately different semantics. I want to solve the underlying need, not simply emulate the less useful semantics of PEP 505. But those same semantics COULD be perfectly well emulated with a similar class. > > In [8]: NoneAware(foo).bar.blim.unbox() > > In [9]: NoneAware(foo).bar.baz.blat.unbox() > > Out[9]: 42 > > How many bugs will be caused by people forgetting to unbox when they're > done? > Far fewer and far more easily caught. When the object you get wherever the real failure happens is ` <none_aware.NoneAware at 0x11156a748>` or the like, the source of the problem become dead obvious. Having `None` somewhere unexpected is much more mysterious and difficult to diagnose. That said, NoneAware is the wrong name for the class I wrote. Maybe GreedyAccess would be a better name. Perhaps I'll make slightly less toy implementations of an actual NoneCoalesce and GreedyAccess class and post in this thread and/or on PyPI. It does look like PyMaybe does much of what I'm thinking of. I didn't think my toy was the first or best implementation. > But we aren't entering such a world, at least not in PEP 505. Attribute > access can fail. > spam.eggs = 42 spam?.eggs?.upper > is still going to raise AttributeError, because eggs is not None, it is an > int, and ints don't have an attribute "upper". True enough. But it's extremely difficult to imagine a real-world case where those particular semantics are actually particularly useful. I guess my revulsion at the syntax blinded me to the fact that the semantics are actually pretty bad on their own. > How does your class implement short-circuit behaviour? > You mean if we want something like this? favorite = GreedyAccess(cfg, sentinel=ExpensiveLookup()).user.profile.food.unbox() It doesn't. Something else (like PyMaybe) could defer the computation using a lambda or other means. My toy code doesn't do that. We could also avoid the visible lambda by doing an 'iscallable(sentinel)' and only calling it if it turns out to be needed, but that might be too magical. E.g.: # If we fail, favorite = ExpensiveLookup(), by magic favorite = GreedyAccess(cfg, sentinel=ExpensiveLookup).user.profile.food.unbox() So we don't like operators like ?? because its too cryptic, but you're > happy to have one-character class and property names. > No, I'm not happy with that. I was just pointing out that code golf is possible for someone who really wants it. I'm happy to spend a few characters for readability. But one COULD write: from nested import GreedyAccess as G G._ = G.unbox > What happens if you have an attribute that happens to be > called "unbox" in your attribute look-up chain? > Don't use this class and/or modify the API slightly? This is getting trite. My 5 minute code isn't a final proposal, just a way of seeing a napkin-sketch of a better approach. -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/