Thread overview
Friends in D, a new idiom?
May 27, 2018
Vijay Nayar
May 27, 2018
Vijay Nayar
May 27, 2018
(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 27, 2018
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 27, 2018
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 27, 2018
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.