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.
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:
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.