www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to create friends of a class at compile time?

reply Tejas <notrealemail gmail.com> writes:
I can do it like this in C++:
```
template<class abc>
class def
{
     friend typename abc;
}
```

I am just hopelessly confused on how to achieve the same in D.
Jul 15 2021
next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 15 July 2021 at 17:21:45 UTC, Tejas wrote:
 I can do it like this in C++:
You don't just put class def and class abc in the same module and you get the same effect though.
Jul 15 2021
parent reply Tejas <notrealemail gmail.com> writes:
On Thursday, 15 July 2021 at 17:26:41 UTC, Adam D Ruppe wrote:
 On Thursday, 15 July 2021 at 17:21:45 UTC, Tejas wrote:
 I can do it like this in C++:
You don't just put class def and class abc in the same module and you get the same effect though.
I really should've just posted the whole thing... I know how modules and access specifiers work in D I was just reading the source of one of the files of libcxx and came across this: ``` template <class _Cp, bool = __has_storage_type<_Cp>::value> class __bit_reference { typedef typename _Cp::__storage_type __storage_type; typedef typename _Cp::__storage_pointer __storage_pointer; __storage_pointer __seg_; __storage_type __mask_; //PART I'M CONCERNED WITH *********************************** friend typename _Cp::__self; friend class __bit_const_reference<_Cp>; friend class __bit_iterator<_Cp, false>; //END OF PART I'M CONCERNED WITH ************************ public: _LIBCPP_INLINE_VISIBILITY __bit_reference(const __bit_reference&) = default; _LIBCPP_INLINE_VISIBILITY operator bool() const _NOEXCEPT {return static_cast<bool>(*__seg_ & __mask_);} _LIBCPP_INLINE_VISIBILITY bool operator ~() const _NOEXCEPT {return !static_cast<bool>(*this);} _LIBCPP_INLINE_VISIBILITY __bit_reference& operator=(bool __x) _NOEXCEPT { if (__x) *__seg_ |= __mask_; else *__seg_ &= ~__mask_; return *this; } _LIBCPP_INLINE_VISIBILITY __bit_reference& operator=(const __bit_reference& __x) _NOEXCEPT {return operator=(static_cast<bool>(__x));} _LIBCPP_INLINE_VISIBILITY void flip() _NOEXCEPT {*__seg_ ^= __mask_;} _LIBCPP_INLINE_VISIBILITY __bit_iterator<_Cp, false> operator&() const _NOEXCEPT {return __bit_iterator<_Cp, false>(__seg_, static_cast<unsigned>(__libcpp_ctz(__mask_)));} private: _LIBCPP_INLINE_VISIBILITY __bit_reference(__storage_pointer __s, __storage_type __m) _NOEXCEPT : __seg_(__s), __mask_(__m) {} }; ``` How do you write the equivalent of that in D? Is the answer still the same? Manually keep it in the same module, or is there a programmatic way of converting this to D?
Jul 15 2021
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 7/15/21 1:43 PM, Tejas wrote:

 How do you write the equivalent of that in D? Is the answer still the 
 same? Manually keep it in the same module, or is there a programmatic 
 way of converting this to D?
Functions in the same module can access `private` members. Functions in the same package (or in whatever package you specify) can access `package` members. That is how D does "friends". So the answer to your question depends on how the C++ code is organized. It's always possible that something in C++ here is not translatable into D, but most likely can be redesigned (and likely better designed). -Steve
Jul 15 2021
parent reply Tejas <notrealemail gmail.com> writes:
On Thursday, 15 July 2021 at 18:06:26 UTC, Steven Schveighoffer 
wrote:
 On 7/15/21 1:43 PM, Tejas wrote:

 How do you write the equivalent of that in D? Is the answer 
 still the same? Manually keep it in the same module, or is 
 there a programmatic way of converting this to D?
Functions in the same module can access `private` members. Functions in the same package (or in whatever package you specify) can access `package` members. That is how D does "friends". So the answer to your question depends on how the C++ code is organized. It's always possible that something in C++ here is not translatable into D, but most likely can be redesigned (and likely better designed). -Steve
Yes, it seems like seperating chunks of C++ code into seperate modules and using the ```d package(qualifiedIdentifier) ``` access specifier seems to be the way to go. Was wondering if there was some wizardry that the veterans knew that would make it less difficult, but it seems this is the only way. Thank you very much for replying!
Jul 15 2021
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 7/15/21 11:24 AM, Tejas wrote:

 it seems like seperating chunks of C++ code into seperate modules
 and using the
 ```d
 package(qualifiedIdentifier)
 ```
 access specifier seems to be the way to go.
That would be necessary if one agreed with C++'s 'private' to begin with. In other words, one would agree that implementations inside one source file should be protected from each other. Through Walter Bright's experience, D does not buy into that view: It is silly to protect implementation details of features of the same file from each other. Personally, I fully agree! I am rarely strongly opinionated; this topic is one of those cases. :) In hind sight, this is one of the examples of D that thought me and improved me. C++'s 'friend' "feature" covers up a language design mistake: It is a mistake because a tool should be useful; C++'s 'private' protects the programmer unnecessarily strongly from himself or herself. What a view that causes unnecessary mental load on many programmers with the 'friend' keyword... If you agree with all of that, then your idea of separating chunks into separate modules becomes unnecessary work. Just don't do it and you will miss nothing at all. You will gain a lot in the future without even noticing it. :) Ali
Jul 15 2021
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 7/15/21 5:46 PM, Ali =C3=87ehreli wrote:

 On 7/15/21 11:24 AM, Tejas wrote:
  > package(qualifiedIdentifier)
 Just don't do it
