www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Friends in D, a new idiom?

reply IntegratedDimensions <IntegratedDimensions gmail.com> writes:
(Please don't respond if you are going to attack me in any way! I 
only accept answers that are meaningful to me and if you come up 
with the wrong answer don't get offended when I tell you it's 
wrong, if you do, expect to to get it thrown back in your face)

Was having to restrict write access to a type, for safety, in 
general but required access by some types.

The idea is to supply the write assessors through a sub-interface:

module m;

class C
{
	protected int x = 0;
	 property int X() { return x; }
	protected  property int X(int v) { _this.x = v; return v; }
	public struct _Access
	{

		 property int X(int v) { _this.x = v; return v; }
		C _this;
	}

	_Access Access;

	this() { Access._this = this; }

}








import std.stdio, m;

void main()
{

	C c = new C();

	writeln(c.X);
	c.Access.X = 4;
	writeln(c.X);

	getchar();

}


Here Access has the public setters and so any writing must occur 
through it.

Initially I thought nested classes contained an inherent super 
but I guess that is not the case?

I imagine that the pattern could be extended to really 
encapsulate types better by separating write and read access. By 
forcing write access through another deference, it prevents easy 
write access and hence less use and makes it more explicit.

I also imagine that one could enhance this so that write access 
could also be allowed by certain types.

Any ideas about this type of pattern, how to make it better, 
already exists etc?
May 26 2018
parent reply Vijay Nayar <madric gmail.com> writes:
On Sunday, 27 May 2018 at 05:25:53 UTC, IntegratedDimensions 
wrote:

 Re: Friends in D, a new idiom?
In D, there's no exact equivalent to friend, but there are a few more specialized tools at your disposal. Normally all code in the same module is essentially a friend, so if the classes you are dealing with are tightly coupled, they can simply be in the same module. For example: module m; class C { // This is still visible in the same module. // See https://dlang.org/spec/attribute.html#VisibilityAttribute private int data; ... } class CAccessor { C _this; this(C c) { _this = c; } property void data(int v) { _this.data = v; } ... }
 Initially I thought nested classes contained an inherent super 
 but I guess that is not the case?
Super is for inheritance rather than inner classes. So another way to tackle your problem using super would be this: class C { protected int _data; property int data() { return _data; } } class CAccessor : C { property void data(int v) { _data = v; } C toC() { return this; } }
 I also imagine that one could enhance this so that write access 
 could also be allowed by certain types.
The 'package' visibility attribute can also be given a parameter if you need to limit access only to certain module.
 Any ideas about this type of pattern, how to make it better, 
 already exists etc?
You might be looking for the "Builder Pattern" which uses a separate object to construct and modify objects, and then it creates a read-only object with those values upon request. Also, I would recommend using "const" to control access as well. Setter methods will not be const, but getters will be. Those that have a `const(C)` reference will only be able to read, and those with a `C` will be able to call all methods. For example: class C { private int _data; property int data() const { return _data; } property void data(int v) { _data = v; } } void main() { C a = new C(); const(C) b = a; a.data(3); a.data(); b.data(); // b.data(4); Compile error. }
May 26 2018
parent reply IntegratedDimensions <IntegratedDimensions gmail.com> writes:
On Sunday, 27 May 2018 at 06:24:13 UTC, Vijay Nayar wrote:
 On Sunday, 27 May 2018 at 05:25:53 UTC, IntegratedDimensions 
 wrote:

 Re: Friends in D, a new idiom?
In D, there's no exact equivalent to friend, but there are a few more specialized tools at your disposal. Normally all code in the same module is essentially a friend, so if the classes you are dealing with are tightly coupled, they can simply be in the same module.
Yes, but this is not the case. I have two classes somewhat related but in different modules so I am looking for a more general solution. I do not like chunking everything in to the same module just to get around this type of problem.
 For example:

 module m;

 class C {
   // This is still visible in the same module.
   // See 
 https://dlang.org/spec/attribute.html#VisibilityAttribute
   private int data;
   ...
 }

 class CAccessor {
   C _this;
   this(C c) {
     _this = c;
   }
    property void data(int v) {
     _this.data = v;
   }
   ...
 }

 Initially I thought nested classes contained an inherent super 
 but I guess that is not the case?
Super is for inheritance rather than inner classes. So another way to tackle your problem using super would be this: class C { protected int _data; property int data() { return _data; } } class CAccessor : C { property void data(int v) { _data = v; } C toC() { return this; } }
Yeah, but this is a bit bulky. Although maybe UFCS could work well in this case although one would end up requiring different names in modules rather than Access or Friend. I haven't tried it but if UFCS allows a module function to access the protected member and outside the module the UFCS could be called. I think this might defeat the usage except I recently saw that UFCS can be called with = so they can emulate setters, so it might work well(until that syntax is depreciated).
 I also imagine that one could enhance this so that write 
 access could also be allowed by certain types.
The 'package' visibility attribute can also be given a parameter if you need to limit access only to certain module.
Yeah, maybe using packages is the best way to go. The modules I'm using are related so they could be used in a package. Doesn't help with the general case though.
 Any ideas about this type of pattern, how to make it better, 
 already exists etc?
You might be looking for the "Builder Pattern" which uses a separate object to construct and modify objects, and then it creates a read-only object with those values upon request.
I'm looking for something lightweight and direct. It is not for total encapsulation control but to simply provide an extra level of indirection for write access to make the object look read only to those that directly use it. Basically I have another class outside the module that needs to write to a variable in side an object to set it up, from then on it is read only. It can't be done at construction. Maybe their will be one or two other times that it will need to change but I don't see why I should have to expose it for anyone nor create a huge layer of complexity to allow for a single access. The method I gave works fine for this type of behavior and the UFCS probably will even be easier if it works.
May 26 2018
parent Vijay Nayar <madric gmail.com> writes:
On Sunday, 27 May 2018 at 06:37:56 UTC, IntegratedDimensions 
wrote:

 I'm looking for something lightweight and direct. It is not for 
 total encapsulation control but to simply provide an extra 
 level of indirection for write access to make the object look 
 read only to those that directly use it.
I think const is something that may be helpful then. If applied consistently, especially with methods, it can also protect you from accidentally making mutations in functions where were originally intended to be read-only. Having an object "look" read-only is more of a stylistic thing based on conventions about method naming, etc. Personally I lean towards having the compiler enforce it.
May 27 2018