On Feb 3, 2020, at 10:25, Andrew Barnert
This is the same as Smalltalk, ObjC, Ruby, f-script, and all of the other languages that use the same dynamic type/data model as Python. And Smalltalk was the first language to have practical refactoring tools (although I don’t think they were called that until Ralph Johnson’s refactoring object browser in the early 90s).
One difference between Python and most of the other Smalltalk-model languages is that they use symbols or selectors or some other string-like type to name methods, while Python uses plain old strings. If you have print(:bar, foo.bar) obviously bar is the name of an attribute rather than normal text. Dropping selectors from the language turns out to cause a lot fewer problems than any Smalltalk devotee would have believed, just a few very small problems—like the one nameof is trying to fix.
Meanwhile, unlike Smalltalk and most other languages with the same model, Python has optional static typing. The other major Smalltalk-model language that added optional static types is ObjectiveC—and one of the reasons was to improve the navigation and refactoring tools. For example, if you have a function that takes a `foo: Any` param (spelled `id foo` in ObjC) and there are three unrelated types that all have a `bar` method, the tool will tell you that it’s ambiguous which one you meant by `nameof bar` (spelled `@sel(bar)`), and it can suggest that you either specify a type for `foo`, or create an implicit ABC (a `@protocol` in ObjC terms) to own the method. If you do the first, renaming Foo.bar to baz will change the selector; if you do the latter, it will warn you that Foo.bar makes Foo conform to the Barable protocol that you defined and there are selectors in your program that depend on it being Barable, so do you want to break that or do you want to rename Barable.bar and all of the classes that implement it instead? If you do neither, it doesn’t guess, it tells you that there are two ambiguous uses of the selectors and lets you see the two uses of the selector or the three classes that define it, so you can proceed manually.
Of course this means that an IDE, object browser, or standalone refactoring tool has to build a mapping from selector names to a list of implicit uses, explicit uses, and definitions (including knowing which definitions are inherited, and which are relied on by protocols) for the whole program. But that’s exactly what they do. That’s why RJBrowser takes a while to start up, and why Xcode is constantly running clang on bits of your code in the background as you edit.
Couldn’t a Python tool just also keep track of every string and substring that has at least one match as a use or definition of an attribute? Yes. But I think it’s obvious why this is a lot more work and at least a little less useful. And that may be part of the reason Python has always had fewer refactoring tools available than Smalltalk, ObjC, etc., which is why nameof could be a useful addition.
All that being said, I’m not sure _how_ useful it would be in practice. Python has a chicken-and-egg problem that C#, ObjC, etc. don’t. If the C#/ObjC devs add a new feature to their language, the Visual Studio/Xcode team next door adds a nameof-driven renaming feature to the refactoring tools in the IDE that 90% of C#/ObjC programmers use, and then then everyone who wants that feature starts using nameof. If the Python devs add nameof, PyCharm, PyDev, etc. may not take advantage of it, and they may already have an often-good-enough heuristic-guessing feature for people who don’t use it. If not many people start using it, there will be even less motivation for PyCharm to take advantage of it, etc. If a new feature has an obvious large benefit (and/or is fun enough to implement), like optional static typing, you can jump past that hurdle. If a new feature has other uses even without IDE support, like @dataclass, you can spiral over it. But nameof is neither; it might just be a dead-on-arrival feature that’s only ever used by a handful of large teams who build their own internal tools. (And that large internal-tool-building team could just define a builtin `def nameof(x: str): return x` to use while debugging and write an install-time or import-time transformer that just replaces every `nameof(x)` with `x` to eliminate the deployed runtime cost.) Add in the fact that most people use the newest version of C# or ObjC for any new project, while Python developers often stay a version or 3 behind, and a breaking change like this would probably need a __future__ and/or deprecation schedule on top of that, and the problem looks even worse. So, someone who wants this feature has to not only resolve all the confusion over what exactly is being proposed and how it helps, but also make the case that Python tools and Python programmers are likely to actually take advantage of it.