tags:

views:

356

answers:

5

Okay, this question has evolved a bit, and I want to try to start (over) with the basic goals I'm shooting for:

  • Create library code that wrappers legacy C-language entities in C++ resource acquisition is initialization and also provides basic or better exception guarantee.
  • Enable clients of this code to use it in a very natural C++ fashion w/o creating a lot of overhead to existing code to convert it to use the C++ wrapper objects (i.e. automatic conversion to appropriate legacy types, constructors that take legacy types, etc.)
  • Limit the namespace impact of the library code. Ideally, The library would have several sub-namespaces that provide related functionality that limit the volume and impact of using namespace X type declarations - much as the boost libraries do (i.e. use of details namespaces to only inject those symbols that the user would reasonably want to use, and hide those that are implementation details; also limit the extent of possible new meanings to existing symbols, to avoid surprising implicit conversions within user-code)
  • Require that clients explicitly ask for those parts of the library that they actually want to inject into their code base. This goes hand in hand with limiting the impact of inclusion of the the library's headers. The client code should have a reasonable level of control over which parts of the library are going to be automatically used for name-resolution when they compile their code.
  • My own library code should not have to be riddled with refactor-brittle code constructs. It would be ideal if the library's headers didn't have to constantly declare private typedefs in order to have access to the rest of that section of the library. Or in other words: I want my library to be able to be written as intuitively as my clients get to when making use of said library. Name resolution should include the namespace that the library is defined within in addition to any others that have been explicitly "using'd".

I come across this scenario often, and am looking for a better way...

I have a class, C in namespace N. C has a member, Free. It free's something that C manages, and allows C to manage a new thing.

There are several global Free functions. There are also a few helper functions in the same namespace N as C, one of which is a helper that free's the thing managed by C, named free.

So we have something like:

namespace N {

void free(THING * thing);

class C
{
public:
  ... details omitted...
  free()
  { 
    free(m_thing); // <- how best to refer to N::free(THING&)
  }
}

} // namespace N

I could use N::free(m_thing). But that seems unfortunate to me. Is there no way to refer to that which is outside the class scope but without resolving absolute namespace (a relative one step out scope-wise)?

It seems to me that having to name N::free is obnoxious, since you wouldn't have to if this were a free-standing function. Nor would you need to if the class's method name happened to be different (e.g. dispose). But because I've used the same name, I cannot access it without having to specify what amounts to an absolute path - rather than a relative path - if you'll indulge me the analogy.

I hate absolute paths. They make moving things around in namespaces very brittle, so code-refactoring becomes much uglier. Plus, the rules of how to name things in function bodies becomes more complex with the current set of rules (as I understand them) - less regular - inducing a schism between what one expects and what one gets as a programmer.

Is there a better way to access free-standing functions in the same namespace as a class without having to absolutely name the free-function absolutely?

EDIT: Perhaps I should have gone with a less abstract example:

namespace Toolbox {
  namespace Windows {

// deallocates the given PIDL
void Free(ITEMIDLIST ** ppidl);

class Pidl
{
public:
    // create empty
    Pidl() : m_pidl(NULL) { }

    // create a copy of a given PIDL
    explicit Pidl(const ITEMIDLIST * pidl);

    // create a PIDL from an IShellFolder
    explicit Pidl(IShellFolder * folder);

    ...

