First thing first, I'm talking about code with -preview=dip1000
. Make sure that is on if you test these.
There are times when you want to treat data in a scoped struct as non-scoped. Example:
struct MyType
{ // Struct designed so that this will never point to local data
private @system int* _content;
// This might.
int* otherPtr;
@trusted this(return ref int i)
{ _content = new int(i);
otherPtr = &i;
}
// Note, not marked RETURN scope. Should return an unscoped pointer.
@trusted scope content(){return _content;}
}
@safe void main()
{ int* outer;
if(true)
{ int inner;
// Inferred as scope, which is intended
auto myVar = MyType(inner);
// Should be allowed
outer = myVar.content;
}
}
This pattern is perfectly @safe and makes sense. One problem though - it does not compile. Auto-inference being on, the compiler goes on to infer that MyType.content
is return scope
.
In this case, it would be easy to avoid this by simply disabling auto-inference by giving the function an explicit type: @trusted pure nothrow @nogc scope int* content()
. This only works in non-templated functions and types though. We sometimes need to achieve the same inside a template too. We can do that:
@trusted scope content()
{ auto tmp = _content;
return tmp;
}
This works. The compiler does not really track lifetimes of the variables inside @trusted
or @system
functions. But it still tries to be smart if directly returning a pointer from the struct.
Frankly, this violates the principle of least astonishment pretty badly. Can't we just have a simple rule: if the function is explicitly marked @trusted
or @system
, NO scope
or return
attributes are inferred whatsoever?