On Saturday, 28 July 2012 at 20:22:27 UTC, Jonathan M Davis wrote:
@property auto save()
{
import std.conv;
alias typeof((*_range).save) S;
static assert(isForwardRange!S, S.stringof ~ " is not a
forward range.");
@trusted {auto mem = new void[S.sizeof];}
static if(isSafelyCallable!((){(*_range).save;}))
{
@trusted { emplace!S(mem, cast(S)(*_range).save); }
}
else
{
emplace!S(mem, cast(S)(*_range).save);
}
@trusted {return RefRange!S(cast(S*)mem.ptr);}
}
It's still a bit ugly, but it's far better than what we can
currently do. As
it stands, you can't even put the emplace call in a separate
function and mark
it @trusted or @system depending on save, because the only way
to mark the
rest of the function as @trusted is to mark the whole thing as
@trusted. You'd
have to specifically put _everything else_ in its own function
_and_ emplace in
its own function (one @trusted, one @system) and have the outer
function call
both. It's a mess. Being able to mark statements as @trusted
rather than just
entire functons would be _huge_.
For the specific case of calling unsafe functions from otherwise
safe code, which occurs quite frequently due to parts of Phobos
not being properly annotated yet, I've been experimenting with an
alternative solution in my code. It allows you to »apply
trusted« at a function call level, and is easily implemented in
the library with today's D – using it RefRange.save would look
like this using it:
---
@property auto save()
{
import std.conv;
alias typeof((*_range).save) S;
static assert(isForwardRange!S, S.stringof ~ " is not a
forward range.");
auto mem = new void[S.sizeof];
TRUSTED!(emplace!S)(mem, cast(S)(*_range).save);
@trusted return RefRange!S(cast(S*)mem.ptr);
}
---
TRUSTED is just a @trusted template function which accepts a
callable via an alias parameter and invokes it with the given
parameters, adding @trusted to the function type via a cast (an
application of std.traits.SetFunctionAttributes, by the way).
It seems to work fine, but there is an obvious catch: Just like
@trusted, TRUSTED circumvents safety, and all of its uses must be
carefully examined. But in contrast to the former, it is not part
of the language, so anyone working on the code base, especially
reviewers, must be aware of implications. The all-caps name is
meant to help drawing attention to .
Maybe it would be a good idea to also allow
`@trusted(emplace!S)(mem, cast(S)(*_range).save)`, with semantics
similar to TRUSTED? Or even applying @trusted to arbitrary
expressions, similar to `checked` in C#?
David