    // dispose of the underlying ITEMIDLIST* so we can be free to manage another...
    void Free();
};

So ITEMIDLIST* come from a variety of places, and are destroyed with CoTaskMemFree(). I could introduce Pidl as a global name - as well as all of the helper functions in the "Windows Shell.h" header that is part of my toolbox library.

Ideally, I would segment some of the tools in my library by what they relate to - in this case the above all relates to COM programming in Windows. I have chose Toolbox as the base namespace for my libraries stuff, and was currently thinking I'd use Toolbox::Windows for very windows-y functions, classes, etc.

But the C++ namespace and name-resolution rules seem to make this very difficult (hence this question). It makes it very unnatural to create such segmentation of my code - since koenig lookup fails (since ITEMIDLIST is not in my Toolbox::Windows namespace), and I don't have the ability to move it there! Nor should I. The language should be flexible enough, IMO, to both allow for extension libraries such as my Toolbox library to extend other folks code without having to inject my extensions into their namespace (which, in the case of Win32 and the general vast majority of code that exists today, is the GLOBAL NS - which is the whole point of making namespaces in the first place: to avoid global NS crowding / pollution / ambiguity / programming surprises).

So, I come back around to, Is there a better way to do this: Extend existing libraries of code while not polluting their NS with my extensions but still allow for intuitive and useful name resolution as one would expect if my code were in their NS but explicitly introduced by the client of my code (i.e. I don't want to inject my code willy-nilly, but only upon explicit request)?

Another Thought: Perhaps what would satisfy my above criterea would be if I had the following:

using namespace X {
  code here...
}

Where I could place such a construct anywhere, including in a header, and I would not have to be concerned about dragging X into my client's code, but I would have the same freedom to write my source code as I would if I were in the root namespace.

+4  A: 

You have two options:

  1. Fully qualify function name.
  2. Let Koenig lookup do the job (if THING belongs to namespace N).

I'd choose the first one with such popular function name as free.

Alternate option is to use m_thing->Release() or something like that.

Kirill V. Lyadvinsky
I was wondering if Koenig Lookup would actually do the job, don't you have the risk of `MyClass::free` hiding `N::free` during lookup ?
Matthieu M.
Only if `MyClass::free` has the same number of arguments as `N::free`. In that case it will not hide, call will be ambiguous and you'll get an error message.
Kirill V. Lyadvinsky
Koenig lookup is exactly what I want. Unfortunately, as is very often the case for me, THING is NOT defined in namespace N. It is in the global namespace, provided most often by Microsoft (but sometimes another library vendor), and because it is a crufty C-struct or bald pointer, I am trying to create a wrapper class to manage the underlying object's lifetime. So it seems that I can create a free(ITEMIDLIST*) for example, but only if I put it in the global namespace will it be found. And as MattM indicates, even then it will be hidden by the class's member: I have to use ::free(thing) :(
Mordachai
In the OP's question `MyClass::free` has no arguments, but it could be changed. That's why I prefer to fully qualify function name in this case.
Kirill V. Lyadvinsky
@Kirill - maybe if C, THING and free(THING) are in the same namespace they wouldn't be hidden by C::free(). But unfortunately, THING is global (or proprietary vendor namespace), and C and free(THING) I wish to have placed in Toolbox::Windows namespace. Must I move all that code into the global namespace to make this work?!
Mordachai
A: 

Yuu could write ::free(m_thing);. This will call the global free() function. However, if you have another free() function outside the N namespace, you've got yourself into trouble. Either change names of some of your functions or use the function name with explicit namespace.

Alex
-1 free is in the N namespace. I am hesitant to put free(THING) in the global NS to avoid injecting free-function polymorphism into my client's code w/o some level of control (say, having to force them to say "using namespace XYX" or "using XYZ::free". At this point, I know that they really do want free(THING) to be injected into their compilation unit, and its reasonably likely that they won't be surprised.
Mordachai
A: 

I would use a completely different approach to what you are trying to accomplish. I think you need a bit of redesigning. Remove the globals and make a factory/abstract factory that will fabricate (create an instance of your class) and destroy it with the destructor. In fact, that would be the RAII idiom.

Partial
That's a good idiom. But like MFC code, I am trying to extend the environment to allow interaction between the raw OS defined THING and a smart helper class C (in my example). THING is already created in various ways by the OS. And it is to be destroyed using a mechanic defined by the OS. I just want a wrapper class that hides these details and makes usage of THING natural and very-unlikely-to-leak.
Mordachai
What is THING exactly?
Partial
I have extended my question to hopefully clarify what I'm trying to accomplish, and also with a 2nd more-concrete example (THING is an ITEMIDLIST*)
Mordachai
A: 

It seems to me that there is a problem of design here.

I find strange to have the same identifier used both as a free-function and a class method, it really is confusing. I try to minimize the occurence as much as possible, although I admit that it happens for swap...

I try not to qualify the names within the method, but here of course you run the risk of hiding, where MyClass::free hides the N::free method, which never participates in the lookup... tried to find about the scope resolution here but could not find the exact passage.

For swap I simply use:

class MyClass
{
  void swap(MyClass& rhs)
  {
    using std::swap;         // Because int, etc... are not in std
    swap(m_foo, rhs.m_foo);
    swap(m_bar, rhs.m_bar);
  }
};

inline void swap(MyClass& lhs, MyClass& rhs) { lhs.swap(rhs); }

Therefore I make sure that the right method will be included in the lookup, and avoid falling back on a 'global' method if any.

I prefer this approach to explicit naming and usually bolts using and typedef declaration at the top of the method so that the actual code is not bloated.

Matthieu M.
Yes, the problem is that THING is really a C-language entity, and not really a C++ one. I am trying to provide a wrapper for the crummy C-thing and make my wrapper work with the C++ rules to allow great ease of use while not introducing surprises for my clients, and not having to write brittle code in my headers.
Mordachai
Wrapping C in C++ is often messy, it's very commendable of you though, so I'll wish you good luck! I wish all the other developers cared so much about their clients!
Matthieu M.
+5  A: 

I don't see to avoid having to qualify namespace-scope free() here, but it should be noted that this is not the same as an "absolute path". For one thing, if you have nested namespaces, you only have to refer to the innermost one:

namespace N1 {
  namespace N2 {
    namespace N3 {
      void free(THING * thing);

      class C {
      public:
        free() {
          N3::free(m_Thing); // no need to do N1::N2::
        }
      };
    }
  }
}

[EDIT] in response to edited question. Again, I do not see any way to do this in the exact scenario that you describe. However, it doesn't seem to be idiomatic C++ approach - the more common way to do the same is to provide your own wrapper class for ITEMIDLIST that manages all allocations, RAII-style, and exposes the original handle (e.g. via conversion operators a la ATL, or an explicit member function like c_str() if you want extra safety). That would remove the need for your free altogether, and for any other free function that you might want there, since you control the wrapper type and the namespace it's in, you can use ADL as usual.

[EDIT #2]. This part of the question:

allow for intuitive and useful name resolution as one would expect if my code were in their NS but explicitly introduced by the client of my code (i.e. I don't want to inject my code willy-nilly, but only upon explicit request)?

Isn't this precisely what you putting it in a namespace, and your client writing using namespace ..., will achieve?

Pavel Minaev
Woot! I learn something new everytime I ask questions here. Thanks Pavel. If you haven't already, would you take a look at my updated question, and see if you have any insight on the bigger issue at hand (selectively introduce polymorphic free functions into client code and the ability to do so for my own classes, even in my headers, w/o polluting client code)
Mordachai
I've updated the answer.
Pavel Minaev
Thanks again. And as to edit #2 - yes, that is what I want. I know that putting my code in its own NS achieves this. But the draw-backs to using my own NS is that koenig lookup fails (is that what ADL is?) for class-member-to-free-function-lookup, as per my original question. So how to provide the advantages of forcing them to explicitly include my NS, while not having the draw-backs of name-resolution headaches in my code?
Mordachai
Good answer. If you're going to wrap, do it like you mean it. I've done this before to use POSIX APIs in a more C++-ish way. Better not to expose the underlying C-cruft at all. Or if you must, do it with some kind of accessor function (e.g., c_str()) to allow the caller to do crufty C-style things to it.
Dan
@Mordachai, ADL is argument-dependent lookup, aka. Koenig lookup. But ... what is ATL? typo?
Dan
ATL is one of Microsoft's template based helper-libraries (it was originally a COM centric framework, but has since been somewhat merged with MFC, so that they both use common elements of the other, while leaving it to the consumer to choose to go whole-hog into more MFC or ATL specific directions).
Mordachai
@Pavel - as to not being idiomatic C++ to supply both the free-standing functions as well as a wrapper class... I find that in practical programming there are times when you have the raw THING and are not responsible for its lifetime, or you are responsible but the responsibility is simply to immediately free it, and no more. Times like those, where invoking the creation of a wrapper object is wasted overhead muddies the issue, rather than clarifying it. This is often true in Win32 programming, because a message will return a ITEMIDLIST* that you don't own, but must manipulate, e.g.
Mordachai
Mordachai
Mordachai
"I find that in practical programming there are times when you have the raw THING and are not responsible for its lifetime, or you are responsible but the responsibility is simply to immediately free it, and no more." - if you have responsibility to free it, then that alone is good enough reason to wrap it (if you ever need to have more than one such member in a class, you'll need the wrapper anyway to have exception-safe release).
Pavel Minaev