digitalmars.D.learn - Scope & Structs
- Salih Dincer (36/36) Oct 12 I have a small program like below. Everything works as it should
- Salih Dincer (6/8) Oct 12 Edit: It seems like scope is ineffective in structures. In fact,
- Nick Treleaven (5/13) Oct 12 Declaring a `scope SomeClass` initialized with `new` is a special
- Salih Dincer (11/18) Oct 12 Actually, I almost never use the new operator except with(). I
- Richard (Rikki) Andrew Cattermole (5/14) Oct 12 ``scope`` offers protection from escaping.
- Richard (Rikki) Andrew Cattermole (3/3) Oct 12 You are not wrong, when it is a struct, it is being heap allocated.
- Salih Dincer (14/16) Oct 12 Sorry for prolonging the topic. I am very curious about your
- Nick Treleaven (26/33) Oct 13 Just to note that `new` does not give you a struct, it gives a
- Richard (Rikki) Andrew Cattermole (113/133) Oct 18 Sorry for not replying sooner, COVID has not been a fun virus for my
- Salih Dincer (5/25) Oct 19 Thank you for your answer. I also had a minor operation and I am
I have a small program like below. Everything works as it should in classes; even if I call the structure with the new operator. But if I stop using classes, scope doesn't work properly! ```d class/* STEP2 struct//*/ Foo { this(int i) { i.writefln!"Object %s is created..."; } ~this() { writeln("Object was deleted!"); } } import std.stdio; void main() { write("call "); writeln("return ", loop); } auto loop() { enum func = __FUNCTION__; func.writeln; for (auto i = 1; i != 3; ++i) { scope // STEP1 auto foo = new Foo(i); } return func; } ``` Please put a comment (//) mark at the beginning of the line that says STEP1 and then STEP2. Then change STEP1 back to its previous state, that is, enable the scope. You will sense that something is wrong... Why doesn't it work correctly in structs? Or is scope the default in structs? SDB 79
Oct 12
On Saturday, 12 October 2024 at 12:02:04 UTC, Salih Dincer wrote:... even if I call the structure with the new operator. But if I stop using classes, scope doesn't work properly!Edit: It seems like scope is ineffective in structures. In fact, if there is the new operator, it is as if scope does not exist, and if it is construct without the new operator, it is as if scope does exist; is this normal? SDB 79
Oct 12
On Saturday, 12 October 2024 at 12:10:17 UTC, Salih Dincer wrote:On Saturday, 12 October 2024 at 12:02:04 UTC, Salih Dincer wrote:Declaring a `scope SomeClass` initialized with `new` is a special case to allocate on the stack: https://dlang.org/spec/attribute.html#scope-class-var... even if I call the structure with the new operator. But if I stop using classes, scope doesn't work properly!Edit: It seems like scope is ineffective in structures. In fact, if there is the new operator, it is as if scope does not exist, and if it is construct without the new operator, it is as if scope does exist; is this normal?If you want stack allocation of structs, why use `new`?
Oct 12
On Saturday, 12 October 2024 at 13:08:03 UTC, Nick Treleaven wrote:If you want stack allocation of structs, why use `new`?Actually, I almost never use the new operator except with(). I was surprised because it seemed inconsistent here and wanted to share my experiment. On Saturday, 12 October 2024 at 13:11:52 UTC, Richard (Rikki) Andrew Cattermole wrote:You are not wrong, when it is a struct, it is being heap allocated. Looks like the optimization for classes, hasn't been applied to structs. https://issues.dlang.org/show_bug.cgi?id=24806So if `scope` is a facility for classes, it should give an error when used in structures. Is that so? I understand this from the issue you opened. SDB 79
Oct 12
On 13/10/2024 3:12 AM, Salih Dincer wrote:You are not wrong, when it is a struct, it is being heap allocated. Looks like the optimization for classes, hasn't been applied to structs. https://issues.dlang.org/show_bug.cgi?id=24806 <https:// issues.dlang.org/show_bug.cgi?id=24806> So if |scope| is a facility for classes, it should give an error when used in structures. Is that so? I understand this from the issue you opened.``scope`` offers protection from escaping. It is functioning correctly. The problem is an optimization you want, isn't being applied by the frontend, but is elsewhere.
Oct 12
You are not wrong, when it is a struct, it is being heap allocated. Looks like the optimization for classes, hasn't been applied to structs. https://issues.dlang.org/show_bug.cgi?id=24806
Oct 12
On Saturday, 12 October 2024 at 13:11:52 UTC, Richard (Rikki) Andrew Cattermole wrote:You are not wrong, when it is a struct, it is being heap allocated.Sorry for prolonging the topic. I am very curious about your answers along with your patience... Can we say that structs are in the stack (LIFO) as long as we do not use the new operator? Also, should using scope in structures cause a change? I never seen it does! However, there is no incompatibility here: Whether it is a class or a struct, when you use the new operator, the first run constructor becomes the first run destructor with FIFO logic. You can reverse this situation with scope (but only in classes). By reverse I don't mean LIFO! In fact, the correct expression is that when you are done with the object, it is removed. Thanks, SDB 79
Oct 12
On Sunday, 13 October 2024 at 05:12:32 UTC, Salih Dincer wrote:Can we say that structs are in the stack (LIFO) as long as we do not use the new operator?Just to note that `new` does not give you a struct, it gives a struct pointer. Structs use the stack when declared inside a stack-allocated function frame. A struct B field inside another struct A will use A's storage. A could be allocated on the heap with `new`.Also, should using scope in structures cause a change? I never seen it does!With -dip1000 and safe, `scope` is meaningful for a struct - it applies to the fields of a struct. However, it can be inferred too. ```d safe: struct S { int* i; } int* f() { int i; scope s = S(&i); // OK (scope will be inferred if missing) return s.i; // error } ```However, there is no incompatibility here: Whether it is a class or a struct, when you use the new operator, the first run constructor becomes the first run destructor with FIFO logic.I don't think so for `new`: "Important: The order in which the garbage collector calls destructors for unreferenced objects is not specified." From https://dlang.org/spec/class.html#destructors
Oct 13
On 13/10/2024 6:12 PM, Salih Dincer wrote:On Saturday, 12 October 2024 at 13:11:52 UTC, Richard (Rikki) Andrew Cattermole wrote:Sorry for not replying sooner, COVID has not been a fun virus for my mind to have. When a variable is declared with a struct that needs cleanup, it effectively rewrites the following statements into a try finally: ```d void main() { S s = 0; try { if (true) return 0; } finally s.~this(); return 0; } ``` There are simplifications of this, without the need for the try finally, but we can ignore it for the purposes of this explanation. The same can be seen with a class that was allocated on the stack: ```d void main() { scope C c = new C; try { if (true) return 0; } finally delete c; return 0; } ``` Nested: ```d void main() { scope C c = new C; try { S s = 0; try { if (true) return 0; } finally s.~this(); } finally delete c; // aggregate dtor is called return 0; } ``` How nesting destroys fields: ```d class C : Object { S s; scope ~this() // user dtor { } scope ~this() // field dtor { this.s.~this(); } scope ~this() // aggregate dtor { // user dtor , field dtor this.~this() , this.~this(); } } ``` This should cover the ordering on the stack. If you have any further questions about it please ask. ---------------------------------------------You are not wrong, when it is a struct, it is being heap allocated.Sorry for prolonging the topic. I am very curious about your answers along with your patience... Can we say that structs are in the stack (LIFO) as long as we do not use the new operator? Also, should using scope in structures cause a change? I never seen it does! However, there is no incompatibility here: Whether it is a class or a struct, when you use the new operator, the first run constructor becomes the first run destructor with FIFO logic. You can reverse this situation with scope (but only in classes). By reverse I don't mean LIFO! In fact, the correct expression is that when you are done with the object, it is removed. Thanks, SDB 79Also, should using scope in structures cause a change? I never seen it does!The scope attribute in a declaration body such as a struct, class or union applies to the method, for its this pointer. It does not apply to the fields. Generally speaking, scope should not be on a type or field declaration. Good: ```d struct S { int fields; private shared int* thing; export safe nothrow nogc: this() scope {} void method1() scope {} scope { // ok void method2() {} } scope: // no indication at function that it is applied, not great void method3() {} } ``` Bad: ```d struct S { export safe nothrow nogc scope: int fields; this() {} void method() {} } shared scope struct S { export safe nothrow nogc: int fields; this() {} void method() {} } ```
Oct 18
On Friday, 18 October 2024 at 07:43:47 UTC, Richard (Rikki) Andrew Cattermole wrote:Sorry for not replying sooner, COVID has not been a fun virus for my mind to have. When a variable is declared with a struct that needs cleanup, it effectively rewrites the following statements into a try finally: ```d void main() { S s = 0; try { if (true) return 0; } finally s.~this(); return 0; } ```Thank you for your answer. I also had a minor operation and I am fine now. I hope you are fine too. SDB 79
Oct 19