On 2021-06-22 05:14, Chris Angelico wrote:
Fair point. However, I've worked with a good number of languages that
have some notion of object methods, and generally, an object has or
doesn't have a method based on what the object*is*, not on who's
asking.
I agree, and this is the aspect of the proposal that most confuses me.
I still can't understand concretely what is being proposed, though, so
I'm not sure I even understand it. Can someone clarify? Suppose I have
this
*****
### file1.py
@extend(list)
def len2(self):
return len(self)**2
### file2.py
# or whatever I do to say "I want to use extensions to list defined in
file1"
from file1 extend list
def coolness(some_list):
return some_list.len2() + 1
my_list = [1, 2, 3]
print("My list len2:", my_list.len2())
print("My list coolness:", coolness(my_list))
### file3.py
import file2
other_list = [1, 2, 3, 4]
print("Other list len2:", other_list.len2())
print("other list coolness:", file2.coolness(other_list))
print("My list len2 from outside:", file2.my_list.len2())
print("My list coolness from outside:", file2.coolness(file2.my_list))
*****
What exactly is supposed to happen here if I run file3? file2 declares
use of file1's extensions. file2 does not. But file3 uses a function
in file2 that makes use of such extensions. Who sees the extension?
The list object my_list in file2 is the same object accessed as
file2.my_list in file3. Likewise coolness and file2.coolness. It is
going to be super confusing if calling the same function object with the
same list object argument gives different results depending on which
file you're in. Likewise it's going to be confusing if the same list
object sometimes has a .len2 method and sometimes doesn't.
But if it doesn't work that way, then it would seem to mean either
every module sees the extensions (even if they didn't opt in), or else
my_list in file2 is not the same object as file2.my_list in file3. And
that would be even worse. (In this example it may seem okay because you
can ask why I would call len2 from file3 if I didn't want to use it.
But what if the extension is an override of an existing method? Is that
not allowed?)
In addition, if there is a difference between my_list and other_list,
then that apparently means that the syntax for lists now does something
different in the two files. This is maybe the most reasonable approach,
since it's at least remotely reminiscent of a __future__ import, which
changes syntactic behavior. But what exactly is the difference between
the two objects here? Are both objects lists? If they are, then how
can they have different methods? If they're not, then what are they?
Most __future__ imports don't work like this. Maybe the closest thing
is the generator_stop one, but at least that places a flag on the code
object to indicate the difference. Would "extended lists" have some
kind of magic attribute indicating which extensions they're using? That
may have been marginally acceptable in the case of PEP 479, which was
essentially a bugfix, and set the attribute on code objects which are an
obscure internal data structure. But allowing this kind of thing for
"user-facing" objects like lists would create a profusion of different
list objects with different behavior depending on some combination of
attributes indicating "what extends me" --- or, even worse, create
different behavior without any such overt indication of which extensions
are in use for a given object.
The idea that the file in which code is written would somehow determine
this type of runtime behavior seems to me to break my assumption that by
knowing an object's identity I should have all the information I need to
know about how to use it. Some of the posts earlier in this thread seem
to suggest that somehow the module where something was defined
(something --- not sure what --- maybe the object with the extended
method? maybe the extended method itself?) would somehow get a hook to
override attribute access on some objects (again, not sure which objects).
That to me is the exact opposite of encapsulation. Encapsulation means
the object itself contains all its behavior. If there is some
getattr-like hook in some other module somewhere that is lying in wait
to override attribute access on a given object "only sometimes" then
that's not encapsulation at all. It's almost as bad as the infamous
COME FROM statement!
Existing mechanisms like __getattribute__ are not parallel at all.
When you know an object's identity, you know its MRO, which tells you
all you need to know about what __getattribute__ calls might happen.
You don't need to know anything about where the object "came from" or
what file you're using it in. But it seems with this proposal you would
need to know, and that's kind of creepy to me.
--
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is no
path, and leave a trail."
--author unknown
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/python-ideas@python.org/message/7P6L36H2LADAZF2ZV7MZO5QSITD3I7GZ/
Code of Conduct: http://python.org/psf/codeofconduct/