www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Friends don't let friends use inout with scope and -dip1000

reply Atila Neves <atila.neves gmail.com> writes:
Here's a struct:

-----------------
struct MyStruct {
     import core.stdc.stdlib;
     int* ints;
     this(int size)  trusted { ints = cast(int*) malloc(size); }
     ~this()  trusted { free(ints); }
     scope int* ptr() { return ints; }
}
-----------------

Let's try and be evil with -dip1000:

-----------------
 safe:

// struct MyStruct ...

const(int) *gInt;

void main() {
     auto s = MyStruct(10);
     gInt = s.ptr;
}
-----------------

% dmd -dip1000 scope_inout.d
scope_inout.d(26): Error: scope variable this may not be returned


Yay!

What if instead of `auto` I write `const` instead (or immutable)? 
This is D we're talking about, so none of this boilerplate 
nonsense of writing two (or three) basically identical functions. 
So:

-----------------
// used to be scope int* ptr() { return ints; }
scope inout(int)* ptr() inout { return ints; }
-----------------

% dmd -dip1000 scope_inout.d
% echo $?
0


Wait, what? Turns out now it compiles. After some 
under-the-breath mumbling I go hit issues.dlang.org and realise 
that the issue already exists:


https://issues.dlang.org/show_bug.cgi?id=17935


For reasons unfathomable to me, this is considered the _correct_ 
behaviour. Weirder still, writing out the boilerplate that 
`inout` is supposed to save us (mutable, const and immutable 
versions) doesn't compile, which is what one would expect.

So:  safe + inout + scope + dip1000 + custom memory allocation in 
D gets us to the usability of C++ circa 1998. At least now we 
have valgrind and asan I guess.

"What about template this?", I hear you ask. It kinda works. 
Sorta. Kinda. Behold:

------------
scope auto ptr(this T)() { return ints; }
------------

After changing the definition of `ptr` this way the code compiles 
fine and `ints` is escaped. Huh. However, if you change `auto s` 
to `scope s`, it fails to compile as <insert deity> intended. 
Very weird.

If you change the destructor to `scope` then it also fails to 
compile even if it's `auto s`. Because, _obviously_, that's 
totally different.

I'd file an issue but given that the original one is considered 
not a bug for some reason, I have no idea about what I just wrote 
is right or not.

What I do know is I found multiple ways to do nasty things to 
memory under the guise of  safe and -dip1000, and my 
understanding was that the compiler would save me from myself. In 
the meanwhile I'm staying away from `inout` and putting `scope` 
on my destructors even if I don't quite understand when 
destructors should be `scope`. Probably always? I have no idea.
Aug 17 2018
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/17/18 3:36 AM, Atila Neves wrote:
 Here's a struct:
 
 -----------------
 struct MyStruct {
      import core.stdc.stdlib;
      int* ints;
      this(int size)  trusted { ints = cast(int*) malloc(size); }
      ~this()  trusted { free(ints); }
      scope int* ptr() { return ints; }
 }
 -----------------
 
 Let's try and be evil with -dip1000:
 
 -----------------
  safe:
 
 // struct MyStruct ...
 
 const(int) *gInt;
 
 void main() {
      auto s = MyStruct(10);
      gInt = s.ptr;
 }
 -----------------
 
 % dmd -dip1000 scope_inout.d
 scope_inout.d(26): Error: scope variable this may not be returned
 
 
 Yay!
 
 What if instead of `auto` I write `const` instead (or immutable)? This 
 is D we're talking about, so none of this boilerplate nonsense of 
 writing two (or three) basically identical functions. So:
 
 -----------------
 // 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? What happens if you remove the return type? (i.e. scope auto)
 -----------------
 
 % dmd -dip1000 scope_inout.d
 % echo $?
 0

 
 Wait, what? Turns out now it compiles. After some under-the-breath 
 mumbling I go hit issues.dlang.org and realise that the issue already 
 exists:
 
 
 https://issues.dlang.org/show_bug.cgi?id=17935
I don't see what this bug report has to do with the given case.
 
 
 For reasons unfathomable to me, this is considered the _correct_ 
 behaviour. Weirder still, writing out the boilerplate that `inout` is 
 supposed to save us (mutable, const and immutable versions) doesn't 
 compile, which is what one would expect.
 
 So:  safe + inout + scope + dip1000 + custom memory allocation in D gets 
 us to the usability of C++ circa 1998. At least now we have valgrind and 
 asan I guess.
 
 "What about template this?", I hear you ask. It kinda works. Sorta. 
 Kinda. Behold:
 
 ------------
 scope auto ptr(this T)() { return ints; }
 ------------
 
 After changing the definition of `ptr` this way the code compiles fine 
 and `ints` is escaped. Huh. However, if you change `auto s` to `scope 
 s`, it fails to compile as <insert deity> intended. Very weird.
