Can you publicly alias a private type?
Nick Sabalausky
a at a.a
Tue Jun 21 18:05:56 PDT 2011
"Trass3r" <un at known.com> wrote in message news:op.vxf267mf3ncmek at enigma...
> Or more precisely to disallow instantiation by the user and only provide a
> finite set of (nicer) methods.
Yea. I did something similar in an early draft of the "Dynamic Fallback"
example in my contest article (
http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/#part6-4 ).
In the final version, I ended up defining the DynamicGizmo separately from
the compile-time-configurable Gizmo, because in that particular case, it
just happened to work out a little cleaner that way. But, as I said in the
article, "It would have also been possible to use a single definition for
both the metaprogramming Gizmo and the DynamicGizmo...Doing so would
probably be a good idea if only part of your struct is affected by the
change from runtime options to compile-time options."
And that's exactly how I originally had it in an earlier draft:
// Gizmo Implementation
struct GizmoImpl(bool isDynamic, int _numPorts, bool _isSpinnable)
{
/+ ...snipped... +/
}
Basically, if isDynamic is true, then it uses ordinary member variables for
numPorts and isSpinnable instead of the template parameters.
But since numPorts and isSpinnable are *only* applicable if isDynamic is
false, that makes the interface a bit funky. Very funky, in fact, if you
consider that GizmoImpl!(true,2,true) and GizmoImpl!(true,3,false) are
separate types even though, semantically, they're supposed to be the same
(since the last two params are not supposed to be applicable if isDynamic is
true). So I cleaned up the interface like this:
// A few convenience aliases just to clean up GizmoImpl's funky parameters:
template Gizmo(int numPorts, bool isSpinnable)
{
alias GizmoImpl!(false, numPorts, isSpinnable) Gizmo;
}
alias GizmoImpl!(true, int.max, false) DynamicGizmo;
Clearly, the intent is that actual users should only use Gizmo and
DynamicGizmo (*especially* if they want a dynamic gizmo). GizmoImpl is just
a private implementation detail that's only there so the two
publically-visible types can share the same definition.
This was just a one-module example, so I didn't make anything private, but
if it were a real library module, then naturally you'd want GizmoImpl to be
private and the aliases to be public.
My Goldie parsing library makes heavy use of the same basic idiom for its
"static-style" Token types ( See
http://www.semitwist.com/goldie/APIOver/StatVsDyn/#Types and
http://www.semitwist.com/goldie/APIOver/AmbiguousSym/ ). It has a few
private "implementation" classes that, by necessity, aren't the most
user-friendly (a big part of the issue is that, due to the nature of
templates and classes, there *must* be a one-to-one mapping between the
arguments to the templates and the actual resulting types). But then it
exposes various public templated aliases to provide a clean, flexible system
for referencing the implementation types.
Another good use of access-expanding aliases was brought up by someone else
in the last discussion we had about them. Suppose you want to privately
import a module, but you want one of its symbols to be publically imported
(maybe under an alternate name). Sure, you could probably do something like:
import std.stdio;
public import std.stdio : echo = writeln;
But it's reasonable to expect that this would achieve the same thing:
import std.stdio;
alias writeln echo;
And I suspect the alias method might be more flexible for metaprogramming.
For instance, if you wanted to use metaprogramming to determine *which*
symbol to publically import (which I can imagine could be a nifty trick).
More information about the Digitalmars-d
mailing list