Ok, I said all that before realizing what you needed with transpiling=20 C++ to D and the solution of package(qualifiedIdentifier). (And=20 package(qualifiedIdentifier) is news to me! :) ) Ali
Jul 15 2021
prev sibling next sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Thursday, 15 July 2021 at 17:21:45 UTC, Tejas wrote:
 I can do it like this in C++:
 ```
 template<class abc>
 class def
 {
     friend typename abc;
 }
 ```

 I am just hopelessly confused on how to achieve the same in D.
Uncharitably: D is a friendless language. Charitably: D is so much more friendly that instead of a short explicit list of friends, D has a large implicit list of friends: everything else in a module. That's why this works: ```d class Secret { private int id; } void main() { import std.stdio : writeln; auto s = new Secret; writeln("visible to me: ", s.id); } ``` But this doesn't: ```d void main() { import std.stdio : writeln; import secret : Secret; auto s = new Secret; writeln("visible to me: ", s.id); } ``` Error: no property `id` for type `secret.Secret`
Jul 15 2021
parent reply Tejas <notrealemail gmail.com> writes:
On Thursday, 15 July 2021 at 17:30:05 UTC, jfondren wrote:
 On Thursday, 15 July 2021 at 17:21:45 UTC, Tejas wrote:
 I can do it like this in C++:
 ```
 template<class abc>
 class def
 {
     friend typename abc;
 }
 ```

 I am just hopelessly confused on how to achieve the same in D.
Uncharitably: D is a friendless language. Charitably: D is so much more friendly that instead of a short explicit list of friends, D has a large implicit list of friends: everything else in a module. That's why this works: ```d class Secret { private int id; } void main() { import std.stdio : writeln; auto s = new Secret; writeln("visible to me: ", s.id); } ``` But this doesn't: ```d void main() { import std.stdio : writeln; import secret : Secret; auto s = new Secret; writeln("visible to me: ", s.id); } ``` Error: no property `id` for type `secret.Secret`
I'm sorry, I should've explicitly mentioned I'm interested in learning how to do friend injection in D. I know that access specifiers operate at module scope, seen a few posts about that here already. Thank you for answering though.
Jul 15 2021
parent reply evilrat <evilrat666 gmail.com> writes:
On Thursday, 15 July 2021 at 17:49:06 UTC, Tejas wrote:
 I'm sorry, I should've explicitly mentioned I'm interested in 
 learning how to do friend injection in D.

 I know that access specifiers operate at module scope,  seen a 
 few posts about that here already.
 Thank you for answering though.
Probably the only way is CRTP (unlikely) or mixin that access internals. Both will be limited and cumbersome to use though. Additionally there is "package" visibility kind that takes optional package name to give access to specific package. https://dlang.org/spec/grammar.html#attributes (under visibility attributes) I rarely use package visibility so might be incorrect, but here an example anyway. ```d module somepackage.somemod; struct A { private int x; // only accessible from same module package int y; // accessible from any module in 'somepackage' package(otherpackage) int z; // accessible from 'otherpackage' package } ```
Jul 15 2021
parent Tejas <notrealemail gmail.com> writes:
On Thursday, 15 July 2021 at 18:11:30 UTC, evilrat wrote:
 On Thursday, 15 July 2021 at 17:49:06 UTC, Tejas wrote:
 I'm sorry, I should've explicitly mentioned I'm interested in 
 learning how to do friend injection in D.

 I know that access specifiers operate at module scope,  seen a 
 few posts about that here already.
 Thank you for answering though.
Probably the only way is CRTP (unlikely) or mixin that access internals. Both will be limited and cumbersome to use though. Additionally there is "package" visibility kind that takes optional package name to give access to specific package. https://dlang.org/spec/grammar.html#attributes (under visibility attributes) I rarely use package visibility so might be incorrect, but here an example anyway. ```d module somepackage.somemod; struct A { private int x; // only accessible from same module package int y; // accessible from any module in 'somepackage' package(otherpackage) int z; // accessible from 'otherpackage' package } ```
CRTP and mixins are our best solution against multiple inheritance. Doubt they'll help with friend injection. I also could only think of package specifiers for access control, but wondered whether it could be drilled down to a specific module, rather than package level. you think ``` package(otherpackage.specific_module)``` is valid D code? Thanks for replying, much appreciated!
Jul 15 2021
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Jul 15, 2021 at 05:21:45PM +0000, Tejas via Digitalmars-d-learn wrote:
 I can do it like this in C++:
 ```
 template<class abc>
 class def
 {
     friend typename abc;
 }
 ```
 
 I am just hopelessly confused on how to achieve the same in D.
D does not have `friend` declarations. Equivalent functionality is achieved by `private` being module-private rather than aggregate-private, meaning that all you have to do is to put `abc` in the same module as `def`, and it will have access to all `def`s private members. If, however, you're trying to inject friend access to something outside def's module, then you might want to reconsider what you're trying to accomplish and whether it can be done differently. T -- Obviously, some things aren't very obvious.
Jul 15 2021
parent Tejas <notrealemail gmail.com> writes:
 If, however, you're trying to inject friend access to something 
 outside def's module, then you might want to reconsider what 
 you're trying to accomplish and whether it can be done 
 differently.


 
Was just dreaming of how to transpile C++ code to D :( Curiously enough, friend injection was not made part of the standard back in 1998 and only g++ supported it through a non-standard extension. But now here we are. I wonder why this was allowed.
Jul 15 2021