On 5/21/18 5:23 PM, Walter Bright wrote:
In C, the way to do PIMPL is to write just a struct declaration:
=== s.h ===
struct S;
=== s.c ===
#include "s.h"
struct S { ... };
=== t.c ===
#include "s.h"
struct T {
S* pimpl;
};
And the users of T cannot access anything in S. The straightforward
equivalent in D is:
=== s.di ===
struct S;
=== s.d ===
struct S { ... }
=== t.d ===
import s;
struct T {
S* pimpl;
};
But if you don't want to use .di files, such as when compiling all the
files together with one command, then things get a bit awkward. D
doesn't like:
=== s.d ===
public struct S;
private struct S { ... }
Making a public alias to a private struct doesn't work, as the struct's
members are still accessible. I finally found a way:
=== s.d ===
public struct Spimpl {
private S* pimpl;
private alias pimpl this;
}
private struct S { ... }
=== t.d ===
import s;
struct T {
Spimpl* s;
Don't you mean a nonpointer here? Otherwise, there are 2 indirections
needed.
}
and the contents of S are inaccessible to T, while type safety is
maintained. There are no extra indirections - the alias this takes care
of that. s.d can use s to directly access S's contents, but t.d cannot.
https://github.com/dlang/dmd/blob/master/src/dmd/func.d#L229
https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d#L151
C: http://wiki.c2.com/?PimplIdiom
C++: http://en.cppreference.com/w/cpp/language/pimpl
Will this really work?
I mean, if the compiler can see the implementation of S, even though
it's private, can't it inline things and screw with the binary
compatibility?
I thought that was the main benefit of pimpl, to create a barrier which
you know is going to separate the user from the implementation.
-Steve