August 20, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nicholas Wilson | On 8/20/18 5:43 AM, Nicholas Wilson wrote: > On Monday, 20 August 2018 at 09:31:09 UTC, Atila Neves wrote: >> On Friday, 17 August 2018 at 13:39:29 UTC, Steven Schveighoffer wrote: >>>> // used to be scope int* ptr() { return ints; } >>>> scope inout(int)* ptr() inout { return ints; } >>> >>> Does scope apply to the return value or the `this` reference? >> >> I assumed the return value. I think I've read DIP1000 about a dozen times now and I still get confused. As opposed to `const` or `immutable`, `scope(T)` isn't a thing so... I don't know? A type constructor affects the type of something. So const(int) is an int that is const. const int is actually NOT a type constructor, but a storage class. It's main effect is to make the int actually const(int), but can have other effects (e.g. if it's a global, it may be put into global storage instead of thread-local). scope is not a type constructor, ever. So how do you specify the return type is scope? How do you specify a difference between the scope of the 'this' pointer, and the scope of the return value? I'm super-confused as to what dip1000 actually is doing, and how to use it. >> > What usually happens is that qualifiers to the left of the name apply to the return type and those to the right apply `this`. Not that that _should_ make any difference since lifetime ints == lifetime this > No: const int* foo() const { return null; } Error: redundant const attribute. Up until 2.080, this was a deprecation, and the result was int * >>> What happens if you remove the return type? (i.e. scope auto) >> >> And write what instead? >> > > scope ptr() inout { return ints; } ? Yes, this is what I was thinking. -Steve |
August 20, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Atila Neves | On Monday, 20 August 2018 at 13:02:23 UTC, Atila Neves wrote: > On Monday, 20 August 2018 at 12:56:42 UTC, Kagamin wrote: >> You need `return` attribute there, not `scope`: >> >> struct MyStruct >> { >> import core.stdc.stdlib; >> int* ints; >> this(int size) @trusted { ints = cast(int*) malloc(size); } >> ~this() @trusted { free(ints); } >> inout(int)* ptr() return inout { return ints; } >> } > > I need `return` for what exactly? Your code still compiles, and my point is it shouldn't. It sure isn't memory safe. @safe: struct MyStruct { import core.stdc.stdlib; int* ints; this(int size) @trusted { ints = cast(int*) malloc(size); } ~this() @trusted { free(ints); } inout(int)* ptr() return inout { return ints; } } int* gInt; void f() { auto s=MyStruct(10); gInt=s.ptr; } > Error: address of variable s assigned to gInt with longer lifetime Looks safe to me. |
August 20, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On Monday, 20 August 2018 at 15:55:54 UTC, Kagamin wrote:
> On Monday, 20 August 2018 at 13:02:23 UTC, Atila Neves wrote:
>> On Monday, 20 August 2018 at 12:56:42 UTC, Kagamin wrote:
>>> You need `return` attribute there, not `scope`:
>>>
>>> struct MyStruct
>>> {
>>> import core.stdc.stdlib;
>>> int* ints;
>>> this(int size) @trusted { ints = cast(int*) malloc(size); }
>>> ~this() @trusted { free(ints); }
>>> inout(int)* ptr() return inout { return ints; }
>>> }
>>
>> I need `return` for what exactly? Your code still compiles, and my point is it shouldn't. It sure isn't memory safe.
>
> @safe:
> struct MyStruct
> {
> import core.stdc.stdlib;
> int* ints;
> this(int size) @trusted { ints = cast(int*) malloc(size); }
> ~this() @trusted { free(ints); }
> inout(int)* ptr() return inout { return ints; }
> }
>
> int* gInt;
> void f()
> {
> auto s=MyStruct(10);
> gInt=s.ptr;
> }
>
>> Error: address of variable s assigned to gInt with longer lifetime
>
> Looks safe to me.
Is that safe as well?
void f()
{
auto s = MyStruct(10);
gInt = (() => s.ptr)();
}
|
August 21, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On Monday, 20 August 2018 at 15:55:54 UTC, Kagamin wrote:
> On Monday, 20 August 2018 at 13:02:23 UTC, Atila Neves wrote:
>> On Monday, 20 August 2018 at 12:56:42 UTC, Kagamin wrote:
>>> [...]
>>
>> I need `return` for what exactly? Your code still compiles, and my point is it shouldn't. It sure isn't memory safe.
>
> @safe:
> struct MyStruct
> {
> import core.stdc.stdlib;
> int* ints;
> this(int size) @trusted { ints = cast(int*) malloc(size); }
> ~this() @trusted { free(ints); }
> inout(int)* ptr() return inout { return ints; }
> }
>
> int* gInt;
> void f()
> {
> auto s=MyStruct(10);
> gInt=s.ptr;
> }
>
>> Error: address of variable s assigned to gInt with longer lifetime
>
> Looks safe to me.
With dmd 2.081.2 on Arch Linux, the code above compiles with no error message.
|
August 21, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Atila Neves | On Tuesday, 21 August 2018 at 09:50:46 UTC, Atila Neves wrote:
> On Monday, 20 August 2018 at 15:55:54 UTC, Kagamin wrote:
>> On Monday, 20 August 2018 at 13:02:23 UTC, Atila Neves wrote:
>>> On Monday, 20 August 2018 at 12:56:42 UTC, Kagamin wrote:
>>>> [...]
>>>
>>> I need `return` for what exactly? Your code still compiles, and my point is it shouldn't. It sure isn't memory safe.
>>
>> @safe:
>> struct MyStruct
>> {
>> import core.stdc.stdlib;
>> int* ints;
>> this(int size) @trusted { ints = cast(int*) malloc(size); }
>> ~this() @trusted { free(ints); }
>> inout(int)* ptr() return inout { return ints; }
>> }
>>
>> int* gInt;
>> void f()
>> {
>> auto s=MyStruct(10);
>> gInt=s.ptr;
>> }
>>
>>> Error: address of variable s assigned to gInt with longer lifetime
>>
>> Looks safe to me.
>
> With dmd 2.081.2 on Arch Linux, the code above compiles with no error message.
Never mind, I forgot to use -dip1000. Ok, cool, so _why_ does it work as intended now? Also, if I have to remember to annotate correctly, surely this is a massive hole in @safe dip1000?
|
August 21, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Atila Neves | On Tuesday, 21 August 2018 at 10:57:15 UTC, Atila Neves wrote:
> On Tuesday, 21 August 2018 at 09:50:46 UTC, Atila Neves wrote:
>> On Monday, 20 August 2018 at 15:55:54 UTC, Kagamin wrote:
>>> On Monday, 20 August 2018 at 13:02:23 UTC, Atila Neves wrote:
>>>> On Monday, 20 August 2018 at 12:56:42 UTC, Kagamin wrote:
>>>> Error: address of variable s assigned to gInt with longer lifetime
>>>
>>> Looks safe to me.
>>
>> With dmd 2.081.2 on Arch Linux, the code above compiles with no error message.
>
> Never mind, I forgot to use -dip1000. Ok, cool, so _why_ does it work as intended now? Also, if I have to remember to annotate correctly, surely this is a massive hole in @safe dip1000?
MyStruct is not a template, I presume `return` would get inferred if it was. But yeah that is annoying.
|
August 21, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Atila Neves | On Tuesday, 21 August 2018 at 10:57:15 UTC, Atila Neves wrote: > Never mind, I forgot to use -dip1000. Ok, cool, so _why_ does it work as intended now? Also, if I have to remember to annotate correctly, surely this is a massive hole in @safe dip1000? It thought dip1000 was impenetrable, but if I understand it (honestly that's a surprise!), `scope` has strict semantics: all in, nothing out; you don't need to think about lifetime of data passed to scope parameters, because it doesn't escape anywhere. If you want to return data extracted from argument, `return` attribute relaxes scoping rules and allows to return data and passes scoping properties from argument to return value much like `inout` does for const. Without annotation: @safe: struct MyStruct { import core.stdc.stdlib; int* ints; this(int size) @trusted { ints = cast(int*) malloc(size); } ~this() scope @trusted { free(ints); } inout(int)* ptr() inout { return ints; } } int* gInt; void f() { scope s=MyStruct(10); gInt=s.ptr; } >Error: scope variable s assigned to non-scope parameter this calling MyStruct.ptr Doesn't let to call method without annotation. |
August 21, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Atila Neves | On Tuesday, 21 August 2018 at 10:57:15 UTC, Atila Neves wrote:
> Also, if I have to remember to annotate correctly, surely this is a massive hole in @safe dip1000?
In general, safety works per method and doesn't help much in building safe data structures, those are trusted as a whole. EMSI containers are a notable big victim of this thing.
|
August 21, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | I mean if one method in structure is trusted, other methods need manual verification too. |
August 21, 2018 Re: Friends don't let friends use inout with scope and -dip1000 | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | ...except for templated functions: int[] escape(scope int[] r) { return r; //error, can't return scoped argument } int[] escape(return int[] r) { return r; //ok, just as planned } int[] escape(return scope int[] r) { return r; //ok, `return scope` reduced to just `return` } int[] escape(T)(scope int[] r) { return r; //ok! `scope` silently promoted to `return` } You can't have strictly scoped parameter in a templated function - it's silently promoted to return parameter. Is this intended? |
Copyright © 1999-2021 by the D Language Foundation