What exactly does "@safe" mean?
Jonathan M Davis
jmdavisProg at gmx.com
Sat Jun 1 16:32:32 PDT 2013
On Sunday, June 02, 2013 01:12:53 Piotr Szturmaj wrote:
> W dniu 01.06.2013 23:55, Jonathan M Davis pisze:
> > The guarantees of @safe hold only so long as there are no holes in it, but
> > any and all holes we find get fixed. Making ref be truly @safe has been a
> > large part of the recent ref discussions, as you can currently get away
> > with doing something like
> >
> > ref int id(ref int i) { return i; }
> >
> > ref int foo()
> > {
> >
> > int j;
> > return id(j);
> >
> > }
>
> I know that introducing another type qualifier may complicate things
> but this would be a compile time solution.
>
> I mean _scope_ type qualifier, so your example could be rewritten as:
>
> ref int id(ref int i) { return i; }
>
> ref int foo()
> {
> int j;
> return id(j); // error: could not pass scope(int) as ref int parameter
> }
>
> Taking an address of local variable would always yield a scope
> qualified type, scope(int) in this example.
>
> Obviously, scope qualified type could be passed to functions taking
> scope parameters:
>
> void bar(scope ref int i) { i = 10; }
>
> void foo()
> {
> int j = 0;
> bar(j); // ok
> assert(i == 10);
> }
>
> I think this could fill the @safety holes.
Except that that makes it so that you can't return a ref argument, which is
completely unacceptable. You need to be able to pass local variables to
functions which accept ref in @safe code, and you need functions which ref
arguments to be able to return those arguments by ref. The only thing that we
want to prevent is a local variable from escaping its original scope. It's
perfectly valid that the id function accept a local variable by ref and
returns it by ref. What's invalid is that the function that the local variable
was declared in then returns it by ref.
Manu suggested something similar to what you're suggesting with the addition
of having making it so that you can then return variables as scope ref, in
which case, the caller would see that the function was accepting by scope ref
and returning by scope ref and that none of the variables that it accepted
were scope ref in the caller. But this requires having having yet another
annotation - scope ref - which Andrei was completely against (and Walter too
IIRC), and it actually would end up making something like this illegal as
well, went it shouldn't:
scope ref int foo(scope ref int i, scope ref int j)
{
return j;
}
scope ref bar(scope ref int q)
{
int i;
return foo(i, q);
}
The compiler can't know whether it's i or q that's being returned from foo, so
it would have to given a compilation error, which is more restrictive than the
runtime solution that has been proposed. So, you can do less, and you have to
have mark up your functions with even more attributes, and it's yet another
attribute for those learning the language to have to learn.
Contrast this with simply inserting a very cheap runtime check in the rare
cases where the compiler detects that a local variable might escape. No
additional attributes are needed. So, the code is simpler, and there's less
for people to learn. There's almost no performance hit (and if you want it to
be zero, then use -noboundscheck). And we lose _zero_ functionality. None of
that is the case with the scope ref proposal.
Walter and Andrei do not like the idea of introducing even more attributes to
solve this problem and were very excited to have this solution proposed
(unfortunately, I'm not sure who proposed it though, since I missed that part
of the conversation). And I'm inclined to agree with them. It's very simple
and cheap. The only real downside is that it's caught at runtime rather than
compile time, but it's quickly and easily caught at runtime, and the
simplicity of it makes it seem like a great solution.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list