This code doesn't compile anymore:
---
import std.typecons : Unique;
struct Foo
{
private int i;
}
void main()
{
Unique!Foo foo = new Foo(1);
foo.i = 2; // Error: no property 'i' for type 'Unique!(Foo)'
}
---
It compiled before https://github.com/dlang/phobos/pull/4763 was merged. But the new implementation uses Proxy, which is a template mixin that is instantiated from std.typecons itself.
If this behaviour is intended, the doc should state it.
Comment #1 by greeenify — 2017-01-07T21:42:22Z
> If this behaviour is intended, the doc should state it.
This should definitely have gotten a proper changelog entry (and deprecation warning).
However, I am not really convinced that it should be noted in the documentation that access to private member variables isn't supported as this is the way visibility is supposed to work in D. Did anything lead you to this assumption or was it just by chance that accessing `private` variables worked and you didn't realize until the hole was fixed?
Comment #2 by dransic — 2017-01-07T22:04:11Z
(In reply to greenify from comment #1)
> > If this behaviour is intended, the doc should state it.
>
> This should definitely have gotten a proper changelog entry (and deprecation
> warning).
> However, I am not really convinced that it should be noted in the
> documentation that access to private member variables isn't supported as
> this is the way visibility is supposed to work in D. Did anything lead you
> to this assumption or was it just by chance that accessing `private`
> variables worked and you didn't realize until the hole was fixed?
Private members are supposed to be accessible in the module where the type is declared (module-level encapsulation). A type constructor like `Unique` should return a type with the same access behavior. RefCounted works as I expect (but maybe I have wrong expectations...):
---
import std.typecons : RefCounted;
struct Foo
{
private int i;
}
void main()
{
RefCounted!Foo foo = Foo(1);
foo.i = 2; // OK
}
---
Comment #3 by b2.temp — 2017-01-07T23:10:07Z
(In reply to dransic from comment #2)
> Private members are supposed to be accessible in the module where the type
> is declared (module-level encapsulation).
> [...]
> ---
There's a bigger underlying problem. Clearly something is broken by the change but the change doesn't work because Proxy uses __traits() and __traits() has a limitation related to the protection attributes. I don't know if you've followed the NG discussions last months but there's been several topics about this. A semantic change is even planned for the next 6 months (see the recent announce about H1)
That being said I don't suggest to wait the semantic change to happen. I just come because this __traits() thing has been a personal concern.
Comment #4 by dransic — 2017-01-07T23:49:34Z
(In reply to b2.temp from comment #3)
> (In reply to dransic from comment #2)
> > Private members are supposed to be accessible in the module where the type
> > is declared (module-level encapsulation).
> > [...]
> > ---
>
> There's a bigger underlying problem. Clearly something is broken by the
> change but the change doesn't work because Proxy uses __traits() and
> __traits() has a limitation related to the protection attributes. I don't
> know if you've followed the NG discussions last months but there's been
> several topics about this. A semantic change is even planned for the next 6
> months (see the recent announce about H1)
>
> That being said I don't suggest to wait the semantic change to happen. I
> just come because this __traits() thing has been a personal concern.
OK, thanks. I didn't know about these discussions about __traits() and I see now why Proxy doesn't work. So there's a plan to allow __traits() to bypass access rules to provide more useful introspection. That's good. Maybe we should have waited for this change before switching to a new implementation of `Unique`.
Comment #5 by code — 2017-01-17T23:58:31Z
I'm for reverting this change (the Proxy part).
Proxy is a horrible hack that employ a giant template machinery and was only introduced to replace typedef. It's main difference from alias this being, that you cannot implicitly convert it to the type.
Unique should work like this, but cannot until -dip1000 became default.
static if (class_or_interface)
T get() return scope { return _p; }
else
ref T get() return { return *_p; }
alias this get;
This does allow implicit conversion, but binds the lifetime of the returned class ref/ref to the lifetime of Unique, thus making it impossible to escape.
It'll still take a while until that works, and we're likely to come up with new RC implementations after that (b/c both Unique and RefCounted leave a lot to wish).
Also opDot isn't going away for a while (and maybe be could be replaced with opDispatch).
See https://trello.com/c/pTlDuyBD/31-finish-smartref-implementation for previous attempts on fixing Unique/RefCounted.
Comment #6 by dransic — 2017-01-18T08:24:39Z
(In reply to Martin Nowak from comment #5)
> I'm for reverting this change (the Proxy part).
I agree.
But I suggest reverting all of PR #4763: the Proxy part and the destroy part. The latter also because it introduces undeterministic destruction of Unique!structs (see [1], there is no bug report for this yet, I guess).
[1] http://forum.dlang.org/post/[email protected]
Comment #7 by dransic — 2017-12-16T10:59:14Z
std.experimental.typecons.Final is also affected, since its implementation uses Proxy the same way.
I should probably change the title for a more general one.
Comment #8 by b2.temp — 2020-01-08T20:21:36Z
Created attachment 1772
fix proposal
Comment #9 by robert.schadek — 2024-12-01T16:29:17Z