14 ms·
Yes people have floated the idea. I argued against it, I was asked at the wg14 meeting to explain my position and the following was my reply: I was asked durin
by quelsolaar 4y ago
Yes people have floated the idea. I argued against it, I was asked at the wg14 meeting to explain my position and the following was my reply:
I was asked during the meeting why I think that name spaces are a bad idea, so here is my thoughts. I must warn you that the following may sound like an anti C++ rant, because well .... it is.
Name spaces have several bad aspects. The majority of them are that they make the code a lot less readable.
First, If I see a function call in source code, I cant assume what function is called. There may be a namespace somewhere above or in a header-file somewhere that changes the meaning of the code. It matters a lot for instance when you copy code from one file to another, and all of a sudden the code just means something completely different. Name spaces add state that changes the meaning of the code around it. When your code isn't doing what it should and you are trying to figure out why, you need to be able to trust that the code you are reading on screen is actually what you think it is. I dislike it for the same reason i dislike overloading: it makes it less clear what things you are reading really are.
(It may be argued that you already cant trust your eyes in C, because you can do lots of devious things with the per-processor, and to that I say, yes its bad enough, so lets not add more of it)
Name spaces splits the identifier in half, but its still a unique identifier.
my_module::create();
is and has to be as unique as:
my_module_create();
So what are we accomplishing? Do we have the same level of collisions? No, in fact we have more collisions because the parts can collide individually! if there are multiple my_module they will collide, and if there are multiple create in different namespaces they will collide!
my_module::create(); // one name space
my_module::destroy(); // another name space
Collision! how about:
using namespace my_module; // namespace with a create
using namespace my_other_module; // namespace with a create
crate();
Collision! If we instead write plain old C:
my_module_create();
my_module_destroy();
No collision.
my_module_create();
my_other_module_create();
No collision.
Beyond creating new opportunities for collisions, we create confusion by making it possible to hide half the identifier somewhere else. Yes, it can save some typing, but programing is never hard because of typing, programing is hard because its hard to understand what is going on. Namespaces solves the easy stuff, by making the hard stuff harder.
Its the age old, trap of C++ of adding something clever out of convenience, that turns out to be unclear and something that the programmer has to manage.
Further, namespaces encourage people to use short common names even further, because they think it saves them typing, and they think if it goes wrong they can always manage it with namespaces, and then they end-up having to manage something they shouldn't have to manage in the first place.
I have never had a namespace collision in 20+ years of C programming. Why? Because I use long descriptive names, that always start with where the functionality resides. Its readable, straight forward and works. Namespaces is a complicated system for managing a problem that should never happen in the first place, unless the user is very careless. We should not encourage carelessness.
I think C, should take some blame for this being a problem because the standard library have far shorter names then is advisable. It has made people think that names like: "jn" or "erf" are good examples of unique, clear and descriptive naming. The added wrinkle of "significant characters" has made people think that C mandates short names, something that no major implementation requires. There also seems to be a persistent belief that display technology has not yet evolved to the level that we can display more then 80 characters per line and that we therefor need to use short cryptic names for everything. This is also an argument from a different age.
Namespace collision in C almost never happens between 3rd party libraries, it is almost the exclusive problem of the standard library because it is so poorly named. If we want to fix this, by hiding the standard library behind a namespace, we might as well just add a c_standard_lib_ prefix to all functions, and keep the garbage that is namespaces out of C. Not that we would do either, since both world break backwards compatibility. So why would we add namespaces if it wouldn't be used by the standard lib, the very library we have name collision problems with? In fact if we added an optional namespace for the standard lib, all we would accomplish is to pollute the namespace with one more identifier.
- jstimpfle 4y agoI agree with everything you say but want to add a caveat to the "long descriptive names". I find that there must be a balance where names are clear and unique enough while not tiring the eyes too much by making them read long boring repetitive prefixes all the time. There is a fine art to creating words and also sentences (statements). By now if a "module prefix" is bigger than say 4-5 characters, I get unhappy and know I need to improve, to find a short mnemnonic. Same goes for local variables names, which I try keep at 1-5, rarely they get 10+ characters long. There is always this tension between names being "self-documenting" and "just long enough to remind of the purpose that was explained in a not too distant context". Variables that are frequently used should be shorter. Variables that have a clear intuitive use (like "x" or "i" which most often have very clear meaning with only little context added) should be shorter. Module names should _always_ be very short because (I assume) there are only few modules, and it's better to remember the purposes of a few modules together with their abbreviated names, than to have to read a long repetitive module name each other line. Function name suffixes (without the module prefix) should often be long because there are many different functions and not all of them can be cached with their meanings in the programmer brain - so I allow function names to be a little self-documenting typically. I agree that the names in POSIX and C are too short and cryptic but think they made more sense in the context of Unixes of the 1970s when projects weren't as big as today. I still try to stay within 80 or 100 columns because line length a readability / eye strain concern as well, but given that I'm in the 8 spaces camp I don't freak out anymore if there is the occasional 140 characters line and I'm to lazy to trim it down. Judicious insertion of linebreaks is most often useless busywork. Then again, some function signatures take too many arguments (glVertexAttribPointer/glBufferData... or the Win32 API come to mind) and inserting linebreaks in calls can improve readability sometimes.
- AlbertoGP 4y ago> “I find that there must be a balance where names are clear and unique enough while not tiring the eyes too much by making them read long boring repetitive prefixes all the time.” I have that problem, repetitive prefixes getting in the way of reading the code, and I’ve been doing some experiments with what could be described as “local namespacing”, only inside an expression or statement, with the prefix/suffix feature of the backstitch macro in my C preprocessor: https://sentido-labs.com/en/library/cedro/202106171400/#backstitch-macro https://sentido-labs.com/en/library/cedro/202106171400/#back... For instance, writing a program with libxml2, I write: Next(reader) @xmlTextReader...; which gets translated to xmlTextReaderNext(reader); and I find the first easier to read. Whether that’s the case for others, I don’t know. A longer example from the link I wrote above, this time for libuv: @uv_thread_... t hare_id, t tortoise_id, create(&hare_id, hare, &tracklen), create(&tortoise_id, tortoise, &tracklen), join(&hare_id), join(&tortoise_id); Result: uv_thread_t hare_id; uv_thread_t tortoise_id; uv_thread_create(&hare_id, hare, &tracklen); uv_thread_create(&tortoise_id, tortoise, &tracklen); uv_thread_join(&hare_id); uv_thread_join(&tortoise_id);