Temporaries / struct RAII patterns
Witold
witold.baryluk+dlang at gmail.com
Mon Oct 16 00:04:59 UTC 2023
Not sure how to name the problem, but here it is.
I want to create a struct instance on a stack using a helper
function, manipulate it Fluent-like style, then destructor be
invoked, that will do something with its state.
I do not want to use `Unique`, because that will allocate actual
data on heap. And unique will have pointer to it. This is because
one can do release and move on Unique. I do not need (or want)
release or move.
I want something that can be done on a stack, but can be
manipulated and passed to functions, and destructor called once I
either go out of scope, or it is not used at all, and expression
/ statement ends.
```d
struct X {
string message;
string file;
int line;
string[string] kvs;
ref X F(string fmt, Args...)(const Args args) {
return this;
...
}
ref X KV(string k, string v) {
kvs[k] = v;
return this;
}
~this() {
DoSomething(&this, message, kvs);
}
}
X Foo(const string message, string file = __FILE__, int line =
__LINE__) {
return X(message, file, line)
}
X Foo(string fmt, Args...)(lazy Args args, string file =
__FILE__, int line = __LINE__) {
return X(message, file, line).F!(fmt, Args)(args);
}
void main() {
Foo("a");
Foo("b").kv("k1", "v1").kv("k2", "v2");
Foo!"c %d %s"(1, "ble").kv("k3", "v3");
}
```
I know I can do this:
```d
void main() {
{
scope x = Foo("a");
}
{
scope x = Foo("b");
x.KV("k1", "v1");
x.KV("k2", "v2");
}
}
```
But this is not going to scale (I will have many of these
statements in each file and function), and now requires me to
remember to put `scope` in front of each variable (`scope`
constraint keyword on struct type itself is deprecated), which is
error prone.
How do I ensure that `X` is not copied (i.e. on return from `f`),
or when doing `kvs` (and similar functions), and that `X` is
allocated on the stack, and is destroyed properly.
I also do want to be able to d the second form (with explicit
scope and calls to `kv`, i.e. when doing `kv` calls in a loop
from some other array or associative array).
I cannot use `ref` return on the `Foo`, because it the thing I am
returning either is not an lvalue, or any lvalue it could
reference would be on stack of `Foo`, so it will be returning
invalid reference after `Foo` returns.
Cheers.
More information about the Digitalmars-d
mailing list