@trusted considered harmful

Jonathan M Davis jmdavisProg at gmx.com
Sat Jul 28 13:22:13 PDT 2012


On Saturday, July 28, 2012 21:53:25 Jesse Phillips wrote:
> For your example of the proposal, when does the compiler mark
> save() as @system over @trusted?
> 
> @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];`
>         emplace!S(mem, cast(S)(*_range).save);`
>         return RefRange!S(cast(S*)mem.ptr);
>     }
> }
> 
> You make a call to _range.save in the @trusted block. So why
> isn't the function marked @trusted?

I screwed up my changes there. I made them in a bit of a hurry. And actually, 
in this particular case, using an @trusted block is still a bit entertaining, 
since the save call is in middle of an expression which is doing @system stuff. 
But the principle is the same regardless. If you need to do @system stuff in a 
function where you know that the @system stuff that you're doing is @safe but 
the function is also calling templated stuff which may or may not be @safe, you 
can't mark the whole function as @trusted, or you'll be marking code which is 
potentially truly unsafe as @trusted. With an @trusted block, you can mark 
sections of the code @trusted and let the rest be properly inferred based on 
what the the template was instantiated with.

In this particular case, it could still drastically reduce save, because only 
the line with @save would need to be duplicated. So, it could become something  
more like

@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_.

- Jonathan M Davis


More information about the Digitalmars-d mailing list