Function attribute best practices
Ali Çehreli
acehreli at yahoo.com
Mon Sep 12 16:14:42 UTC 2022
The following range Foo is trying to be helpful by adding as many
attributes as it can ('const' is missing because ranges cannot be
'const' because at least popFront() needs to be mutable):
import std.algorithm;
struct Foo(R) {
R r;
int i;
bool empty() @nogc nothrow pure @safe scope {
return r.empty;
}
auto front() @nogc nothrow pure @safe scope {
return r.front;
}
auto popFront() @nogc nothrow pure @safe scope {
r.popFront();
}
}
auto foo(R)(R r) {
return Foo!R(r);
}
int count;
void main() {
[ 1, 2 ]
.map!((i) {
++count; // <-- Impure
return i;
})
.foo;
}
Of course there are compilation errors inside the member functions
because e.g. r.front that it dispatches to is not pure (it touches the
module variable 'count'):
Error: `pure` function `deneme.Foo!(MapResult!(__lambda1,
int[])).Foo.front` cannot call impure function
`deneme.main.MapResult!(__lambda1, int[]).MapResult.front`
(Other attributes would cause similar issues if e.g. the lambda were @nogc.)
What are best practices here?
Is this accurate: Because Foo is a template, it should not put any
attribute on member functions? Or only member functions that use a
member that depends on a template parameter? And non-members that are
templates?
It is scary because Foo works just fine until it is used with impure code.
Is putting function attributes on unittest blocks for catching such issues?
@nogc nothrow pure @safe
unittest
{
// ...
}
No, it isn't because unless my unittest code is impure, I can't catch my
incorrect 'pure' etc. on my member functions.
Help! :)
Ali
More information about the Digitalmars-d-learn
mailing list