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

Reply via email to