Is @safe still a work-in-progress?

Atila Neves atila.neves at gmail.com
Thu Aug 23 13:10:17 UTC 2018


On Thursday, 23 August 2018 at 08:48:15 UTC, Walter Bright wrote:
> On 8/22/2018 3:52 AM, Atila Neves wrote:
>> On Wednesday, 22 August 2018 at 09:05:13 UTC, Walter Bright 
>> wrote:
>>> On 8/21/2018 8:58 PM, Nicholas Wilson wrote:
>>>> On Tuesday, 21 August 2018 at 14:31:02 UTC, Atila Neves 
>>>> wrote:
>>>>> The problem is that the code we write doesn't deal directly 
>>>>> with pointers - see the recent confusion in this forum over 
>>>>> where `scope` on the left applies to the `this` pointer or 
>>>>> the one returned by the member function.
>>>>>
>>>>> Kagamin just told me I needed to use `return` instead of 
>>>>> `scope` to get things to work and I'm still not sure why.
>>>>
>>>> The way I think about it is if you have a function that 
>>>> takes a pointer, any pointer, and either returns it or a 
>>>> pointer derived from it (dereferencing or indexing) that 
>>>> argument must be marked `return`. In your case it was a 
>>>> pointer derived from `this` so `return` must be applied to 
>>>> `this`.
>>>
>>>
>>> Another way to think about it is this:
>>>
>>>    S s;
>>>    return &s;
>>>
>>> We all know that is an error. The idea is to have a way to 
>>> express that for:
>>>
>>>     S s;
>>>     return s.foo();
>>>
>>> and:
>>>
>>>     S s;
>>>     return foo(&s);
>>>
>>> so that the compiler knows that the return value of foo() is 
>>> attached to the lifetime of s. Pretty much everything flows 
>>> from that.
>> 
>> Would the guideline below be correct?
>> 
>> "Add scope to every non-template member function that isn't 
>> meant to escape this and add return to every non-template 
>> member function that returns all or part of `this` by pointer 
>> or ref if you want the compiler to check that nothing gets 
>> escaped in @safe code."
>
> Being a template doesn't make any difference, except that it 
> will helpfully infer these things.

The reason I wrote "non-template" is precisely because attributes 
get inferred for templates and therefore it would be at best 
redundant to annotate.

What about the guideline being correct or not?

>
> Also, since 'this' is passed by 'ref' to struct member 
> functions, it cannot escape anyway with dip1000:
>
>   struct S {
>     int x;
>     @safe ref int foo() { return x; }
>   }
>
>   dmd test -dip1000
>   test.d(4): Error: returning this.x escapes a reference to 
> parameter this, perhaps annotate with return

Returning by ref is good, since it's a lot harder to escape it. 
Since variables can't be declared ref, I can't pass it to a ref 
global. However:

----------
struct S {
     int x;
     @safe int* foo() { return &x; }
}
----------

% dmd -o- -dip1000 foo.d
% echo $?
0

Oops:

----------
int* gPtr;
void main() {
     auto s = S(42);
     gPtr = s.foo;
}
----------

"Don't use pointers then!". Ok:

----------
int[] gSlice;
void main() {
     auto s = S([42]);
     gSlice = s.foo;
}

struct S {
     int[] x;
     @safe int[] foo() return { return x; }
}
----------

% dmd -o- -dip1000 bar.d
% echo $?
0

Oops. I can't say `int[] x;` since it doesn't apply to fields.

> `scope` is for pointers, `ref` does not need further annotation.

I always forget this, it's confusing. It doesn't help that slices 
have pointers, so I guess `scope` is for them too?

And in a struct, `this` is a `ref`, yet `scope` on a member 
function applies to `this`.

Atila




More information about the Digitalmars-d mailing list