Comment #0 by alphaglosined — 2023-06-18T10:29:16Z
This is something I've run into while using @mustuse.
The struct could very well be used, without any error being checked.
While I'm not sure opCast(T:bool) should always be used for this purpose, it should be possible to require the compiler to error if it does not occur (although it would be nice not to do this when it comes from opApply/opApplyReverse.
The reason I have used the opCast is because of its integration into if statements which makes it quite nice to use, when it isn't crashing the program (due to error not being checked).
Without this, an ``alias this`` to a method would in theory be enough to keep the compiler happy even if it's null.
Comment #1 by dkorpel — 2023-06-18T10:53:27Z
I don't follow, can you give a code example?
Comment #2 by alphaglosined — 2023-06-18T11:02:50Z
Okay lets say we have an error struct:
```d
@mustuse struct Result(T) {
private T* value;
bool isNull() {
return value is null;
}
ref T get() {
return *value;
}
alias get this;
}
```
We pass it into our function somehow (in this case I'll go with a parameter):
```d
void myFunction(Result!int arg) {
writeln(arg.get);
}
```
Great, you use the variable! But the whole reason for @mustuse is so that we can guarantee that error checks have been handled in some way.
So we want some way for a function (like the isNull in the above example) to have to be checked, not just a method being called.
Without this, you will end up with runtime errors instead of compiler ones (like I have been experiencing).
Comment #3 by dkorpel — 2023-06-18T12:09:04Z
@mustuse is supposed to prevent discarding values of that type. I'm not a fan of tacking on additional rules about `opCast` to a feature that should be simple and orthogonal. It looks like what you really want is type state, which Timon Gehr has been advocating for, but that would require a DIP.
Comment #4 by alphaglosined — 2023-06-18T12:19:00Z
I'm not saying it has to be opCast, that's just my use case as it works for me at runtime as-is.
Basically, I need a way to tell the compiler, if any of these specific methods are not called immediately, then this value has been discarded even if other methods have been called.
Comment #5 by snarwin+bugzilla — 2023-06-18T19:19:23Z
Dennis is correct. This is completely outside the purview of @mustuse. What you are asking for is a guarantee not just that the object has been used, but that it has been used *correctly* (according to some programmer-defined criteria).
For this specific example, I think the best solution is to redesign your Result type so that it is impossible to access the wrapped value without performing a null check. Here's one possible way to do so:
---
import core.attribute, std.stdio;
@mustuse struct Result {
private int* value;
bool isNull() => value is null;
int opApply(scope int delegate(int) dg)
{
if (value is null) return 0;
return dg(*value);
}
}
Result getResult() => Result(new int(42));
void main()
{
auto r = getResult();
foreach (int n; r)
writeln("got ", n);
}
---
Comment #6 by robert.schadek — 2024-12-13T19:29:43Z