This seems like a straight up bug.
 
 If you change the destructor to `scope` then it also fails to compile 
 even if it's `auto s`. Because, _obviously_, that's totally different.
 
 I'd file an issue but given that the original one is considered not a 
 bug for some reason, I have no idea about what I just wrote is right or 
 not.
 
 What I do know is I found multiple ways to do nasty things to memory 
 under the guise of  safe and -dip1000, and my understanding was that the 
 compiler would save me from myself. In the meanwhile I'm staying away 
 from `inout` and putting `scope` on my destructors even if I don't quite 
 understand when destructors should be `scope`. Probably always? I have 
 no idea.
 
 
This doesn't surprise me. I'm beginning to question whether scope shouldn't have been a type constructor instead of a storage class. It's treated almost like a type constructor in most places, but the language grammar makes it difficult to be specific as to what part it applies. -Steve
Aug 17 2018
next sibling parent Dukc <ajieskola gmail.com> writes:
On Friday, 17 August 2018 at 13:39:29 UTC, Steven Schveighoffer 
wrote:
 On 8/17/18 3:36 AM, Atila Neves wrote:
 Here's a struct:
 -----------------
 // 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?
This reference. putting it like: inout(int)* ptr() inout scope { return ints; } ...does not change anything. Another thing it should AFAIK catch but doesn't: import std.stdio; safe: struct MyStruct { int* intP; this(int val) { intP = new int(val); } int* ptr() return scope { return intP; } } int *gInt; void main() { auto s = MyStruct(10); gInt = s.ptr; writeln(*gInt); }
Aug 17 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Friday, 17 August 2018 at 13:39:29 UTC, Steven Schveighoffer 
wrote:
 On 8/17/18 3:36 AM, Atila Neves wrote:
 Here's a struct:
 
 -----------------
 struct MyStruct {
      import core.stdc.stdlib;
      int* ints;
      this(int size)  trusted { ints = cast(int*) malloc(size); 
 }
      ~this()  trusted { free(ints); }
      scope int* ptr() { return ints; }
 }
 -----------------
 
 Let's try and be evil with -dip1000:
 
 -----------------
  safe:
 
 // struct MyStruct ...
 
 const(int) *gInt;
 
 void main() {
      auto s = MyStruct(10);
      gInt = s.ptr;
 }
 -----------------
 
 % dmd -dip1000 scope_inout.d
 scope_inout.d(26): Error: scope variable this may not be 
 returned
 
 
 Yay!
 
 What if instead of `auto` I write `const` instead (or 
 immutable)? This is D we're talking about, so none of this 
 boilerplate nonsense of writing two (or three) basically 
 identical functions. So:
 
 -----------------
 // 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?
 What happens if you remove the return type? (i.e. scope auto)
And write what instead?
 -----------------
 
 % dmd -dip1000 scope_inout.d
 % echo $?
 0

 
 Wait, what? Turns out now it compiles. After some 
 under-the-breath mumbling I go hit issues.dlang.org and 
 realise that the issue already exists:
 
 
 https://issues.dlang.org/show_bug.cgi?id=17935
I don't see what this bug report has to do with the given case.
That's because I'm an idiot and I meant this one: https://issues.dlang.org/show_bug.cgi?id=17927
 This seems like a straight up bug.
 This doesn't surprise me. I'm beginning to question whether 
 scope shouldn't have been a type constructor instead of a 
 storage class. It's treated almost like a type constructor in 
 most places, but the language grammar makes it difficult to be 
 specific as to what part it applies.
I'm so confused it's not even funny.
Aug 20 2018
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
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?
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
 What happens if you remove the return type? (i.e. scope auto)
And write what instead?
scope ptr() inout { return ints; } ?
Aug 20 2018
next sibling parent Atila Neves <atila.neves gmail.com> writes:
On Monday, 20 August 2018 at 09:43:46 UTC, 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:
 [...]
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?
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
 What happens if you remove the return type? (i.e. scope auto)
