http://d.puremagic.com/issues/show_bug.cgi?id=5115
Summary: std.typecons.scoped problems Product: D Version: D2 Platform: x86 OS/Version: Windows Status: NEW Severity: enhancement Priority: P2 Component: Phobos AssignedTo: nob...@puremagic.com ReportedBy: bearophile_h...@eml.cc --- Comment #0 from bearophile_h...@eml.cc 2010-10-24 19:10:07 PDT --- The D type system doesn't know about the scoped nature of objects built by std.typecons.scoped, this gives two main disadvantages over the (deprecated) "scope" classes: - The class destructor isn't called - The compiler doesn't and can't enforce that references to the class don't escape the scope. The first problem may be seen with this test program, changing the values of the three static if: import std.typecons: scoped; import std.conv: emplace; import std.c.stdio: puts; import std.c.stdlib: exit; class Foo { this() { puts("constructor"); } ~this() { puts("destructor"); } } void main() { { static if (1) { scope Foo f = new Foo(); // shows "destructor" } static if (0) { Foo f = scoped!Foo(); // doesn't show "destructor" } static if (0) { // doesn't show "destructor" ubyte[__traits(classInstanceSize, Foo)] buf = void; Foo f = emplace!(Foo)(cast(void[])buf); } } //exit(0); } A temporary patch to this problem is to add a template constraint to std.typecons.scoped, that refuses to instantiate the template if the given class has a destructor. This means replacing: @system auto scoped(T, Args...)(Args args) if (is(T == class)) { With: @system auto scoped(T, Args...)(Args args) if (is(T == class) && !__traits(hasMember, T, "__dtor")) { --------------------------- The second problem may be seen with this program: import std.typecons: scoped; import std.conv: emplace; class Foo {} Foo bar() { static if (1) { // shows: Error: escaping reference to scope local f scope Foo f = new Foo(); } static if (0) { // shows no errors Foo f = scoped!Foo(); } static if (0) { // shows no errors ubyte[__traits(classInstanceSize, Foo)] buf = void; Foo f = emplace!(Foo)(cast(void[])buf); } return f; } void main() {} In the first case the DMD 2.049 compiler catches the bug, while in the two other cases no errors are generated. ------------------------------- I guess that once std.typecons.scoped works well, the std.conv.emplace may be removed from Phobos. ------------------------------- The main purpose of "scoped" is to increase performance, allowing stack allocation of a class instance (the Java VM solves this problem becoming smarter, performing escape analysis and stack-allocating object instances that don't escape the current scope. But this is not exactly the same thing as a well implemented scope/scoped feature, because the scoped documents that the programmer wants a class to be stack-allocated, this means that the compiler has to generate an error if a reference to this class escapes. While in Java if the programmer wants a scoped class instance, then the programmer has to be careful that no references escape, otherwise the class instance will be silently heap allocated). So this is benchmark code that may be used to compare the performance of the various implementations. To give a meaningful reference, the timings of this D benchmark must be compared to the baseline timings of the Java code below, run on a updated JavaVM using the -release switch too. // D2 code import std.typecons: scoped; import std.conv: emplace; final class Test { // 32 bytes each instance int i1, i2, i3, i4, i5, i6; this(int ii1, int ii2, int ii3, int ii4, int ii5, int ii6) { this.i1 = ii1; this.i2 = ii2; this.i3 = ii3; this.i4 = ii4; this.i5 = ii5; this.i6 = ii6; } void doSomething(int ii1, int ii2, int ii3, int ii4, int ii5, int ii6) { } } void main() { enum int N = 10_000_000; int i; while (i < N) { static if (1) { // 2.70 seconds, without testObject=null; 2.71 seconds Test testObject = new Test(i, i, i, i, i, i); } static if (0) { // 0.66 seconds, without testObject=null; 1.31 seconds scope Test testObject = new Test(i, i, i, i, i, i); } static if (0) { // 0.42 seconds, without testObject=null; 0.42 seconds // 0.24 seconds if I comment out the enforces inside emplace!() ubyte[__traits(classInstanceSize, Test)] buf = void; Test testObject = emplace!(Test)(cast(void[])buf, i, i, i, i, i, i); } static if (0) { // 0.69 // without testObject=null; 0.69 seconds Test testObject = scoped!Test(i, i, i, i, i, i); } static if (0) { // (Test is a struct) 0.19 seconds Test testObject = Test(i, i, i, i, i, i); } testObject.doSomething(i, i, i, i, i, i); testObject.doSomething(i, i, i, i, i, i); testObject.doSomething(i, i, i, i, i, i); testObject.doSomething(i, i, i, i, i, i); testObject = null; i++; } } -------------------------- // Java code final class Obj { int i1, i2, i3, i4, i5, i6; Obj(int ii1, int ii2, int ii3, int ii4, int ii5, int ii6) { this.i1 = ii1; this.i2 = ii2; this.i3 = ii3; this.i4 = ii4; this.i5 = ii5; this.i6 = ii6; } void doSomething(int ii1, int ii2, int ii3, int ii4, int ii5, int ii6) { } } final class Test { public static void main(String args[]) { final int N = 10_000_000; int i = 0; while (i < N) { Obj testObject = new Obj(i, i, i, i, i, i); testObject.doSomething(i, i, i, i, i, i); testObject.doSomething(i, i, i, i, i, i); testObject.doSomething(i, i, i, i, i, i); testObject.doSomething(i, i, i, i, i, i); // testObject = null; // no difference i++; } } } -------------------------- Currently the version that uses emplace is the fastest in D if all enforce() are commented out from the code of emplace itself. Being emplace a template (so it is not statically compiled into the Phobos lib, but compiled every time, this means that asserts are keeps inside it or removed according to the user compilation switches), and being its purpose essentially for performance, I suggest to replace all enforce() inside emplace() with normal asserts. A possible solution to the problems of scoped is to add back some compiler support to this feature, so the compiler is more aware of the situation. (For example a @scoped type attribute, that just forbid a class reference to escape the current scope. So all objects instantiated by std.typecons.scoped automatically have this attribute.) -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------