You are right that there are many things to consider, and I too don't know what the right answer is. I was more interested in the challenge of doing it. Like I said this is only a demo, and would probably need consideration of things like this. I had thought of the dict/list thing, and as you say it will work one way if the setself var is in a dict, but in if x =[Foo()]; x="hello world", would reassign the list. I dont know what the the least surprising thing would be, and it would strongly depend on how deeply someone thought about what is actually going on. What is not surprising at surface might be more surprising to someone more experienced or vice versa.
It is true that fastlocals gets called in functions and so this is not respected, I didnt look into what it would take to change this, as was not ready to go down the rabbit hole as it were.
I myself am of two minds on this, as I can see some cool things I or others could do with this, but also new limitations and or confusion. It would need to be very well publicized if it were a new feature, and probably come with some builtins to for instance check if a type implements this.
On Fri, Jun 21, 2019 at 5:10 PM Andrew Barnert email@example.com wrote:
On Jun 20, 2019, at 13:25, nate lust firstname.lastname@example.org wrote:
There is nothing more humbling than sending nonsense out to an entire mailing list.
You’re something like the 300th person to suggest overloading assignment, but the only one of that 300 willing to think it through, much less create a patch. That’s hardly something to feel bad about!
Thinking about things the right way around, I dug in to the interpreter an hacked something up to add an assignment overload dunder method. A diff against python 3.7 can be found here: https://gist.github.com/natelust/063f60a4c2c8ad0d5293aa0eb1ce9514
There are other supporting changes, but the core idea is just that the type struct (typeobject.c) now has one more field (I called it tp_setself) that under normal circumstances is just 0. Then in the insertdict function (dictobject.c) (which does just what it sounds), post looking up the old value, and pre setting anything new, I added a block to check if tp_setself is defined on the type of the old value. If it is this means the user defined a __setself__ method on a type and it is called with the value that was to be assigned causing whatever side effects the user chose for that function, and the rest of insertdict body is never run.
Intercepting this at the namespace’s dict rather than at the store op is a really clever idea, and it seems like it should avoid the major performance hit as well. But I have a few questions.
Does assigning a local variable actually call dictinsert anywhere? There is a locals dict, but I believe it’s only created and kept up to date with the fast locals array if you ask for it.
What about other namespaces that aren’t dicts, like attributes of __slots__ classes?
What about dicts that aren’t namespaces? For example, will x[y] = z call __setself__ on x[y] if x is a dict, but not if it’s a list (and if it’s a SortedDict it may or may not depending on internal details of how that’s implemented under the covers)?
Will x += y call __setself__(self) after the __iadd__(y)?
I’m not entirely sure what the right answer is for all of these situations. And that might depend on how you describe this protocol in the docs (the name “setself” doesn’t necessarily imply the same thing as “overloading assignment”).
-- Nate Lust, PhD. Astrophysics Dept. Princeton University