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