@trusted considered harmful

David Nadlinger see at klickverbot.at
Sat Jul 28 13:52:32 PDT 2012


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


More information about the Digitalmars-d mailing list