Re: [Python-ideas] Method signature syntactic sugar (especially for dunder methods)
* __add__ is only part of the addition protocol, there is also __radd__ and __iadd__
__iadd__ could be represented as def self += value:. Reflected binary operators do pose a problem. A possible solution would be to give self special meaning in this context, so def self + other: would correspond to __add__ and def other + self: to __radd__. But of course, this would be a more fundamental change to the language than just syntactic sugar.
* likewise, there is not a one-to-one correspondence between the bool() builtin and the __bool__() special method (there are other ways to support bool(), like defining __len__() on a container)
That is a fair point, but I think this would be only a slight point of confusion. I believe for the most part other builtins such as __abs__, __len__, etc. do have a one-to-one correspondence so this syntax would make sense in almost all situations. But while were on the topic, I will take this opportunity to note that all the methods to support builtins suffer from the same ambiguity I alluded to earlier with bool(self). One solution could be to use a @builtin decorator or something to that effect, but that would more or less defeat the purpose of cleaner, more intuitive syntax. It may be that there is no viable alternative for the builtin function dunder methods.
* the mapping protocol covers more than just __getitem__
__setitem__(self, key, value) could be def self[key] = value likewise __delitem__(self, key) def del self[key]: __iter__(self) iter(self) __len__(self) len(self)
(and you also need to decide if you're implementing a mapping, sequence, or multi-dimensional array)
Could you speak more about this? It doesn't seem to me that this would affect the method signatures since it is up to the implementer to interpret the semantic meaning of the keys.
it would break the current symmetry between between name binding in def statements and target binding in assignment statements
With the proposed change, we'd face the problem that the following would both be legal, but meant very different things:
cls.mymethod = lambda self: print(self) def cls.mymethod(self): print(self)
The former is already legal and assigns the given lambda function as a method on the existing class, `cls`
The latter currently throws SyntaxError.
With the proposed change, rather than throwing SyntaxError as it does now, the latter would instead be equivalent to:
def mymethod(cls, self): print(self)
which would be a very surprising difference in behaviour.
I will admit that there is potential for confusion here as this class Formatter(object): def Formatter.displayDefault(obj): print('[{}]'.format(obj)) is rather suggestive of a static method, but I don't think the confusion arises because the syntax breaks the symmetry you reference. The self-dot syntax *is* meant to elicit target binding in assignment statements. Just as self.mymethod = lambda p1, p2: p1+p2 indicates that an instance of the class has a callable with two parameters bound to its mymethod attribute, so too does the statement def self.mymethod(p1, p2):. So I don't think this inherently breaks any symmetry. It is specifically in the case that the identifier is the same as the class name that this leads to surprising behavior, but there is already a similar risk of confusion any time the name of a class is used as an identifier within the class body. Perhaps my proposed syntax does increase this risk since the identifier doesn't look like a parameter or a variable, but hopefully the self form of this syntax would be so commonplace that seeing anything else before the dot would throw up a red flag. Thanks, -Nate
Nathan Dunn writes:
* the mapping protocol covers more than just __getitem__
__setitem__(self, key, value) could be def self[key] = value likewise __delitem__(self, key) def del self[key]: __iter__(self) iter(self) __len__(self) len(self)
The template used by last two (BTW, shouldn't they be "def iter(self)" and "def len(self)"?) seems like a really bad idea to me. This would imply that any class that defines such methods in some arbitrary fashion will appear to participate in the corresponding protocol although it doesn't. That seems likely to result in bugs, that might be hard to diagnose (haven't thought about how hard that might be, though). It would require the programmer to know about all such protocols when designing a public API, while with the dunder convention, you only need to find out whether the dunders you want to use for your new protocol are already in use somewhere, and programmers who aren't designing protocols don't need to know about them at all. It would also require a modification to the compiler for every new protocol. I personally don't see that the other syntaxes are helpful, either, but that's a matter of opinion and I'd be interested to hear about experience with teaching languages that implement such "method definitions look like invocation syntax". Regards,
I think that the most important simple thing with dunder/magic methods is name mangling, and that an abstraction like your proposed one makes it less clear what will happen to a name. Also, as Nick Coghlan pointed out, there are a lot of dunder/magic methods https://docs.python.org/3/reference/datamodel.html. Either each of those methods would need an alternate representation, or some would be left out - which would lead to inconsistent style. Maybe I'm resisting change too much, but I think that the solution to this issue is to make the magic method documentation easier to teach, as opposed to changing them. -Ryan Birmingham On 7 November 2016 at 23:49, Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
Nathan Dunn writes:
* the mapping protocol covers more than just __getitem__
__setitem__(self, key, value) could be def self[key] = value likewise __delitem__(self, key) def del self[key]: __iter__(self) iter(self) __len__(self) len(self)
The template used by last two (BTW, shouldn't they be "def iter(self)" and "def len(self)"?) seems like a really bad idea to me. This would imply that any class that defines such methods in some arbitrary fashion will appear to participate in the corresponding protocol although it doesn't. That seems likely to result in bugs, that might be hard to diagnose (haven't thought about how hard that might be, though). It would require the programmer to know about all such protocols when designing a public API, while with the dunder convention, you only need to find out whether the dunders you want to use for your new protocol are already in use somewhere, and programmers who aren't designing protocols don't need to know about them at all. It would also require a modification to the compiler for every new protocol.
I personally don't see that the other syntaxes are helpful, either, but that's a matter of opinion and I'd be interested to hear about experience with teaching languages that implement such "method definitions look like invocation syntax".
Regards,
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Another advantage of dunder method names is that you can google them. Someone coming across a method called "__foo__" can easily find documentation about it, but it's not so easy to do that for special syntax. -- Greg
Also you can support future changes to the syntax (e.g. __matmul__ and
friends from 3.5, __aiter__ from 3.5.2) with a single codebase rather than
having to push that grammar back to previous versions (impossible?) or have
the grammar for magic methods be extraordinarily general (messy?)
On Tue, Nov 8, 2016 at 3:56 PM, Greg Ewing
Another advantage of dunder method names is that you can google them. Someone coming across a method called "__foo__" can easily find documentation about it, but it's not so easy to do that for special syntax.
-- Greg
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
participants (5)
-
Greg Ewing
-
Nathan Dunn
-
Nick Timkovich
-
Ryan Birmingham
-
Stephen J. Turnbull