I've observed another meta as well: IDEs/language servers.
I was writing a Wordpress plugin and by default in PHP all function definitions are global, e.g. is_single that WP defines is global. Naturally to avoid conflicts you would use a namespace, but since most of the examples I saw used prefixed function names, I decided to try that as well.
In my opinion, coding just feels much clearer when you prefix all your names, like my_library_my_func. When I see my_library_, I just immediately know that is my code. If you use different prefixes for different modules, you can tell from a glance which modules a piece of code interacts with. In C++, you can tell a random word is a field by the simple fact everyone prefixes them with m_. I've seen people using prefixes for pointers as well.
This is the same concept you have when designing an UI. Everyone agrees a problem with hamburger menus is that you don't know what's inside the burger until you click on it. If you want people to be aware something exists, you need to make it appear on screen, explicitly.
Instead, languages have evolved toward the very opposite. We ran away from self-documentating variable names and prefixes, and toward namespaces, "const" and other keywords, and "OOP" that feels less object-orientated and more press-the-dot-key-to-get-a-list-of-methods orientated. We depend on docstrings that show in the IDE, and then on auto-generated documentation from those docstrings. Typescript is probably the worst case of this, because it gives you a lot of tools to make the dot work the way you want, you'll spend way too much tinkering with the dot instead of just writing code that actually runs.
Thanks to this, when you look at code, you have to wait until your language server figures out what you're looking at for you. If the IDE doesn't work, it's effectively impossible to code anything in many cases. But the variable names are shorter so people think it's cleaner and better, like removing features from an UI to make it cleaner.
A language where every definition is global is the worst starting point imaginable. Of course, solutions to that will remain severely lacking. Prefixed variables as you propose were abandoned for good reason.
Perhaps give Rust or Python, maybe Go a spin, and see how they do namespaces, imports and such. I find that mostly sane and readable, as they retain the full chain of custody (you can always trace where a symbol comes from by its qualification or import statement, unlike in less sane ecosystems such as C/C++/C#/Java, and apparently the insane version PHP uses).
Modern C# is a lovely language overall but I think OP talked about the module system where the more explicit approach of Python is arguably better.
When dealing with C#, if you’re browsing code un anything less than a IDE it can be really hard to find where a symbol comes from. And that is if the author was nice enough to use one folder per namespace, otherwise it becomes a nightmare.
In case of external references, most of the time, you do not need to browse the source files - that's something you reach for if inline documentation and type system are insufficient. Arguably much more of an issue in dynamically typed languages, yes.
Although even source browsing is now easy - you just press F12, and packages come with sourcelink integrated automatically (previously you had to rely on IDE to resolve symbols or decompile it from IL (readable but not perfect, Rider did and still does it really well)).
Navigating the solution itself does not differ significantly from Rust and its crate system. People usually structure the code by projects and folders, sometimes aggregating multiple types in a file (because you don't need a separate file per a couple of 4 line class declarations) sometimes not but I generally find the structure way more browsable than e.g. what a typical TypeScript project looks like. The regular symbol navigation rules apply - F12, Shift+F12 and friends.
In Rust, Python and Go you can trace every symbol back to its source by just reading source code. `cat file` would suffice.
In C#, that’s impossible by design, as you say. C# imports work like wildcard imports in Rust and Python, which are wildly frowned upon for very good reason (except for specific cases like preludes in Rust).
I was writing a Wordpress plugin and by default in PHP all function definitions are global, e.g. is_single that WP defines is global. Naturally to avoid conflicts you would use a namespace, but since most of the examples I saw used prefixed function names, I decided to try that as well.
In my opinion, coding just feels much clearer when you prefix all your names, like my_library_my_func. When I see my_library_, I just immediately know that is my code. If you use different prefixes for different modules, you can tell from a glance which modules a piece of code interacts with. In C++, you can tell a random word is a field by the simple fact everyone prefixes them with m_. I've seen people using prefixes for pointers as well.
This is the same concept you have when designing an UI. Everyone agrees a problem with hamburger menus is that you don't know what's inside the burger until you click on it. If you want people to be aware something exists, you need to make it appear on screen, explicitly.
Instead, languages have evolved toward the very opposite. We ran away from self-documentating variable names and prefixes, and toward namespaces, "const" and other keywords, and "OOP" that feels less object-orientated and more press-the-dot-key-to-get-a-list-of-methods orientated. We depend on docstrings that show in the IDE, and then on auto-generated documentation from those docstrings. Typescript is probably the worst case of this, because it gives you a lot of tools to make the dot work the way you want, you'll spend way too much tinkering with the dot instead of just writing code that actually runs.
Thanks to this, when you look at code, you have to wait until your language server figures out what you're looking at for you. If the IDE doesn't work, it's effectively impossible to code anything in many cases. But the variable names are shorter so people think it's cleaner and better, like removing features from an UI to make it cleaner.