Behavior can change when functions, methods, and operators are imported when a new "using namespace" line is added possibly leading to an import being bound instead of a preexisting function, because of the prioritization implicit in overloading / polymorphism.
(Some of the toughest bugs to find in this area have involved templates. Templates in libray Lib1 using a naked name such as foo(T1,T2), that are used in Lib2, and whose naked name foo gets bound to something in Lib3... up until the time Lib4 is imported via "using namespace", at which time it gets changed.)
I spouted the standard reason not to allow "using namespace". But I hate myself for doing so, since I find code that is cluttered up by std:: ugly to read.
So of course I try to think about what the real problem is.
The real problem is that some names, functions, operators, methods match multiple prototypes in different libraries. And the match chosen may change in major ways with minor edits (or, possibly even worse, in minor ways with minor edits).
So, let's look at these one at a time:
First, some names, functions, operators, methods match multiple prototypes in different libraries.
(1) Surely the compiler could compare namespaces, and warn the user about names that might possibly conflict - that might possibly be coerced to different instances in different modules/libraries/namespaces. (Heck, I think that such an ability might be useful even inside the same library/module/namespace.)
(2) Specifically, perhaps an given use of a name that is remapped via overloading/polymorphism could warn if there was more than one possible mapping? Especially if in separate libraries/modules/namespaces?
Second, the match may change:
(3) Perhaps the editing/build system could record which overloading is applied at every point in the source code. And warn when it changes.
Like so much source annotation, this would have to be resilient across edits. But, that's what patch, and so many VCS, do. Heck, it would even be useful if only inexactly resilient across edits - if there was just a table of source module/name -> dest module/instance mappings, and that was diffed.
1 comment:
Could this issue be handled (or its problems reduced) by better development tools which reduced the visual impact of (possibly hid) the qualifier? E.g., the developer might see [glyph-representing-std::]variable_name or [glyph-representing-non-local-namespace]variable_name or font or color might be used to indicate that there is qualifying information.
The fully qualified name could be revealed to the human reader and would be available to the compiler.
(To be practical, it seems that such would require a form of autocompletion in the development tools.)
(From the little I have read, development tools which indicated something of the implied nature of some C++ statements could be useful.)
Side thought: I wonder if it would be useful to extend namespace assignments to include a namespace aggregate. E.g., "namespace tools = { power::screwdriver, manual::hammer, power::drill, manual::file, manual::saw};" would collect these names into a single group. For a simple implementation/semantic (where no 'tools::' qualified identifier would need further qualification), it would probably be difficult for the programmer to develop useful aggregates (but such might be easily added to C++). A more complex implementation might allow reduced qualification such as 'tools::screwdriver::', but such would only be useful if there was a substantial hierarchy of namespaces.
Well, that's a lot of blah, blah, blah. Anyway, thanks for bringing me to think.
Post a Comment