And write what instead?
scope ptr() inout { return ints; } ?
I guess you meant `scope ptr(this This)() { return this; }`. Nothing changes from the behaviour I described.
Aug 20 2018
prev sibling next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, August 20, 2018 3:43:46 AM MDT Nicholas Wilson via Digitalmars-d 
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?
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
I don't know what happens with scope with -dip1000, but that's not how D works with any other qualifier that can affect the return type. If you don't put parens on the qualifier on the return type, it refers to the this pointer/reference. And arguably, if we're now putting scope on return types, scope(T) should be a thing, and scope should have exactly the same behavior as const, shared, etc. with regards to placement, or it's just going to cause problems. - Jonathan M Davis
Aug 20 2018
prev sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
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
Aug 20 2018
prev sibling parent reply Kagamin <spam here.lot> writes:
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; }
}
Aug 20 2018
next sibling parent Kagamin <spam here.lot> writes:
AIU, `return` for `scope` is what `inout` is for `const`. I 
proposed to extend `inout` to mean `return`, but Walter said that 
they are independent.
Aug 20 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
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.
Aug 20 2018
parent reply Kagamin <spam here.lot> writes:
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.
Aug 20 2018
next sibling parent Dgame <r.schuett.1987 gmail.com> writes:
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)(); }
Aug 20 2018
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
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.
Aug 21 2018
parent reply Atila Neves <atila.neves gmail.com> writes:
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?
Aug 21 2018
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
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.
Aug 21 2018
parent Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 21 August 2018 at 11:28:39 UTC, Nicholas Wilson wrote:
 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.
At the very least then it should fail to compile if I don't add the relevant annotation, not silently accept buggy code that isn't memory safe but somehow _is_ ` safe`. That's the whole point of -dip1000, no? If I get around it by forgetting something, it's not going to work.
Aug 21 2018
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
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.
Aug 21 2018
parent reply Kagamin <spam here.lot> writes:
...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?
Aug 21 2018
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/21/18 9:42 AM, Kagamin wrote:
 ....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?
I would guess it's no different than other inferred attributes. I would also guess that it only gets promoted to a return parameter if it's actually returned. As long as the *result* is scoped like the parameter. In the case of the OP in this thread, there is definitely a problem with inout and the connection to the return value. -Steve
Aug 21 2018
parent reply Kagamin <spam here.lot> writes:
On Tuesday, 21 August 2018 at 14:04:15 UTC, Steven Schveighoffer 
wrote:
 I would guess it's no different than other inferred attributes. 
 I would also guess that it only gets promoted to a return 
 parameter if it's actually returned.
If we can't have properly typed parameters, it feels like it has potential to prevent some patterns. This prevents automatic scope promotion: template escape(T) { int[] escape1(scope int[] r) { return r; } alias escape=escape1; }
Aug 22 2018
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/22/18 4:17 AM, Kagamin wrote:
 On Tuesday, 21 August 2018 at 14:04:15 UTC, Steven Schveighoffer wrote:
 I would guess it's no different than other inferred attributes. I 
 would also guess that it only gets promoted to a return parameter if 
 it's actually returned.
If we can't have properly typed parameters, it feels like it has potential to prevent some patterns.
But scope is not part of the type, nor is return. One of my biggest concerns about dip1000 is that the "scope-ness" or "return-ness" of a variable is hidden from the type system. It's just the compiler doing flow analysis and throwing you an error when it can't work the thing out. I'm more worried about not being able to express the flow in a way that the compiler understands, and having it complain about things that are actually safe.
 
 This prevents automatic scope promotion:
 
 template escape(T)
 {
      int[] escape1(scope int[] r)
      {
          return r;
      }
      alias escape=escape1;
 }
But that's not valid dip1000 code. If you call it, it should give a compiler error (r *does* escape its scope). -Steve
Aug 22 2018
parent Kagamin <spam here.lot> writes:
On Wednesday, 22 August 2018 at 14:05:10 UTC, Steven 
Schveighoffer wrote:
 But that's not valid dip1000 code. If you call it, it should 
 give a compiler error (r *does* escape its scope).
When I complained about C++ safety to my C++ programmer colleague, he told me that the compiler just compiles what's written. On one hand I can understand what he wanted to say, but the wording is still hilarious and fits C++ very well. What I like in D is that if it's written doesn't mean that it will compile: invalid code should be rejected.
Aug 22 2018
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Tuesday, 21 August 2018 at 13:42:31 UTC, Kagamin wrote:
 int[] escape(scope int[] r)
 {
     return r; //error, can't return scoped argument
 }
...
 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?
I filed a similar bug (it uses return type inference rather than a template). Walter closed it as invalid: https://issues.dlang.org/show_bug.cgi?id=17362
Aug 21 2018
prev sibling parent reply Kagamin <spam here.lot> writes:
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.
Aug 21 2018
parent Kagamin <spam here.lot> writes:
I mean if one method in structure is trusted, other methods need 
manual verification too.
Aug 21 2018