Attempting to find a compromise between the constraints of a facade that wraps a system API, the limitations of a limited namespace naming scheme, and a user wanting more expressiveness, revealed an interesting compromise in design.
This uses the winstl::reg_key class, which is actually a typedef to a specialisation of
winstl::basic_reg_key. (Like std::basic_string, winstl::basic_reg_key
can support different character encodings. Thus, winstl::reg_key is a typedef of
here for more details.)
The problem with the above statement, from the perspective of our user, is that it does not create a key. It only
opens the key SOFTWARE\MyCompany\MyApp if it already exists. If it does exist, then an instance of
winstl::registry_exception is thrown, carrying the result code (ERROR_FILE_NOT_FOUND)
returned by the underlying Registry API call, RegOpenKeyEx().
The corresponding constructor for winstl::basic_reg_key has three parameters, as follows:
In other words, it's a whole lot of flags covering the bit-width of a DWORD. The consequence
of this is that the third constructor parameter, carrying all possible (now and future) values that
may be passed to RegOpenKeyEx(), cannot also carry an additional flag to enable creation
by constructor, as in:
The reason is simple. Whatever value we might select for a member constant/enumerator
winstl::reg_key::createKey cannot be guaranteed not to clash with Windows API constants
to be used with the Windows Registry API functions. (If you're interested, I talk about this issue
at more length in Chapter 17 of my new book,
Extended STL, volume 1: Collections and Iterators, which is
published in three weeks' time. Coincidentally.)
Given this restriction, we must look for an alternative. Our user (rightly) observed that the
following single line form, which does have the desired semantics, is syntactically unappealing:
The problem here is that, for good or ill, the use of namespaces within the STLSoft libraries is
restricted to a minimum. Specifically, elements from each of the sub-projects (COMSTL for COM components:
namespace comstl; UNIXSTL for UNIX components: unixstl; WinSTL for Windows components:
winstl; and so on) are defined within their single, top-level namespace. (If you're interested,
this is an artefact of the early history of STLSoft, wherein compilers that did not (properly) support
namespaces were supported by the libraries. If there is ever an STLSoft 2.x - we're currently at
I might seek to address this and employ library-specific namespaces. But for now it is what it is.)
Hence, as shown above, a function inserted into the winstl namespace to create a key could
not simply be named create(), or even create_key(), because that is not
specific to the registry. So, it'd have to be reg_create_key() or, as the user suggested
create_reg_key(). This option, with either name, does not appeal to me, as the function will
be ligging around the winstl namespace with other free functions. But it's not really a
free function, is it? It's actually a non-member function
that is part of the winstl::basic_reg_key interface.
The answer to this conundrum is to declare a static creator method, as in:
To be sure, it's not as expressive as the straight (opening, not creating) constructor call. But that's
actually a good thing, because it is actually doing something different and significant: creating a
key rather than opening it. Positively, it remains closely associated with the
STLSoft Windows Registry Library
despite there not being a distinct namespace for it.
For your interest, the implementation of the method is very simple:
It does look like it was an interesting conundrum. As I was reading through it, though, I was wondering what the facade really brought to the table. It looks like a rather thin veneer over the registry API.
Often when I work with teams, I suggest to them that there is a good chance that they will never use the full breadth of an API like that because it wasn't designed to cover their use case; it was designed to cover everyone's use case. What they are better off doing is creating some application specific abstraction that wraps the API. In the case of the registry, it often looks like a map. It's simple and the details of registry access are hidden from the rest of the application.
One of the benefits is better encapsulation. If you ever want to change the mechanism you use for registry-like information, you're in trouble if the API is used all over the place. Better to put it behind some application-specific API that presents only the capability you need. Today it can use the registry. Tomorrow it can persist anyplace.
Testing is another area where application-specific facades win. I don't know whether this API lets you make an in-memory registries (fakes) for unit testing classes that use it, but that's a handy feature and many APIs are quite set up to do that yet. If you make an application-specific API, it's easy to make your own.
This looks great, I didn't expect a response so quickly, much less a fix. Thank you!
I'm interested that you chose to use a public static method rather than a free functions. Your reasoning does make sense, and the resulting syntax is nice and clean, but it goes slightly against what Sutter says in "C++ Coding Standards" item 44, which is "Prefer writing nonmember nonfriend functions". He argues that if a function can be implemented without knowledge of the internals of a class, it should be, and this one definitely seems like it can be. I'm sure I've also read somewhere, possibly in one of Sutter's other books, that free functions that operate on a class can be considered part of its interface, even though they're not actual members.
On the other hand, in this case the static method has the advantage that you don't have to specify the basic_reg_key specialization when calling it. Looking more closely at my suggested solution, for it to work with any specialization it would have to be a function template which would be called like:
I don't know, I quite like the fact that winstl offers this thin veneer over the Win32 registry functions. The value they provide is to help with all of the handle and memory management that makes raw Win32 code so ugly, while still offering all the functionality you have with the raw API.
Application-specific interfaces are good too, but there's no reason why these couldn't be implemented on top of winstl -- this would undoubtedly make them easier to maintain than if they were built on raw Win32.
> I don't know, I quite like the fact that winstl offers > this thin veneer over the Win32 registry functions. The > value they provide is to help with all of the handle and > memory management that makes raw Win32 code so ugly, while > still offering all the functionality you have with the raw > API.
Well put. The message I've consistently failed to get over wrt STLSoft over the years is that it is a deliberately thin level of abstraction. One of the primary purposes of STLSoft is to support the creation of other libraries, rather than attempt to be all answers to all needs.
> Application-specific interfaces are good too, but there's > no reason why these couldn't be implemented on top of > winstl -- this would undoubtedly make them easier to > maintain than if they were built on raw Win32.
Again, well put. (Can I hire you as my marketing guru? <g>).
This is a very important aspect of STLSoft and, in my opinion, a much under-discussed factor in the design tradeoffs in the facade/adaptor design. In fact, I have been bold enough to coin a principle: The Principle of Intersecting Conformance (see http://www.stlsoft.org/doc-1.9/group__group____principle____conformance.html). This will be one of the feature concepts/principles in my next book, Breaking Up The Monolith, which I'm working on now. :-)