www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Create class on stack

reply Johnson Jones <JJ Dynomite.com> writes:
using gtk, it has a type called value. One has to use it to get 
the value of stuff but it is a class. Once it is used, one 
doesn't need it.

Ideally I'd like to treat it as a struct since I'm using it in a 
delegate I would like to minimize unnecessary allocations. Is 
there any way to get D to allocate a class on the stack like a 
local struct?
Aug 05
next sibling parent angel <andrey.gelman gmail.com> writes:
On Saturday, 5 August 2017 at 17:08:32 UTC, Johnson Jones wrote:
 using gtk, it has a type called value. One has to use it to get 
 the value of stuff but it is a class. Once it is used, one 
 doesn't need it.

 Ideally I'd like to treat it as a struct since I'm using it in 
 a delegate I would like to minimize unnecessary allocations. Is 
 there any way to get D to allocate a class on the stack like a 
 local struct?
Emplace ? https://dlang.org/phobos/std_conv.html#emplace
Aug 05
prev sibling next sibling parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Saturday, 5 August 2017 at 17:08:32 UTC, Johnson Jones wrote:
 using gtk, it has a type called value. One has to use it to get 
 the value of stuff but it is a class. Once it is used, one 
 doesn't need it.

 Ideally I'd like to treat it as a struct since I'm using it in 
 a delegate I would like to minimize unnecessary allocations. Is 
 there any way to get D to allocate a class on the stack like a 
 local struct?
The easy way is through std.typecons.scoped [1]. Here be dragons, though, because classes are reference types. [1] https://dlang.org/phobos/std_typecons.html#.scoped
Aug 05
parent reply Johnson Jones <JJ Dynomite.com> writes:
On Saturday, 5 August 2017 at 23:09:09 UTC, Moritz Maxeiner wrote:
 On Saturday, 5 August 2017 at 17:08:32 UTC, Johnson Jones wrote:
 using gtk, it has a type called value. One has to use it to 
 get the value of stuff but it is a class. Once it is used, one 
 doesn't need it.

 Ideally I'd like to treat it as a struct since I'm using it in 
 a delegate I would like to minimize unnecessary allocations. 
 Is there any way to get D to allocate a class on the stack 
 like a local struct?
The easy way is through std.typecons.scoped [1]. Here be dragons, though, because classes are reference types. [1] https://dlang.org/phobos/std_typecons.html#.scoped
Thanks, I didn't think it created on the stack but it makes sense to do so. The only issue is that it escaping the reference?
Aug 05
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Sunday, 6 August 2017 at 01:18:50 UTC, Johnson Jones wrote:
 On Saturday, 5 August 2017 at 23:09:09 UTC, Moritz Maxeiner 
 wrote:
 On Saturday, 5 August 2017 at 17:08:32 UTC, Johnson Jones 
 wrote:
 using gtk, it has a type called value. One has to use it to 
 get the value of stuff but it is a class. Once it is used, 
 one doesn't need it.

 Ideally I'd like to treat it as a struct since I'm using it 
 in a delegate I would like to minimize unnecessary 
 allocations. Is there any way to get D to allocate a class on 
 the stack like a local struct?
The easy way is through std.typecons.scoped [1]. Here be dragons, though, because classes are reference types. [1] https://dlang.org/phobos/std_typecons.html#.scoped
Thanks, I didn't think it created on the stack but it makes sense to do so.
See the source [1] as to why: typeof(scoped!T) is a (non-copyable) struct that holds the memory for the T object inside it.
 The only issue is that it escaping the reference?
Yes, don't escape references, that's the reason for my comment:
 Here be dragons, though, because classes are reference types.
[1] https://github.com/dlang/phobos/blob/v2.075.0/std/typecons.d#L6613
Aug 05
parent reply FoxyBrown <Foxy Brown.IPT> writes:
On Sunday, 6 August 2017 at 02:10:31 UTC, Moritz Maxeiner wrote:
 On Sunday, 6 August 2017 at 01:18:50 UTC, Johnson Jones wrote:
 On Saturday, 5 August 2017 at 23:09:09 UTC, Moritz Maxeiner 
 wrote:
 On Saturday, 5 August 2017 at 17:08:32 UTC, Johnson Jones 
 wrote:
 using gtk, it has a type called value. One has to use it to 
 get the value of stuff but it is a class. Once it is used, 
 one doesn't need it.

 Ideally I'd like to treat it as a struct since I'm using it 
 in a delegate I would like to minimize unnecessary 
 allocations. Is there any way to get D to allocate a class 
 on the stack like a local struct?
The easy way is through std.typecons.scoped [1]. Here be dragons, though, because classes are reference types. [1] https://dlang.org/phobos/std_typecons.html#.scoped
Thanks, I didn't think it created on the stack but it makes sense to do so.
See the source [1] as to why: typeof(scoped!T) is a (non-copyable) struct that holds the memory for the T object inside it.
 The only issue is that it escaping the reference?
Yes, don't escape references, that's the reason for my comment:
 Here be dragons, though, because classes are reference types.
[1] https://github.com/dlang/phobos/blob/v2.075.0/std/typecons.d#L6613
I don't think you understand what I'm saying. If I use this method to create a "reference" type on the stack rather than the heap, is the only issue worrying about not having that variable be used outside that scope(i.e., have it "escape")? Obviously since it's on the stack it will be invalid after the function call, but I'm talking about other pitfalls. I don't see any but I want to be sure. Also, does it do the allocation at compile time(reserve space on the stack for the variable along with all the others or does it "allocate" space on the stack at runtime?... which is slightly slower).
Aug 05
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 6 August 2017 at 02:19:19 UTC, FoxyBrown wrote:
 Also, does it do the allocation at compile time(reserve space 
 on the stack for the variable along with all the others or does 
 it "allocate" space on the stack at runtime?... which is 
 slightly slower).
compile time. It works like a static array of the appropriate size. though the cost if ti was at runtime is small regardless. I think it is just a register subtract.
Aug 05
parent FoxyBrown <Foxy Brown.IPT> writes:
On Sunday, 6 August 2017 at 02:32:05 UTC, Adam D. Ruppe wrote:
 On Sunday, 6 August 2017 at 02:19:19 UTC, FoxyBrown wrote:
 Also, does it do the allocation at compile time(reserve space 
 on the stack for the variable along with all the others or 
 does it "allocate" space on the stack at runtime?... which is 
 slightly slower).
compile time. It works like a static array of the appropriate size. though the cost if ti was at runtime is small regardless. I think it is just a register subtract.
yeah, I know, but no need for it ;) Still better than the heap but was just curious ;) No need to waste cycles if it's not necessary.
Aug 05
prev sibling parent Moritz Maxeiner <moritz ucworks.org> writes:
On Sunday, 6 August 2017 at 02:19:19 UTC, FoxyBrown wrote:
 [...]

 I don't think you understand what I'm saying.

 If I use this method to create a "reference" type on the stack 
 rather than the heap, is the only issue worrying about not 
 having that variable be used outside that scope(i.e., have it 
 "escape")?
It's the only one I'm aware of OTTOMH. If you encounter others, a bug report would be appreciated.
Aug 06
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-08-05 19:08, Johnson Jones wrote:
 using gtk, it has a type called value. One has to use it to get the
 value of stuff but it is a class. Once it is used, one doesn't need it.

 Ideally I'd like to treat it as a struct since I'm using it in a
 delegate I would like to minimize unnecessary allocations. Is there any
 way to get D to allocate a class on the stack like a local struct?
Prefix the variable declaration with "scope": scope foo = new Object; -- /Jacob Carlborg
Aug 06
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Sunday, 6 August 2017 at 15:24:55 UTC, Jacob Carlborg wrote:
 On 2017-08-05 19:08, Johnson Jones wrote:
 using gtk, it has a type called value. One has to use it to 
 get the
 value of stuff but it is a class. Once it is used, one doesn't 
 need it.

 Ideally I'd like to treat it as a struct since I'm using it in 
 a
 delegate I would like to minimize unnecessary allocations. Is 
 there any
 way to get D to allocate a class on the stack like a local 
 struct?
Prefix the variable declaration with "scope": scope foo = new Object;
If you use this option, do be aware that this feature has been scheduled for future deprecation [1]. It's likely going to continue working for quite a while (years), though. [1] https://dlang.org/deprecate.html#scope%20for%20allocating%20classes%20on%20the%20stack
Aug 06
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2017-08-06 17:47, Moritz Maxeiner wrote:

 If you use this option, do be aware that this feature has been scheduled
 for future deprecation [1].
 It's likely going to continue working for quite a while (years), though.
It's used all over the place in the DMD code base. -- /Jacob Carlborg
Aug 07
parent Moritz Maxeiner <moritz ucworks.org> writes:
On Monday, 7 August 2017 at 10:42:03 UTC, Jacob Carlborg wrote:
 On 2017-08-06 17:47, Moritz Maxeiner wrote:

 If you use this option, do be aware that this feature has been 
 scheduled
 for future deprecation [1].
 It's likely going to continue working for quite a while 
 (years), though.
It's used all over the place in the DMD code base.
I don't see how that's a reason for increasing the amount of code that needs to be changed if/when scope classes are deprecated. Mike's argument holds, though (if the loophole I pointed out gets fixed and scope classes are removed from the future deprecation list).
Aug 07
prev sibling next sibling parent reply Mike <none none.com> writes:
On Sunday, 6 August 2017 at 15:47:43 UTC, Moritz Maxeiner wrote:

 If you use this option, do be aware that this feature has been 
 scheduled for future deprecation [1].
 It's likely going to continue working for quite a while 
 (years), though.

 [1] 
 https://dlang.org/deprecate.html#scope%20for%20allocating%20classes%20on%20the%20stack
FYI: http://forum.dlang.org/post/np1fll$ast$1 digitalmars.com "Yes, it will have to be updated - but I didn't want to adjust it before DIP1000 spec is finalized. Rationale that was driving deprecation of scope storage class is becoming obsolete with DIP1000 implemented but not before." Mike
Aug 07
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Monday, 7 August 2017 at 10:50:21 UTC, Mike wrote:
 On Sunday, 6 August 2017 at 15:47:43 UTC, Moritz Maxeiner wrote:

 If you use this option, do be aware that this feature has been 
 scheduled for future deprecation [1].
 It's likely going to continue working for quite a while 
 (years), though.

 [1] 
 https://dlang.org/deprecate.html#scope%20for%20allocating%20classes%20on%20the%20stack
FYI: http://forum.dlang.org/post/np1fll$ast$1 digitalmars.com "Yes, it will have to be updated - but I didn't want to adjust it before DIP1000 spec is finalized. Rationale that was driving deprecation of scope storage class is becoming obsolete with DIP1000 implemented but not before."
Thanks, I wasn't aware of this. I tried fooling around scope classes and DIP1000 for a bit and was surprised that this is allowed: --- import core.stdc.stdio : printf; import std.algorithm : move; class A { int i; this() safe { i = 0; } } void inc(scope A a) safe { a.i += 1; } void print(scope A a) trusted { printf("A %x: %d\n", cast(void*) a, a.i); } auto makeA() safe { scope a = new A(); a.print(); return move(a); } void main() safe { auto a = makeA(); foreach (i; 0..10) { a.print(); a.inc(); } } --- You can still create a (scope) class on the stack, escape a reference to it using `move` and use it afterwards, all within the rules of safe, so I'm not convinced that the reason for deprecating scoped classes is gone yet. Compare this to `scoped`, which behaves as expected (since it wraps the reference type object in a value type): --- import std.typecons : scoped; auto makeA() trusted { auto a = scoped!A(); a.print(); return move(a); } void main() trusted { auto a = makeA(); foreach (i; 0..10) { a.print(); a.inc(); } } ---
Aug 07
next sibling parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Monday, 7 August 2017 at 13:40:18 UTC, Moritz Maxeiner wrote:
 Thanks, I wasn't aware of this. I tried fooling around scope 
 classes and DIP1000 for a bit and was surprised that this is 
 allowed:

 ---
 import core.stdc.stdio : printf;
 import std.algorithm : move;

 class A
 {
 	int i;

 	this()  safe
 	{
 		i = 0;
 	}
 }

 void inc(scope A a)  safe
 {
 	a.i += 1;
 }

 void print(scope A a)  trusted
 {
 	printf("A %x: %d\n", cast(void*) a, a.i);
 }

 auto makeA()  safe
 {
 	scope a = new A();
 	a.print();
 	return move(a);
 }

 void main()  safe
 {
 	auto a = makeA();
 	foreach (i; 0..10) {
 		a.print();
 		a.inc();
 	}
 }
 ---

 You can still create a (scope) class on the stack, escape a 
 reference to it using `move` and use it afterwards, all within 
 the rules of  safe, so I'm not convinced that the reason for 
 deprecating scoped classes is gone yet.
 Compare this to `scoped`, which behaves as expected (since it 
 wraps the reference type object in a value type):

 ---
 import std.typecons : scoped;

 auto makeA()  trusted
 {
 	auto a = scoped!A();
 	a.print();
 	return move(a);
 }

 void main()  trusted
 {
 	auto a = makeA();
 	foreach (i; 0..10) {
 		a.print();
 		a.inc();
 	}
 }
 ---
Forgot to add the runtime output after compiling with `dmd a.d -dip1000`: For `scope A`: A 198d1568: 0 A 198d1568: 0 A 198d1568: 1 A 198d1568: 2 A 198d1568: 3 A 198d1568: 4 A 198d1568: 5 A 198d1568: 6 A 198d1568: 7 A 198d1568: 8 A 198d1568: 9 For `scoped!A`: A 8de538b8: 0 A 8de53940: 0 A 8de53940: 1 A 8de53940: 2 A 8de53940: 3 A 8de53940: 4 A 8de53940: 5 A 8de53940: 6 A 8de53940: 7 A 8de53940: 8 A 8de53940: 9
Aug 07
parent reply Mike <none none.com> writes:
On Monday, 7 August 2017 at 13:42:33 UTC, Moritz Maxeiner wrote:

 You can still create a (scope) class on the stack, escape a 
 reference to it using `move` and use it afterwards, all within 
 the rules of  safe, so I'm not convinced that the reason for 
 deprecating scoped classes is gone yet.
 Compare this to `scoped`, which behaves as expected (since it 
 wraps the reference type object in a value type):
Looks like a bug to me. I recommend submitting a bug report and tag it somehow with "scope" and/or "DIP1000". It appears Walter is giving any bugs with scope/DIP1000 priority. Mike
Aug 07
parent Moritz Maxeiner <moritz ucworks.org> writes:
On Monday, 7 August 2017 at 22:02:07 UTC, Mike wrote:
 On Monday, 7 August 2017 at 13:42:33 UTC, Moritz Maxeiner wrote:

 You can still create a (scope) class on the stack, escape a 
 reference to it using `move` and use it afterwards, all 
 within the rules of  safe, so I'm not convinced that the 
 reason for deprecating scoped classes is gone yet.
 Compare this to `scoped`, which behaves as expected (since it 
 wraps the reference type object in a value type):
Looks like a bug to me. I recommend submitting a bug report and tag it somehow with "scope" and/or "DIP1000". It appears Walter is giving any bugs with scope/DIP1000 priority.
Thanks for the feedback, done: https://issues.dlang.org/show_bug.cgi?id=17730
Aug 07
prev sibling parent Johan Engelen <j j.nl> writes:
On Monday, 7 August 2017 at 13:40:18 UTC, Moritz Maxeiner wrote:
 Thanks, I wasn't aware of this. I tried fooling around scope 
 classes and DIP1000 for a bit and was surprised that this is 
 allowed:
Thanks for the test case :-) It was fun to see that ASan can catch this bug too. Because writing the blog post about ASan will take quite some time still, I've pasted the demonstration below (there is a big big big caveat that will need more work from LDC's side, but you'll have to wait until the blog article). Simplified your code for the demonstration: ``` class A { int i; } void inc(A a) safe { a.i += 1; // Line 6 } auto makeA() safe { // Line 9 import std.algorithm : move; scope a = new A(); return move(a); } void main() safe { auto a = makeA(); a.inc(); // Line 17 } ``` ```
 ldc2 -fsanitize=address -disable-fp-elim scopeclass.d -g -O1 
 -dip1000
 ASAN_OPTIONS=detect_stack_use_after_return=1 ./scopeclass 2>&1 
 | ddemangle
================================================================= ==11446==ERROR: AddressSanitizer: stack-use-after-return on address 0x000104929050 at pc 0x0001007a9837 bp 0x7fff5f457510 sp 0x7fff5f457508 READ of size 4 at 0x000104929050 thread T0 #0 0x1007a9836 in safe void scopeclass.inc(scopeclass.A) scopeclass.d:6 #1 0x1007a9a20 in _Dmain scopeclass.d:17 #2 0x1008e40ce in _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv (scopeclass:x86_64+0x10013c0ce) #3 0x7fff9729b5ac in start (libdyld.dylib:x86_64+0x35ac) Address 0x000104929050 is located in stack of thread T0 at offset 80 in frame #0 0x1007a984f in pure nothrow nogc safe scopeclass.A scopeclass.makeA() scopeclass.d:9 ```
Aug 08
prev sibling parent reply ANtlord <antlord92 gmail.com> writes:
On Sunday, 6 August 2017 at 15:47:43 UTC, Moritz Maxeiner wrote:
 If you use this option, do be aware that this feature has been
> scheduled for future deprecation [1].
 It's likely going to continue working for quite a while 
 (years), though.

 [1] 
 https://dlang.org/deprecate.html#scope%20for%20allocating%20classes%20on%20the%20stack
I can't understand. Why is moved a scope allocation to a library. I'm pretty sure it should be a language feature.
Aug 07
parent Moritz Maxeiner <moritz ucworks.org> writes:
On Tuesday, 8 August 2017 at 05:37:41 UTC, ANtlord wrote:
 On Sunday, 6 August 2017 at 15:47:43 UTC, Moritz Maxeiner wrote:
 If you use this option, do be aware that this feature has been
> scheduled for future deprecation [1].
 It's likely going to continue working for quite a while 
 (years), though.

 [1] 
 https://dlang.org/deprecate.html#scope%20for%20allocating%20classes%20on%20the%20stack
I can't understand. Why is moved a scope allocation to a library. I'm pretty sure it should be a language feature.
The reason is given at the link under "Rationale": --- scope was an unsafe feature. A reference to a scoped class could easily be returned from a function without errors, which would make using such an object undefined behavior due to the object being destroyed after exiting the scope of the function it was allocated in. To discourage it from general-use but still allow usage when needed a library solution was implemented. Note that scope for other usages (e.g. scoped variables) is unrelated to this feature and will not be deprecated. --- Do note that - as Mike pointed out - this rationale does predate DIP1000 escape analysis and is largely invalidated by it for safe code. Another reason to use the library type is the ability to move the class object around via std.algorithm.move (if you need such C++ style behaviour); I'm not sure whether scope classes will get this feature (I have argued for it at the bug report linked to in my response to Mike), but I wouldn't count on it.
Aug 08