August 20, 2018
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
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
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
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
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
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
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
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
I mean if one method in structure is trusted, other methods need manual verification too.
August 21, 2018
...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?