www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Struct Constructor Lazy

reply Jiyan <jiyan jiyan.info> writes:
Hey there:)

i want to know whether the following is somehow possible:
structs dont have default constructors, i know so:

struct A
{
int field;
this(int i){field = getDataFromFile("file.txt");}
}

A instance = A(0);

Here comes my issue:
when A(0) is called I would want here optimal performance, so 
there doesnt even need to be a value pushed on the stack (i=0), 
what would be like having a constructor with zero arguments (i is 
never used!).
Im pretty new to D, can somebody tell me how i would do this?
Is this(lazy int i){ ... a solution?
Jul 12
next sibling parent reply Biotronic <simen.kjaras gmail.com> writes:
On Wednesday, 12 July 2017 at 11:00:54 UTC, Jiyan wrote:
 Hey there:)

 i want to know whether the following is somehow possible:
 structs dont have default constructors, i know so:

 struct A
 {
 int field;
 this(int i){field = getDataFromFile("file.txt");}
 }

 A instance = A(0);

 Here comes my issue:
 when A(0) is called I would want here optimal performance, so 
 there doesnt even need to be a value pushed on the stack (i=0), 
 what would be like having a constructor with zero arguments (i 
 is never used!).
 Im pretty new to D, can somebody tell me how i would do this?
 Is this(lazy int i){ ... a solution?
The traditional solution is static opCall: struct A { int field; static A opCall() { A result; result.field = getDataFromFile("file.txt"); return result; } } A instance = A(); I believe I've heard this is frowned upon these days, but I don't know of a better solution. For optimal speed you might also want to skip default initialization of result, by writing A result = void;. I would be surprised if the optimizer wasn't able to optimize away the useless parameter though - have you looked at the generated assembly? -- Biotronic
Jul 12
next sibling parent reply Jiyan <jiyan jiyan.info> writes:
On Wednesday, 12 July 2017 at 11:18:08 UTC, Biotronic wrote:
 On Wednesday, 12 July 2017 at 11:00:54 UTC, Jiyan wrote:
 [...]
The traditional solution is static opCall: struct A { int field; static A opCall() { A result; result.field = getDataFromFile("file.txt"); return result; } } A instance = A(); I believe I've heard this is frowned upon these days, but I don't know of a better solution. For optimal speed you might also want to skip default initialization of result, by writing A result = void;. I would be surprised if the optimizer wasn't able to optimize away the useless parameter though - have you looked at the generated assembly? -- Biotronic
Hey, yes i did but to be honest i used dmd in debug version. The thing about the static one, is that it creates a local object A isnt that a performance issue itself - or am i wrong - im confused actually :P?
Jul 12
parent reply Biotronic <simen.kjaras gmail.com> writes:
On Wednesday, 12 July 2017 at 11:34:45 UTC, Jiyan wrote:
 Hey,
 yes i did but to be honest i used dmd in debug version.
 The thing about the static one, is that it creates a local 
 object A isnt that a performance issue itself - or am i wrong - 
 im confused actually :P?
Debug = no optimization. Looking at the generated assembly in a debug build is worthless. You raise a valid point. In a debug build, you're probably right - it will need to copy the temporary to the target. With optimizations enabled, NRVO[0] will populate the target directly, resulting in roughly the equivalent of this code: struct A { int field; static void opCall(A* p) { p.field = getDataFromFile("file.txt"); } } A a; A(&a); If the function is inlined, the whole problem is of course moot. There are probably other optimizations that can interfere with what I've described. -- Biotronic [0]: https://en.wikipedia.org/wiki/Return_value_optimization
Jul 12
next sibling parent reply Jiyan <jiyan jiyan.info> writes:
Thank you, one last question:
If i declare the parameter as ref i, then there shouldnt be any 
overhead wouldnt it?

Thanks :)
Jul 12
parent Biotronic <simen.kjaras gmail.com> writes:
On Wednesday, 12 July 2017 at 12:02:37 UTC, Jiyan wrote:
 Thank you, one last question:
 If i declare the parameter as ref i, then there shouldnt be any 
 overhead wouldnt it?

 Thanks :)
That would be basically the exact equivalent - instead of passing an int, you'll be passing a pointer. -- Biotronic
Jul 12
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 12 July 2017 at 11:57:33 UTC, Biotronic wrote:
 Debug = no optimization.
That's not really true, you can have an optimized debug build. dmd's -debug, -g, and -O switches are all independent. -debug turns on blocks labeled with the `debug` switch in code. -g adds info for a debugger to read. -O turns on optimizations. You can use any combination of those.
 Looking at the generated assembly in a debug build is worthless.
I don't agree - looking at the generated assembly would put to rest all these questions. But before doing that, you should show that the performance is actually bad. I can't imagine sending a zero argument (whether in a register or pushed to the stack) would ever be a serious problem.
Jul 12
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 12 July 2017 at 11:18:08 UTC, Biotronic wrote:
 The traditional solution is static opCall:
That's bug city... the dummy argument is better, or a named static factory function. Foo foo = Foo; Foo foo = Foo(); those are different with static opCall. It also conflicts with constructors and non-static opCall.
Jul 12
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 12 July 2017 at 11:00:54 UTC, Jiyan wrote:
 when A(0) is called I would want here optimal performance, so 
 there doesnt even need to be a value pushed on the stack (i=0), 
 what would be like having a constructor with zero arguments (i 
 is never used!).
This is so, so irrelevant. Even if it isn't optimized out (which it probably is), pushing a zero to the stack is so extremely cheap that you'd probably not notice it, especially compared to reading something from a file.
 Im pretty new to D, can somebody tell me how i would do this?
 Is this(lazy int i){ ... a solution?
That's actually more expensive than just sending the zero!
Jul 12