-
-
Notifications
You must be signed in to change notification settings - Fork 705
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std.typecons.scoped problems #9892
Labels
Comments
bearophile_hugs commented on 2010-12-19T13:06:00ZAn interesting example found by Andrej Mitrovic (modified):
import std.c.stdio: puts;
import std.typecons: scoped;
class Foo {
~this() {
puts("Foo.dtor");
}
}
void main() {
Foo f1 = scoped!Foo(); // doesn't call dtor after the scope
auto f2 = scoped!Foo(); // calls dtor after the scope
} |
yebblies commented on 2010-12-20T21:00:29Z(In reply to comment #1)
> An interesting example found by Andrej Mitrovic (modified):
>
>
> import std.c.stdio: puts;
> import std.typecons: scoped;
> class Foo {
> ~this() {
> puts("Foo.dtor");
> }
> }
> void main() {
> Foo f1 = scoped!Foo(); // doesn't call dtor after the scope
> auto f2 = scoped!Foo(); // calls dtor after the scope
> }
This example (and the first half of this bug report) appears to be a duplicate of bug http://d.puremagic.com/issues/show_bug.cgi?id=3516 |
bearophile_hugs commented on 2010-12-21T00:22:23Z(In reply to comment #2)
> > void main() {
> > Foo f1 = scoped!Foo(); // doesn't call dtor after the scope
> > auto f2 = scoped!Foo(); // calls dtor after the scope
> > }
>
> This example (and the first half of this bug report) appears to be a duplicate
> of bug http://d.puremagic.com/issues/show_bug.cgi?id=3516
But both f1 and f2 gets assigned. I don't fully understand issue 3516 so I can't tell. |
braddr commented on 2010-12-21T00:29:38ZAny issue that involves a struct dtor not being properly run is almost certainly an extension of bug 3516. Walter's well aware of it, but it's a non-trivial problem to fix. |
post (@kyllingstad) commented on 2010-12-21T00:48:45ZIsn't the problem rather that the type of f2 is Scoped!Foo, while the type of f1 is just Foo? The compiler doesn't know that it should call the destructor of a Foo at the end of the scope. |
bearophile_hugs commented on 2010-12-21T00:52:48Z(In reply to comment #5)
> Isn't the problem rather that the type of f2 is Scoped!Foo, while the type of
> f1 is just Foo? The compiler doesn't know that it should call the destructor
> of a Foo at the end of the scope.
You are probably right. Then why isn't this a compile error?
Foo f1 = scoped!Foo(); |
post (@kyllingstad) commented on 2010-12-21T00:56:37Z(In reply to comment #6)
> You are probably right. Then why isn't this a compile error?
>
> Foo f1 = scoped!Foo();
Because Scoped!Foo has an 'alias this' to the underlying Foo, which is necessary for it to behave like a Foo. |
yebblies commented on 2010-12-21T01:00:19Z(In reply to comment #7)
> (In reply to comment #6)
> > You are probably right. Then why isn't this a compile error?
> >
> > Foo f1 = scoped!Foo();
>
> Because Scoped!Foo has an 'alias this' to the underlying Foo, which is
> necessary for it to behave like a Foo.
scoped!Foo() returns a temporary of type scoped!(Foo).Scoped (or something like that).
This temporary is implicitly converted to Foo using alias this, but the temporary never has it's destructor called due to bug 3516, which means Foo's destructor is never called either.
It is fine for the temporary to be converted to Foo, so long as the destructor is called when the scope that 'scoped' was called in is exited. |
k.hara.pg commented on 2011-11-10T23:11:38Z(In reply to comment #8)
> scoped!Foo() returns a temporary of type scoped!(Foo).Scoped (or something like
> that).
> This temporary is implicitly converted to Foo using alias this, but the
> temporary never has it's destructor called due to bug 3516, which means Foo's
> destructor is never called either.
>
> It is fine for the temporary to be converted to Foo, so long as the destructor
> is called when the scope that 'scoped' was called in is exited.
Now bug 3516 was fixed. Then comment#1 code prints two "Foo.dtor"
But allowing conversion from temporary type (e.g. Scoped!Foo) to Foo is unsafe, because the temporary has value type and its lifetime is limited in its scope, but Foo is class reference of the temporary and we can bring it out the scope.
Foo global_foo;
void test1() {
auto foo = scoped!Foo();
global_foo = foo; // implicitly conversion from typeof(foo) to Foo
// This line should be forbidden in compile time
}
void test2() {
// use global_foo -> Access Violation!
}
void main() {
test1();
test2();
}
I think my ProxyOf mixin template is useful for this issue.
https://github.com/D-Programming-Language/phobos/pull/300 |
k.hara.pg commented on 2011-11-10T23:11:39Z(In reply to comment #8)
> scoped!Foo() returns a temporary of type scoped!(Foo).Scoped (or something like
> that).
> This temporary is implicitly converted to Foo using alias this, but the
> temporary never has it's destructor called due to bug 3516, which means Foo's
> destructor is never called either.
>
> It is fine for the temporary to be converted to Foo, so long as the destructor
> is called when the scope that 'scoped' was called in is exited.
Now bug 3516 was fixed. Then comment#1 code prints two "Foo.dtor"
But allowing conversion from temporary type (e.g. Scoped!Foo) to Foo is unsafe, because the temporary has value type and its lifetime is limited in its scope, but Foo is class reference of the temporary and we can bring it out the scope.
Foo global_foo;
void test1() {
auto foo = scoped!Foo();
global_foo = foo; // implicitly conversion from typeof(foo) to Foo
// This line should be forbidden in compile time
}
void test2() {
// use global_foo -> Access Violation!
}
void main() {
test1();
test2();
}
I think my ProxyOf mixin template is useful for this issue.
https://github.com/D-Programming-Language/phobos/pull/300 |
andrej.mitrovich (@AndrejMitrovic) commented on 2012-12-18T13:02:40Z(In reply to comment #10)
> Now bug 3516 was fixed. Then comment#1 code prints two "Foo.dtor"
>
> But allowing conversion from temporary type (e.g. Scoped!Foo) to Foo is unsafe,
> because the temporary has value type and its lifetime is limited in its scope,
> but Foo is class reference of the temporary and we can bring it out the scope.
There is another problem. You may want to pass the instance to another function, which is ok since the type will still be alive during that call:
class C { }
void func(C c) { }
void main()
{
auto c = scoped!C();
func(c); // ok, c is still alive here
}
Disabling implicit conversion (maybe by using your ProxyOf mixin) might be ok, but then we can no longer pass the instance around because `Scoped` is a voldemort type hidden inside the `scoped` function. E.g.:
class C { }
void func(C c) { }
void funcScoped(??? c) { } // param needs to be a proper type
void main()
{
auto c = scoped!C(); // voldemort type
func(c); // error, no implicit conversion
funcScoped(c); // would be ok if we knew what type c was
}
So if we disable implicit conversion we should probably introduce a Scoped type instead of a voldemort, so we can write:
void funcScoped(ref Scoped!C c) { } |
dmitry.olsh (@DmitryOlshansky) commented on 2012-12-19T09:15:42Z(In reply to comment #11)
>
> There is another problem. You may want to pass the instance to another
> function, which is ok since the type will still be alive during that call:
>
> class C { }
> void func(C c) { }
> void main()
> {
> auto c = scoped!C();
> func(c); // ok, c is still alive here
> }
>
> Disabling implicit conversion (maybe by using your ProxyOf mixin) might be ok,
> but then we can no longer pass the instance around because `Scoped` is a
> voldemort type hidden inside the `scoped` function. E.g.:
>
> class C { }
> void func(C c) { }
> void funcScoped(??? c) { } // param needs to be a proper type
> void main()
> {
> auto c = scoped!C(); // voldemort type
> func(c); // error, no implicit conversion
> funcScoped(c); // would be ok if we knew what type c was
> }
>
> So if we disable implicit conversion we should probably introduce a Scoped type
> instead of a voldemort, so we can write:
>
> void funcScoped(ref Scoped!C c) { }
Even more interesting is emplacing inside of class instance (to avoid pointer overhead while modeling composition):
class A{//A makes sure b & c are not escaped
Scoped!B b;
Scoped!C c;
}
Overall I think voldemort types are overpriced. |
dmitry.olsh (@DmitryOlshansky) commented on 2018-05-18T10:21:27ZIndeed and with `scope` becoming a thing in DIP 1000 we can have our scope storage class to have stack-allocated classes.
scope a = new Blah(...);
scope class instances are everywhere in DMD frontend now as well.
It's plain as day that our library solution had failed and is not required anymore. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
bearophile_hugs reported this on 2010-10-24T19:10:07Z
Transfered from https://issues.dlang.org/show_bug.cgi?id=5115
CC List
Description
The text was updated successfully, but these errors were encountered: