On Friday, 18 September 2020 at 14:14:31 UTC, Andrey Zherikov wrote:
It seems that dtor is called at exit from lazy delegate, not at exit form create():
======
    create()
    .do_something()
    .do_lazy()
    .do_something();
======
Output:
======
-> void test.main()
-> test.do_lazy(lazy S s)
-> test.create()
1 S test.S.this(int n)
<- test.create()
-> 1 test.do_something(S s)
<- 1 test.do_something(S s)
1 void test.S.~this()
===-1
<- test.do_lazy(lazy S s)
-> 1703096 test.do_something(S s)
<- 1703096 test.do_something(S s)
<- void test.main()
======

This doesn't even allow me to copy the value of 's' in do_lazy().

You're right, I missed a step: do_lazy() takes a S, not a scoped!S, so the conversion from scoped!S to S happens after create() has returned and before the value is used in do_lazy. This explains my confusion earlier.

D's lazy is essentially the same as a delegate or function, so you could* rewrite to this (writelns omitted for clarity):

S do_lazy(S function() s) {
    return s();
}

void main() {
    (() => cast(S)create()) // Here
    .do_lazy()
    .do_something();
}

On the marked line, the cast from scoped!S to S happens, the scoped!S goes out of scope and the destructor is called.

*There may be differences, but for this discussion these are not important.

--
  Simen

Reply via email to