On Thursday, 5 February 2015 at 16:50:18 UTC, Steven
Schveighoffer wrote:
Reading the thread in bug report
https://issues.dlang.org/show_bug.cgi?id=14125 gets me
thinking, perhaps @trusted is mis-designed.
At the moment, a @trusted function is the same as a @system
function, but is allowed to be called from a @safe function.
And that's it.
But a @trusted function may only need to be marked @trusted
because of a few lines of code. So we now use this mechanism
where we mark the @trusted portions with a lambda or static
nested function, and call that internally, and mark the entire
function @safe.
The benefit of this is, for the 90% of the code that is @safe,
the compiler is used as a tool to check the @safe-ty of the
function. For the 10% that isn't, we have contained it and
marked it, and we can focus on that portion for scrutiny. This
becomes EXTREMELY important when it comes to maintenance.
For example, if a @trusted function has some code added to it,
the new code needs to be measured to see if it really is safe
to call from a @safe function. This may be no easy feat.
At least with the @trusted inner function/lambda, you limit
yourself to the code that has been marked as such, and you
don't need to worry about the actual @safe code that is added
to the function.
Or do you?... the problem with this mentality is interactions
with data inside the @safe code after a @trusted function is
called can still be subject to memory safety issues. An example
(using static functions for clarity):
void foo() @safe
{
static auto tmalloc(size_t x) @trusted {return (cast(int
*)malloc(x * sizeof(int)))[0..x];}
static void tfree(void[] arr) @trusted {free(arr.ptr);}
auto mem = tmalloc(100);
tfree(mem);
mem[0] = 5;
}
Note that the final line in the function, setting mem[0] to 5,
is the only unsafe part. it's safe to malloc, it's safe to free
as long as you don't ever refer to that memory again.
But the problem with the above is that @trusted is not needed
to apply to the mem[0] = 5 call. And imagine that the mem[0] =
5 function may be simply added, by another person who didn't
understand the context. Marking the whole function as safe is
kind of meaningless here.
Changing gears, one of the issues raised in the aforementioned
bug is that a function like this really should be marked
trusted in its entirety. But what does this actually mean?
When we mark a function @safe, we can assume that the compiler
has checked it for us. When we mark a function @trusted, we can
assume the compiler has NOT checked it for us. But how does
this help? A @safe function can call a @trusted function. So
there is little difference between a @safe and a @trusted
function from an API point of view. I would contend that
@trusted really should NEVER HAVE BEEN a function attribute.
You may as well call them all @safe, there is no difference.
What I think we need to approach this correctly is that instead
of marking *functions* with @trusted, we need to mark *data*
and *calls* with @trusted. Once data is used inside a @trusted
island, it becomes tainted with the @trusted mark. The compiler
can no longer guarantee safety for that data.
So how can we implement this without too much pain? I envision
that we can mark lines or blocks inside a @safe function as
@trusted (a @trusted block inside a @system function would be a
no-op, but allowed). I also envision that any variable used
inside the function is internally marked as @safe until it's
used in a @trusted block, and then is marked as @trusted (again
internally, no requirement to mark in syntax). If at any time
during compilation a @trusted variable is used in @safe code,
it's a compile error.
There may be situations in which you DO need this to work, and
in those cases, I would say a cast(@safe) could get rid of that
mark. For example, if you want to return the result of a
@trusted call in a @safe function.
Such a change would be somewhat disruptive, but much more in
line with what @trusted calls really mean.
I've left some of the details fuzzy on purpose, because I'm not
a compiler writer :)
Destroy
-Steve
Hey I like the creativity you're showing. Just to give people a
concrete idea, you might show some sample code and illustrate how
things work. It sure helps when I'm trying to think about things.