It sounds like many would agree that renaming some things could have many benefits, but the cost seems to be higher than I imagined.
What if an easier way could be created to manage renaming that avoided many of these problems?
Perhaps aliases of objects could be something worth baking into the language itself. I don't mean having multiple names pointing to the same object as we can do today, but something new entirely.
*THE FOLLOWING IS PROBABLY A CRACKPOT IDEA*, hear it out of you are in the mood to humor me on this Saturday morning.
What if the __dict__ for modules and classes could be something like a ChainMap, with multiple internal lookup mappings. The first level (by which I mean, the first mapping consulted) would be the same as exists today, but the second would contain a weak value dictionary with aliases pointing to objects so that when you do json.load_str, it returns json.loads object just like it would if you had added the alias in the way you would today. But the dict is weak value so that if an object is garbage collected, its alias entries are removed.
So the second mapping would be a so called "alias dictionary".
How could this be done to overcome some of the same objections raised?
*First, regarding discoverability: *
dir() would work identically to as it does today, but you could give an argument to also provide aliases, something like:
['JSONDecodeError', 'JSONDecoder', 'JSONEncoder', '__all__', '__author__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', '_default_decoder', '_default_encoder', 'codecs', 'decoder', 'detect_encoding', 'dump', 'dumps [dump_str]', 'encoder', 'load', 'loads [load_str]', 'scanner']
Note that when you tell dir() that alias=True, additional aliases for objects are added to the output in the form of a string-ified list.
Also change the default object repr so that it says something like:
<function loads (alias: load_str) at 0x.... >
The help() could be modified to be something like:
Help on function loads in module json (alias: load_str): ...
*Second objection: "people are going to be confused because now they will ask 'What is the difference between these TWO functions, or between these TWO methods?'":*
There are no longer "two different functions/methods". Since aliases are something baked into the language, both new and old folks would need to learn to be GENERALLY aware that they exist, and there will need to be an easy way to retrieve the aliases for an object. So there's a big new thing to learn there.
But once that exists, it mostly becomes a single point of learning.
People would still periodically see the different names in code and ask the question "what's the difference" of course, but the answer would change. Instead of simply "oh it is the same function with a second name", the answer would be "those are a thing called python aliases; here is a link to the docs talking about how to find aliases". The docs for the object would also list aliases (if there are any). However I dare say you'd probably get this question less often because of the repl output I am suggesting above.
*Third objection: it polluts the namespace.*
It still would do this to a degree, but I think in a more tolerable way.
Most importantly, it seems like it would be preferred for * importing everything from a module to import only the first level dictionary and not all the aliases. Additionally, you can still add or monkeypatch new objects into a namespace (they would go into the first level dictionary, therefore overriding any aliases in the second level). Beyond that, since I'm talking about something new baked into the language, the code writing tools would be updated to know about aliases and provide useful auto complete functionality that makes it clear this is an alias.
But yes, of course I knowledge there would definitely be the possibility of bugs created by an accidental typo that happened to also be an alias.
*For convenient addition of aliases and discovering them for a specific member: *
There are likely all sorts of ways you could do this. Perhaps a dunder alias combined with an alias decorator could be added (probably in functools? not top level)?
You could add an alias like:
@functools.alias("load_str") def loads(...): ...
assert loads.__alias__ == ["load_str"]
class MyClass: @functools.alias("prof") def process_file(self, ...): ...
assert MyClass.process_file.__alias__ == ["prof"]
I'm sure this is an extreme idea and likely nobody is going to be interested. But I started writing it and couldn't stop.