private module stuff

Jonathan M Davis jmdavisProg at gmx.com
Sun May 8 15:03:02 PDT 2011


> On 5/8/2011 4:05 AM, Jonathan M Davis wrote:
> >> Sean Cavanaugh:
> >>> 	So I was learning how to make a module of mine very strict with
> >>> 	private
> >>> 
> >>> parts, and was surprised I could only do this with global variables and
> >>> functions.   Enums, structs, and classes are fully visible outside the
> >>> module regardless of being wrapped in a private{} or prefixed with
> >>> private.  Am I expecting too much here?
> >> 
> >> You are expecting the right thing. If you are right, then it's a bug
> >> that eventually needs to be fixed. Take a look in Bugzilla, there are
> >> several already reported import/module-related bugs.
> > 
> > They're private _access_ but still visible. I believe that that is the
> > correct behavior and not a bug at all. I believe that it's necessary for
> > stuff like where various functions in std.algorithm return auto and
> > return a private struct which you cannot construct yourself. Code which
> > uses that struct needs to know about it so that it can use it properly,
> > but since it's private, it can't declare it directly. It works because
> > the types are appropriately generic (ranges in this case). Regardless, I
> > believe that the current behavior with private is intended.
> > 
> > - Jonathan M Davis
> 
> The more I play with private/protected/package the more confused I am by
> it.
> 
> For the most part the rules are:
> 	Functions and variables have protection
> 	Types (enum, struct, class) do not
> 	this and ~this are special and are not considered functions, and are
> always public
> 	struct and class members always default to public
> 
> 
> 
> If you search phobos you will find occurences of 'private struct' and
> 'private class', so even the people writing libraries are expecting
> something to be happening that isn't.  For example:
> 
> 
> //in std.parallelism:
> private struct AbstractTask {
>      mixin BaseMixin!(TaskStatus.notStarted);
> 
>      void job() {
>          runTask(&this);
>      }
> }
> 
> 
> //and in std.demangle:
> private class MangleException : Exception
> {
>      this()
>      {
>          super("MangleException");
>      }
> }
> 
> 
> and in my code I can compile the following without compile-time errors:
> 
> 
> import std.parallelism;
> import std.demangle;
> 
> int main()
> {
> 	MangleException bar = new MangleException();
> 
> 	AbstractTask foo;
> 	foo.job();
> 
> 	return 0;
> }
> 
> 
> 
> 
> With the language the way it is now, it is nonsensical to have the
> attributes public/protected/package/private/export precede the keyword
> struct, class, or enum.

private, public, protected, and private are _always_ about access and _never_ 
about visibility. They affect whether you can _use_ a particular symbol in a 
particular piece of code, _not_ whether the compiler can see it in that 
context. It doesn't matter whether it's a function, variable, class, etc. Now, 
there may be bugs in the current implementation, but the design is fairly 
straightforward.

For instance, anything templated is currently always public regardless of what 
you mark it as ( http://d.puremagic.com/issues/show_bug.cgi?id=1904 , 
http://d.puremagic.com/issues/show_bug.cgi?id=2775 ). Also, it looks like 
there is a bug report for structs and classes not dealing with private 
properly ( http://d.puremagic.com/issues/show_bug.cgi?id=2830 ) when the 
entire class or struct is marked as private. So unfortunately, the 
implementation _is_ currently buggy, but the design is fairly straightforward.

Oh, and this and ~this _are_ functions (albeit special) and can be made 
private - or even outright removed entirely with @disable. Traits works with 
__ctor and __dtor rather than this and ~this, and you can call the constructor 
with __ctor (though it's unlikely that there's a case where you should) and 
the destructor with __dtor (though there probably isn't really a valid case to 
do that - use clear instead, and it'll call the destructor along with 
everything else it does).

The thing with the default constructor is that it exists if you don't declare 
any constructors, and it'll default to public, so you generally have to 
declare it and make it private if you want it to have a default constructor 
and not have it public. That _does_ seem like a likely place for a bug in the 
case where the class is private, but since that's completely broken right now 
anyway, that's not really a concern. The destructor is in the same boat, 
though why you'd want to make the destructor private, I don't know. And 
structs don't have the issue with default constructors because they can't have 
them.

So, yes, the current implementation is broken (and more broken than I thought 
that it was actually), but the basic design is quite straightforward. I would 
think that assuming that dmd were not buggy with regards to private that the 
access specifiers would generally work as you expect them to - though there 
may be some cases where they would surprise you. For instance, per TDPL, 
private member functions are overridable but not callable (as they wolud be in 
C++) by derived classes, which surprises a lot of people in C++ (though 
presently, private functions are not overridable - there's at least one bug 
report on it - so this surprising issue doesn't come up right now). And it's 
because access specifiers are for _access_ only, not visibility.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list