Structural Function Attributes
Q. Schroll via Digitalmars-d
digitalmars-d at puremagic.com
Mon Jun 6 13:31:52 PDT 2016
I'm pretty sure, someone before me has thought about that. Take
pure as an example, but you can replace it by any subset of pure,
nothrow, @safe and @nogc.
Main reason: Assume a struct with simple opApply
struct R
{
// pure -> error: dg possibly impure
int opApply(scope int delegate(size_t i, ref int x) dg)
{ ... }
}
which does only pure operations modulo calls of dg. Then, opApply
is pure if dg is pure.
Further assume a function using that opApply
int wannaBePure(R r) // pure -> error: R.opApply possibly
impure
{
int s = 0;
foreach (i, x; r) s += i*x;
return s;
}
PROBLEM 1: Nobody wants to supply all possible combinations of
attributes the delegate can have. Worse, if the struct R is a
template, it is nearly impossible for e.g. @nogc.
-> Use a template opApply to infer attributes.
PROBLEM 2: Specific to opApply, you cannot infer the foreach
types if opApply is a template; even a trivial one or opApply(DG
: int delegate(size_t, ref int))(scope DG dg) does not do this.
-> Template is an improper solution.
PROBLEM 3: Templates cannot be virtual.
-> Template is not a solution at all.
PROPOSED SOLUTION: For each (strong) attribute like pure, support
a (weak) structural one, meaning that the function is pure if the
parameters are.
PLUS: Always infer structural attributes for functions with
delegate/function parameters, but let the explicit notion be
possible, as the programmer could want to guarantee structural
pureness, cf. attribute inference on function templates can be
denoted explicitly.
FUN FACT: The structural attribute is actually not that weak. It
makes (maybe many) functions pure, that wouldn't be otherwise.
Back to the example:
struct R
{
struct(pure) // dg pure -> opApply pure
int opApply(scope int delegate(size_t i, ref int x) dg)
{ ... }
}
int wannaBePure(R r) pure // pure opApply -> pure
{
int s = 0;
foreach (i, x; r)
s += i*x; // pure stuff -> pure delegate -> pure opApply
return s;
}
From what I see, struct(pure) is perfectly sound with inheriting
and overwriting.
To the overloading set, it can be seen as supplying both versions.
As the code is not affected (only optimizing), this should be
easy to handle in object code. The function has to be marked as
sturct(whatever).
The function must be compiled as it wouldn't have the attribute.
Outside, it can be decided at compile-time.
Ideas?
More information about the Digitalmars-d
mailing list