On Monday, 24 July 2017 at 20:30:25 UTC, Jonathan M Davis wrote:
On Monday, July 24, 2017 2:30:01 PM MDT Atila Neves via
Digitalmars-d wrote:
>> This is fine. What dmd does now is strip shared off of the
>> `this` pointer, not the member variables. There's only a
>> problem if the sharedness of the member variable(s) depends
>> on sharedness of the enclosing object.
>
> What happens with something like
>
> struct S
> {
>
> Foo* _foo;
>
> ~this() {...}
>
> }
>
> shared S s;
>
> Inside the destructor, is what _foo points to still treated
> as
> shared: shared(Foo)*?
No. This is what I meant by the sharedness depening on the
enclosing object. However, there's a workaround:
struct Foo { }
struct S {
Foo* _foo;
bool _isShared;
this(this T, U)(U foo) if(is(T == shared) && is(U ==
shared(Foo)*) || !is(T == shared) && is(U == Foo*)) {
static if(is(T == shared)) _isShared = true;
_foo = foo;
}
~this() {
import std.stdio: writeln;
_isShared ? writeln("shared dtor") :
writeln("non-shared
dtor");
}
}
void main() {
auto f = Foo();
auto sf = shared Foo();
auto s = S(&f);
auto ss = shared S(&sf);
}
It's annoying to use that bool up memory-wise, but I assume
it's not a big deal for most applications.
In any case, that example wouldn't have worked anyway before
my change to dmd - even creating the S struct would've been a
compiler error.
The problem with this is that this means that shared is not
being properly enforced by the compiler. Your workaround is a
way for the programmer to figure out if the object is shared
and do something differently based on that, but for the
compiler to do what it's supposed to be doing with shared (e.g.
prevent non-atomic operations), any indirections in the member
variables must continue to be typed as shared inside the
destructor, and that's clearly not happening right now, which
is a serious problem IMHO. The situation may be better thanks
to your changes in that some stuff is now possible that should
be possible and was not before, but it's not completely sound
as far as the type system goes, and we really should be fixing
it so that shared is properly enforced rather than just blindly
stripped off.
- Jonathan M Davis
I agree that this could be a problem, and that the proper
solution is probably to allow the user to define more than one
destructor. The problem isn't just with shared - immutable is
similar, since you'd be able to invoke undefined behaviour from
the destructor since immutable would be cast away and the
compiler wouldn't even warn you. And that was already the
behaviour in dmd. I think the situation isn't ideal but better
than before.
I also think that while the problem exists, I don't think it'll
be common. This would only affect structs that can be shared
_and_ non-shared (or immutable).
This will require a DIP, methinks.
Atila
Atila