On Thu, Dec 01, 2022 at 03:19:38PM -0700, Anony Mous wrote:
> I'd love to hear a justification -- any justification -- against what I'm
> talking about, because to date, I've never run into one. Many have tried,
> too. :)
What is the `str` interface? Perhaps not the best example, because
strings have so many methods, but it will do. Under Python's design, we
know what methods strings have. We absolutely categorically know that if
`type(obj) is str` then we can rely on a specific interface, namely 47
methods and 33 dunders.
What is the `str` interface with monkey-patching allowed? It's
impossible to predict. The string interface depends on which methods
have been monkey-patched in.
It gets worse if we allow monkey-patching of individual instances as
well as the entire class. Now you don't necessarily know that two
strings support the same operations, even if their type is the same.
If you have a string, you don't know whether or not it will support the
TestDottedQuad method.
These are points of friction that can make the language harder to use.
How is a beginner supposed to know which methods are native to strings,
and which are monkey-patched in? Where is `str.TestDottedQuad`
implemented and documented?
If you have a class and method you are not familiar with, say
`Widget.frob()`, in a large application you don't know well, how do you
find where `frob` was added to the class? It could have come from
anywhere.
What happens if you go to monkey-patch string with TestDottedQuad and
*some completed unrelated library* has beat you to it and already done
so? Monkey-patching is safe so long as you are the only one doing it. As
soon as libraries get in the act, things go down hill very quickly.
These are not insurmountable problems. Python supports powerful
intraspection tools. Most classes that we write in pure Python, using
the `class` keyword, support monkey-patching not just the class but
individual instances as well, and it is considered a feature that most
classes are extendable in that way. We mostly deal with that feature by
*not using it*.
The Ruby communittee learned the same lesson: the best way to use
monkey-patching is to not use monkey-patching.
https://avdi.codes/why-monkeypatching-is-destroying-ruby/
So the ability to monkey-patch classes and instances is considered to be
feature of marginal usefulness. Sure, sometimes its handy, but mostly it
just adds complexity.
When it comes to builtins, the deciding factor is that the builtins are
programmed in C (in CPython, other interpreters may do differently), and
for speed and efficiency, and immutability, they usually don't include a
`__dict__` that you can monkey-patch into. The class itself may have a
read-only mapping proxy rather than a dict you can add items into.
So in principle Python supports monkey-patching, but in practice CPython
at least typically removes that support from most builtin types for
efficiency reasons. And because monkey-patching is frowned upon, we
don't miss it.
> In any case, I wanted that ability because I was doing a lot of interesting
> things to strings, and str was doing a stellar job of making that more
> difficult.
I find that implausible. You can do whatever interesting things you like
with strings, you just can't use method syntax.
You can't use `mystring.TestDottedQuad()` but you can use
`TestDottedQuad(mystring)`, which is just a change in order (and one
character fewer to type).
I suppose the one thing you can't easily do with function syntax is give
each individual instance its own distinct method. So if you have three
instances, spam, eggs, cheese, with monkey-patching you can give all
three instances their own frob() method, each method doing something
different. But that way leads to chaos.
> Again, explain a danger to a nominal class user that arises due to adding
> NEW, immutable in the current instance, functions/functionality to a class
> that do not alter the existing base functionality. ANY danger.
As I said above, that's fine when you are the only one doing it. But as
soon as monkey-patching becomes popular, and everyone starts using it,
then you have to deal with conflicts.
Library A and library B both want to monkey-patch strings with the same
method. Now you can only use one or the other. If they just used
functions, they would be fine, because A.TestDottedQuad and
B.TestDottedQuad live in separate namespaces, but with monkey-patching
they both try to install into the same namespace, causing a clash.
--
Steve
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@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/NM2F743TS4U6WIESVLZQ6MC3IWUCFKEE/
Code of Conduct: http://python.org/psf/codeofconduct/