Re: DIP1000
On Saturday, 2 July 2022 at 09:42:17 UTC, Loara wrote: But you first said "The compiler should deduce if a `scope` pointer points to heap allocated data or not" and when someone tells you this should happen only for not `scope` pointers you say "But the compiler doesn't do that". This discussion isn't going anywhere… :-) (Please don't use quotation marks unless you actually quote.).
Re: DIP1000
On Thursday, 30 June 2022 at 21:30:39 UTC, Ola Fosheim Grøstad wrote: I don't understand what you mean, it could, but it doesn't. And if it did then you would not need `scope`… If the compiler doesn't optimize your code is a compiler issue. When you use the `scope` attribute you're [forcing the compiler to do a stack allocation](https://dlang.org/spec/attribute.html#scope-class-var), so the compiler forbids you from doing something stupid. These are function pointer parameters, how could it trigger allocation on the heap? When you declare `scope` function parameters you're saying that it may point both to heap allocated and stack allocated data, and the compiler choose the more restrictive option when it compiles your option, since at that time it doesn't know if your function arguments are heap allocated or stack allocated. But that doesn't work. But you first said "The compiler should deduce if a `scope` pointer points to heap allocated data or not" and when someone tells you this should happen only for not `scope` pointers you say "But the compiler doesn't do that". No, the latter can most certainly point to any integer. It is just that scope/scope ref/return ref is to be checked in @safe. Unfortunately it is way too limiting. Even standard flow typing appears to be as strong or stronger. No-one forbids you from writing an unsafe function that does unsafe operations, the `@system` and `@trusted` attributes are available yet. Simply you should control very well your code in order to avoid memory leaks and other issues since memory management without garbage collectors can't be safe without introducing a lot of restrictions. If you decide to do so I recommend you this [very useful tool](https://valgrind.org/). If there are destructors then you can think of each stack allocated variable as introducing a invisible scope, but the compiler can keep track of this easily. So the compiler knows the ordering. So if my function imposes and order on the lifetimes of the parameters, then the compiler should be able to check that the ordering constraint is satisfied. If you want the compiler to optimize your code you should remove any additional restriction, and declaring a pointer `scope` is an additional restriction not a relaxation. If you don't like it then you can always build a new compiler that do this if you need it so much, this is how open source software works. But then it won't compile at all in @safe! Find me an example of safe code that needs it and can't work without `scope` variables. Anyway I strongly recommend you to read these [documentation](https://dlang.org/spec/attribute.html#scope) [pages](https://dlang.org/spec/function.html#scope-parameters) in order to understand how `scope` works. If you don't like `scope` then don't use it.
Re: DIP1000
On Thursday, 30 June 2022 at 19:56:38 UTC, Loara wrote: The deduction can happen even if you don't use `scope` attribute. I don't understand what you mean, it could, but it doesn't. And if it did then you would not need `scope`… When you use `scope` attribute you're saying to compiler "You have to allocate this object on the stack, don't try to use heap allocation". These are function pointer parameters, how could it trigger allocation on the heap? If you want to let compiler to decide what is the best approach then don't use `scope`. But that doesn't work. So `scope int v;` is equal to `int v;` since `v` is not a pointer, whereas `scope int *p` is different from `int *v;` since the latter can't point to stack allocated integers. This is the difference. No, the latter can most certainly point to any integer. It is just that scope/scope ref/return ref is to be checked in @safe. Unfortunately it is way too limiting. Even standard flow typing appears to be as strong or stronger. Since stack allocated objects are destroyed in the reverse order allowing a recursive `scope` attribute is a bit dangerous as you can see in the following example: If there are destructors then you can think of each stack allocated variable as introducing a invisible scope, but the compiler can keep track of this easily. So the compiler knows the ordering. So if my function imposes and order on the lifetimes of the parameters, then the compiler should be able to check that the ordering constraint is satisfied. Again if you want to let the compiler to deduce then don't use `scope`. But then it won't compile at all in @safe!
Re: DIP1000
On Tuesday, 28 June 2022 at 21:58:48 UTC, Ola Fosheim Grøstad wrote: Not when connect returns, but the scope that connect was called from. Still, this can be deduced, you just have to give the scopes an ordering. The deduction can happen even if you don't use `scope` attribute. When you use `scope` attribute you're saying to compiler "You have to allocate this object on the stack, don't try to use heap allocation". If you want to let compiler to decide what is the best approach then don't use `scope`. Well, that is a flaw, if the object is stack allocated then the fields are too. No because: `scope` variable === the variable is a pointer/reference that points to stack allocated data So `scope int v;` is equal to `int v;` since `v` is not a pointer, whereas `scope int *p` is different from `int *v;` since the latter can't point to stack allocated integers. This is the difference. Since stack allocated objects are destroyed in the reverse order allowing a recursive `scope` attribute is a bit dangerous as you can see in the following example: ```d struct A{ int *i; ~this(){ writeln(*i); } } ... { A a; int i = 2; ... scope int *j = scope A *b = (*b).i = j; } // i is destroyed before a ``` The compiler could easily deduce it. It is not difficult to see what the life time constraint must be. Again if you want to let the compiler to deduce then don't use `scope`.
Re: DIP1000
On Wednesday, 29 June 2022 at 05:51:26 UTC, bauss wrote: Not necessarily, especially if the fields aren't value types. You can have stack allocated "objects" with pointers to heap allocated memory (heap allocated "objects".) Those are not fields, those are separate objects… The compiler knows which is a field (part of the object). You can't, or rather you shouldn't have stack allocated fields within heap allocated "objects" however; as that will almost be guaranteed to lead to problems. That is perfectly ok if you use RAII and manage life times. Ex. from your example then even if the "node struct" you pass was allocated on the stack, then the memory the "next" pointer points to might not be allocated same place. Unless I'm misunderstanding what you're trying to say. You did :). If you look at the post I made in general about DIP1000 and flow typing you see that I annotate scope with a number to indicate life time ordering. If you have `connect(int* a,int* b){a.next = b}` then the compiler can deduce that the signature with formal parameters should be `connect(scope!N(int*) a, scope_or_earlier!N(int*) b)`. The compiler then checks that the actual parameters at the call site are subtypes (same type or proper subtype).
Re: DIP1000
On Tuesday, 28 June 2022 at 21:58:48 UTC, Ola Fosheim Grøstad wrote: not-scoped variable (`a.next` is not `scope` since this attribute is not transitive) Well, that is a flaw, if the object is stack allocated then the fields are too. Not necessarily, especially if the fields aren't value types. You can have stack allocated "objects" with pointers to heap allocated memory (heap allocated "objects".) You can't, or rather you shouldn't have stack allocated fields within heap allocated "objects" however; as that will almost be guaranteed to lead to problems. I believe it's possible, but one should always refrain from it, but the same isn't true the for stack allocated "objects" with heap allocated fields. Ex. from your example then even if the "node struct" you pass was allocated on the stack, then the memory the "next" pointer points to might not be allocated same place. Unless I'm misunderstanding what you're trying to say.
Re: DIP1000
On Tuesday, 28 June 2022 at 21:40:44 UTC, Loara wrote: When `connect()` returns may happen that `b` is destroyed but `a` not, so `a.next` contains a dangling pointer that Not when connect returns, but the scope that connect was called from. Still, this can be deduced, you just have to give the scopes an ordering. not-scoped variable (`a.next` is not `scope` since this attribute is not transitive) Well, that is a flaw, if the object is stack allocated then the fields are too. is clearly dangerous since `connect` doesn't know which between `a` and `b` terminates first. The compiler could easily deduce it. It is not difficult to see what the life time constraint must be.
Re: DIP1000
On Friday, 24 June 2022 at 18:31:14 UTC, Ola Fosheim Grøstad wrote: The objects are in the calling function, not in the connect() function. So they are not destroyed when the connect() function returns. When `connect()` returns may happen that `b` is destroyed but `a` not, so `a.next` contains a dangling pointer that will bring potential segmentation faults that could be detected only with tools like Valgrind, just consider ```d node * calling(return scope node * a) @safe{ scope node *b = new node(); //b is stack allocated connect(a, b); return a; //b destroyed but a not } ``` The `scope` attribute tries to avoid these events preventing you from doing something potentially dangerous with stack allocated objects, and assigning a `scope` pointer to a not-scoped variable (`a.next` is not `scope` since this attribute is not transitive) is clearly dangerous since `connect` doesn't know which between `a` and `b` terminates first.
Re: DIP1000
On Friday, 24 June 2022 at 17:53:07 UTC, Loara wrote: Why you should use `scope` here? I probably shouldn't. That is why I asked in the «learn» forum… A `scope` pointer variable may refer to a stack allocated object that may be destroyed once the function returns. The objects are in the calling function, not in the connect() function. So they are not destroyed when the connect() function returns. Since a linked list should not contain pointers to stack allocated data you should avoid entirely the `scope` attribute and use instead `const`. It was only an example. There is nothing wrong with connecting objects on the stack.
Re: DIP1000
On Thursday, 23 June 2022 at 16:08:01 UTC, Ola Fosheim Grøstad wrote: How am I supposed to write this: ```d import std; @safe: struct node { node* next; } auto connect(scope node* a, scope node* b) { a.next = b; } void main() { node x; node y; connect(,); } ``` Error: scope variable `b` assigned to non-scope `(*a).next` Why you should use `scope` here? A `scope` pointer variable may refer to a stack allocated object that may be destroyed once the function returns. Since a linked list should not contain pointers to stack allocated data you should avoid entirely the `scope` attribute and use instead `const`.
Re: DIP1000
On Friday, 24 June 2022 at 09:08:25 UTC, Dukc wrote: On Friday, 24 June 2022 at 05:11:13 UTC, Ola Fosheim Grøstad wrote: No, the lifetime is the same if there is no destructor. Being counter intuitive is poor usability. It depends on whether you expect the rules to be smart or simple. Smart is not necessarily better, as the Unix philosophy tells you. I'm sure you have experience about programs that are unpredictable and thus frustating to use because they try to be too smart. If this feature is meant to be used by application developers and not only library authors then it has to match their intuitive mental model of life times. I would expect all simple value types to have the same lifetime as the scope. The other option is to somehow instill a mental model in all users that simple types like ints also having default destructors. If it only is for library authors, then it is ok to deviate from "intuition".
Re: DIP1000
On Friday, 24 June 2022 at 05:11:13 UTC, Ola Fosheim Grøstad wrote: No, the lifetime is the same if there is no destructor. Being counter intuitive is poor usability. It depends on whether you expect the rules to be smart or simple. Smart is not necessarily better, as the Unix philosophy tells you. I'm sure you have experience about programs that are unpredictable and thus frustating to use because they try to be too smart.
Re: DIP1000
On Friday, 24 June 2022 at 03:03:52 UTC, Paul Backus wrote: On Thursday, 23 June 2022 at 21:34:27 UTC, Ola Fosheim Grøstad wrote: On Thursday, 23 June 2022 at 21:05:57 UTC, ag0aep6g wrote: It's a weird rule for sure. Another slightly annoying thing is that it cares about destruction order when there are no destructors. If there are no destructors the lifetime ought to be considered the same for variables in the same scope. Having different lifetime rules for different types is worse UX than having the same lifetime rules for all types. Imagine writing a generic function which passes all of your unit tests, and then fails when you try to use it in real code, because you forgot to test it with a type that has a destructor. No, the lifetime is the same if there is no destructor. Being counter intuitive is poor usability. If you want to help library authors you issue a warning for generic code only.
Re: DIP1000
On Thursday, 23 June 2022 at 21:34:27 UTC, Ola Fosheim Grøstad wrote: On Thursday, 23 June 2022 at 21:05:57 UTC, ag0aep6g wrote: It's a weird rule for sure. Another slightly annoying thing is that it cares about destruction order when there are no destructors. If there are no destructors the lifetime ought to be considered the same for variables in the same scope. Having different lifetime rules for different types is worse UX than having the same lifetime rules for all types. Imagine writing a generic function which passes all of your unit tests, and then fails when you try to use it in real code, because you forgot to test it with a type that has a destructor.
Re: DIP1000
On Thursday, 23 June 2022 at 21:05:57 UTC, ag0aep6g wrote: It's a weird rule for sure. Another slightly annoying thing is that it cares about destruction order when there are no destructors. If there are no destructors the lifetime ought to be considered the same for variables in the same scope.
Re: DIP1000
On Thursday, 23 June 2022 at 21:05:57 UTC, ag0aep6g wrote: It means "may be returned or copied to the first parameter" (https://dlang.org/spec/function.html#param-storage). You cannot escape via other parameters. It's a weird rule for sure. Too complicated for what it does… Maybe @trusted isn't so bad after all.
Re: DIP1000
On Thursday, 23 June 2022 at 20:27:44 UTC, Ola Fosheim Grøstad wrote: On Thursday, 23 June 2022 at 19:38:12 UTC, ag0aep6g wrote: ```d void connect(ref scope node a, return scope node* b) ``` Thanks, so the `return scope` means «allow escape», not necessarily return? It means "may be returned or copied to the first parameter" (https://dlang.org/spec/function.html#param-storage). You cannot escape via other parameters. It's a weird rule for sure.
Re: DIP1000
On Thursday, 23 June 2022 at 19:38:12 UTC, ag0aep6g wrote: ```d void connect(ref scope node a, return scope node* b) ``` Thanks, so the `return scope` means «allow escape», not necessarily return? But that only works for this very special case. It falls apart when you try to add a third node. As far as I understand, `scope` cannot handle linked lists. A `scope` pointer cannot point to another `scope` pointer. One can do two levels, but not three. Got it. Works for some basic data-structures.
Re: DIP1000
On Thursday, 23 June 2022 at 16:08:01 UTC, Ola Fosheim Grøstad wrote: How am I supposed to write this: ```d import std; @safe: struct node { node* next; } auto connect(scope node* a, scope node* b) { a.next = b; } void main() { node x; node y; connect(,); } ``` Error: scope variable `b` assigned to non-scope `(*a).next` DMD accepts this: ```d @safe: struct node { node* next; } void connect(ref scope node a, return scope node* b) { a.next = b; } void main() { node y; scope node x; connect(x, ); } ``` But that only works for this very special case. It falls apart when you try to add a third node. As far as I understand, `scope` cannot handle linked lists. A `scope` pointer cannot point to another `scope` pointer. So as to how you're supposed to do it: with @system.
Re: dip1000 return scope dmd v 2.100
On Friday, 6 May 2022 at 17:17:01 UTC, Dennis wrote: On Friday, 6 May 2022 at 09:24:06 UTC, vit wrote: [...] They were recently updated to match the implementation in 2.100. [...] `return scope` means pointer members (such `this.ptr`, `C.ptr`) may not escape the function, unless they are returned. If you call `test()` on a `scope` variable, the return value will be a scope pointer. [...] Thanks
Re: dip1000 return scope dmd v 2.100
On Friday, 6 May 2022 at 09:24:06 UTC, vit wrote: It look like examples at page https://dlang.org/spec/function.html#ref-return-scope-parameters are no longer relevant. They were recently updated to match the implementation in 2.100. What difference are between `return scope`, `scope return` and `return`? `return scope` means pointer members (such `this.ptr`, `C.ptr`) may not escape the function, unless they are returned. If you call `test()` on a `scope` variable, the return value will be a scope pointer. `scope return` on a struct member is `scope` + `return ref`, meaning pointer members may not escape the function (the `scope` part), but you can return a reference to the struct member itself (``, the `return ref` part). If you call `test()` on a local variable (`scope` or not), the return value will be a scope pointer. Just `return` allows you to return a reference to the struct member itself (``), and also to escape pointer members (`this.ptr`) since there is no `scope`. However, that means you can't call `test` on `scope` variables. ``` int* test() scope return{ return // Error: returning `` escapes a reference to parameter `this` } } ``` I think you're using an older DMD version, the error should be gone in 2.100 Why void* ptr in struct change effect of scope return ? `scope` is ignored when the struct has no pointers, and before 2.100, the meaning of `return` + `scope` on `ref` parameters was very inconsistent.
Re: DIP1000 and immutable
On Tuesday, 27 April 2021 at 14:44:48 UTC, Adam D. Ruppe wrote: On Tuesday, 27 April 2021 at 14:28:12 UTC, jmh530 wrote: However, should it ever matter if you escape an immutable? Your example is a pretty clear case of use-after-free if gloin actually did escape the reference and kept it after main returned. I tried basically the same thing in Rust and it doesn't generate errors (their borrow checker should be assuming scope by default). That means it treats gloin as if it is scope, so it isn't the same as your D code since the gloin there is NOT borrowing. Hmmm, good points. Thanks.
Re: DIP1000 and immutable
On Tuesday, 27 April 2021 at 14:28:12 UTC, jmh530 wrote: However, should it ever matter if you escape an immutable? Your example is a pretty clear case of use-after-free if gloin actually did escape the reference and kept it after main returned. I tried basically the same thing in Rust and it doesn't generate errors (their borrow checker should be assuming scope by default). That means it treats gloin as if it is scope, so it isn't the same as your D code since the gloin there is NOT borrowing.
Re: [DIP1000] Something I don't quite understand regarding 'scope'
On Monday, 29 June 2020 at 06:21:43 UTC, ag0aep6g wrote: Since `local` and `writeln` are templates, the attributes for their parameters are inferred from their bodies. `local!(int*)` doesn't do anything with the parameter, so it's inferred as `scope`. `writeln!(int*)` apparently does something that prevents `scope` from being inferred. Thanks. It would appear indeed that inference fails for some reason. Explicitly marking args as 'scope' for `writeln` and `File.write` lets them compile. I wonder if there's a way to find exactly what it is in either of those that prevents the compiler from inferring 'scope'.
Re: [DIP1000] Something I don't quite understand regarding 'scope'
On 29.06.20 02:28, Stanislav Blinov wrote: void local(Args...)(Args args) { } void main() @safe { import std.stdio; scope int* p; local(p); // Ok writeln(p); // Error: scope variable p assigned to non-scope parameter _param_0 calling std.stdio.writeln!(int*).writeln } The signatures of `std.stdio.writeln` and `local` are the same (see `writeln` [1]). Yet, with '$ dmd -preview=dip1000' the call to `local` compiles, while the call to `writeln` doesn't. Since `local` and `writeln` are templates, the attributes for their parameters are inferred from their bodies. `local!(int*)` doesn't do anything with the parameter, so it's inferred as `scope`. `writeln!(int*)` apparently does something that prevents `scope` from being inferred.
Re: DIP1000 spec?
On Friday, 12 June 2020 at 12:49:08 UTC, Steven Schveighoffer wrote: I was just looking through the DIPs in the system, and noticed that DIP1000 is "superseded". I thought that was odd, since it's in the compiler as a switch and is a major driver of discussion and hope for memory safety. In the DIP it says [1]: "This DIP did not complete the review process. It was left in Draft status for an extended period. During that time, an implementation of the proposal was released. It diverged significantly enough from the proposal that the decsion was made by the Language Maintainers, who are also coauthors of the DIP, to retire the DIP as "Superseded" rather than rewriting it." So where is the documentation that describes what is actually implemented? The section on Scope and Return parameters [2] in the spec is pretty light compared to the DIP text, and only addresses parameters, not locals. Without full documentation in the spec, it can be difficult to know whether something should or should not be a bug. -Steve [1] https://github.com/dlang/DIPs/blob/e64bd0adfd3f6617038e214c82bc5093f2d33aea/DIPs/other/DIP1000.md#formal-assessment [2] https://dlang.org/spec/memory-safe-d.html#scope-return-params This is the state of most of Walter's DIPs. He's just making it up as he goes, it's the same thing with the @live implementation. Just buckle up, hold your cheeks tight and hope for the best.
Re: DIP1000 spec?
Logic is apparently still in flux, too early to document.
Re: dip1000, perhaps annotate with return, and vibe-d
On Wednesday, 24 July 2019 at 16:23:48 UTC, Paul Backus wrote: On Wednesday, 24 July 2019 at 12:54:51 UTC, aliak wrote: [...] It should go on the constructor's parameter; i.e., this(auto return ref T value) { /* ... */ } Under the hood, a constructor actually returns the constructed value by reference, so the actual signature of the above constructor seen by the lifetime checker is: ref Optional!T __ctor(auto return ref T value) You can see this for yourself with something like `pragma(msg, typeof(Optional!T.__ctor))`. Thanks! The under the hood stuff was good to know! I was putting it in the right place but it seems to still have been complaining. Ah well. I guess an auto ref on a constructor doesn't really make sense anyway.
Re: dip1000, perhaps annotate with return, and vibe-d
On Wednesday, 24 July 2019 at 12:54:51 UTC, aliak wrote: Trying to get dip1000 flag in use. I have this error: Error: returning Optional(null, false).this(value) escapes a reference to parameter value, perhaps annotate with return in this function: public auto some(T)(auto ref T value) { return Optional!T(value); // <-- error on this line } And it's instantiated from here: static Optional!T fromRepresentation(Json value) { if (value == Json.undefined) { return no!T; } return some(deserializeJson!T(value)); // <-- instantiated from here } I put the qualifier "return" on the parameter to some, but did nothing. And I put it on Optional.this() as well, but I'm not sure where I'm supposed to put it. It should go on the constructor's parameter; i.e., this(auto return ref T value) { /* ... */ } Under the hood, a constructor actually returns the constructed value by reference, so the actual signature of the above constructor seen by the lifetime checker is: ref Optional!T __ctor(auto return ref T value) You can see this for yourself with something like `pragma(msg, typeof(Optional!T.__ctor))`.
Re: DIP1000: Should this compile
On Thursday, 16 May 2019 at 21:56:52 UTC, Steven Schveighoffer wrote: On 5/16/19 10:21 PM, Max Haughton wrote: https://run.dlang.io/is/cKFsXh Should this compile, or is return scope T* down to the user to not escape (Returning directly does not compile) Answer to subject: no. This is a bug. Please file. Not sure what the solution is, because dip1000 makes scope a storage class. So there's no way to tag what the input parameter points at. -Steve The parameter pointer outlives the the , i.e. cannot be guaranteed that it doesn't escape, which is sufficient grounds to not allow the assignment. Hopefully, this is a implementation rather specification error (If my understanding of the DIP is correct)
Re: DIP1000: Should this compile
On Thursday, 16 May 2019 at 21:21:51 UTC, Max Haughton wrote: https://run.dlang.io/is/cKFsXh Should this compile, or is return scope T* down to the user to not escape (Returning directly does not compile) This is a bug, as can be showed by repeating the call to (*boi).writeln - suddenly the output changes between calls. Filed: https://issues.dlang.org/show_bug.cgi?id=19881 -- Simen
Re: DIP1000: Should this compile
On 5/16/19 10:21 PM, Max Haughton wrote: https://run.dlang.io/is/cKFsXh Should this compile, or is return scope T* down to the user to not escape (Returning directly does not compile) Answer to subject: no. This is a bug. Please file. Not sure what the solution is, because dip1000 makes scope a storage class. So there's no way to tag what the input parameter points at. -Steve
Re: dip1000 rule 5
On Tuesday, 27 November 2018 at 08:56:47 UTC, sclytrack wrote: --- How is a person able to understand this DIP? ./dmd -betterC -dip1000 test.d I'll repeat: the DIP does not currently match the implementation. I was not involved in any of it and have no idea what the diff actually is. Walter informed me a while back that he will update the DIP to match the implementation at some point. I'll discuss it with him after the new year and see where we are. --- How many DIP manager are there? I'll assume single person. Yep, just me. When is a DIP assigned a number? --- As soon as I merge the PR. That's the point where it moves from Draft Review to the first round of Community Review (and I will update the procedures doc to reflect that). Which DIPs get merged when depends on a number of factors -- what is the state of each DIP, what's the priority, how many are currently under review in the post-Draft stages, is the author available to move forward, etc.
Re: dip1000 rule 5
On Monday, 26 November 2018 at 09:10:23 UTC, sclytrack wrote: On Sunday, 25 November 2018 at 19:22:36 UTC, sclytrack wrote: There are 4 rules listed. https://github.com/dlang/DIPs/blob/master/DIPs/DIP1000.md What is rule 5? int* global_ptr; void abc() { scope int* a; int* b; scope int* c = a; // Error, rule 5 scope int* d = b; // Ok int* i = a;// Ok, scope is inferred for i global_ptr = d;// Error, lifetime(d) < lifetime(global_ptr) global_ptr = i;// Error, lifetime(i) < lifetime(global_ptr) int* j; global_ptr = j;// Ok, j is not scope } --- Are the following assumptions correct? lifetime(a) < lifetime(b) Means that b is older and lives longer than a. Or better, the data that b is pointing to is older and lives longer than the one that a is pointing too. With the exception of the null pointer which gets unlimited lifetime because it does not corrupt memory. --- scope int * a; The variable gets unlimited lifetime because the value it is pointing is assigned null. And that throws exception when trying to access the memory and because it does not corrupt memory it is assigned unlimited lifetime. Also once a variable is assigned unlimited lifetime, then it retains that unlimited lifetime during the entire reachability of the variable. scope int * c = a; works The above is allowed. You are assigning a variable that according to the compiler has unlimited lifetime. Therefore the variable c will be handled like it has unlimited lifetime by the compiler. lifetime(c) <= lifetime(a) The dip talks about longer and shorter, but is equal okay too? int * c = a; works (compiles without error and is inferred scope) The above can not be inferred because scope is only inferred when it is assigned a limited lifetime. So it is an error. Rule number 2 of the DIP1000 between quotes "2. A variable is inferred to be scope if it is initialized with a value that has a non-∞ lifetime." I made an error here. Once scope always scope. And will infer scope as much as possible. Rule two is more for local variables that haven't even been marked with scope. A pointer to them needs to be inferred scope. --- How is a person able to understand this DIP? ./dmd -betterC -dip1000 test.d --- How many DIP manager are there? I'll assume single person. When is a DIP assigned a number? ---
Re: dip1000 rule 5
On Sunday, 25 November 2018 at 19:22:36 UTC, sclytrack wrote: There are 4 rules listed. https://github.com/dlang/DIPs/blob/master/DIPs/DIP1000.md What is rule 5? int* global_ptr; void abc() { scope int* a; int* b; scope int* c = a; // Error, rule 5 scope int* d = b; // Ok int* i = a;// Ok, scope is inferred for i global_ptr = d;// Error, lifetime(d) < lifetime(global_ptr) global_ptr = i;// Error, lifetime(i) < lifetime(global_ptr) int* j; global_ptr = j;// Ok, j is not scope } --- Are the following assumptions correct? lifetime(a) < lifetime(b) Means that b is older and lives longer than a. Or better, the data that b is pointing to is older and lives longer than the one that a is pointing too. With the exception of the null pointer which gets unlimited lifetime because it does not corrupt memory. --- scope int * a; The variable gets unlimited lifetime because the value it is pointing is assigned null. And that throws exception when trying to access the memory and because it does not corrupt memory it is assigned unlimited lifetime. Also once a variable is assigned unlimited lifetime, then it retains that unlimited lifetime during the entire reachability of the variable. scope int * c = a; The above is allowed. You are assigning a variable that according to the compiler has unlimited lifetime. Therefore the variable c will be handled like it has unlimited lifetime by the compiler. lifetime(c) <= lifetime(a) The dip talks about longer and shorter, but is equal okay too? int * c = a; The above can not be inferred because scope is only inferred when it is assigned a limited lifetime. So it is an error. --- How is a person able to understand this DIP? --- How many DIP manager are there? When is a DIP assigned a number? ---
Re: dip1000 rule 5
On Sunday, 25 November 2018 at 21:22:09 UTC, sclytrack wrote: Did DIP1000 go through any review process? I'm seeing it is a draft. The previous DIP manager marked DIPs as Draft while they were under review. I don't use that anymore. I left DIP1000 untouched after I took over, however. Walter told me he'll revise it at some point to reflect the actual implementation. https://github.com/dlang/DIPs/blob/master/PROCEDURE.md Keeps talking about a Drafts subdirectory. I don't see any directory named "Drafts". It was originally my intention to push new DIPs into a Drafts subdirectory for the Draft Review stage, but it's more convenient to handle it in the pull request thread. I never edited the document to reflect that and didn't notice it when I've looked it over. Now that you've pointed it out, I'll revise it.
Re: dip1000 rule 5
On Sunday, 25 November 2018 at 21:22:09 UTC, sclytrack wrote: Did DIP1000 go through any review process? I'm seeing it is a draft. Review links are at the very end. https://github.com/dlang/DIPs/blob/master/PROCEDURE.md Keeps talking about a Drafts subdirectory. I don't see any directory named "Drafts". Not sure about that one. Maybe Mike Parker could elaborate on this.
Re: dip1000 rule 5
On Sunday, 25 November 2018 at 19:49:03 UTC, Stanislav Blinov wrote: On Sunday, 25 November 2018 at 19:22:36 UTC, sclytrack wrote: There are 4 rules listed. ... What is rule 5? ... Wouldn't you call it D3 because of the name mangling of DIP1000 once activated by default? That "rule 5" looks like a straight up mistake. As for D3... IMHO, no, not by a long shot. There's 1014 and 1016, 1008, there's `shared`, there are improved move-assignments, there's `__mutable` and `@__future`, there are tons of issues in Bugzilla, the standard library is long overdue for a huge look-over... Did DIP1000 go through any review process? I'm seeing it is a draft. https://github.com/dlang/DIPs/blob/master/PROCEDURE.md Keeps talking about a Drafts subdirectory. I don't see any directory named "Drafts". I only see accepted archived //old stuff rejected
Re: dip1000 rule 5
On Sunday, 25 November 2018 at 19:22:36 UTC, sclytrack wrote: There are 4 rules listed. ... What is rule 5? ... Wouldn't you call it D3 because of the name mangling of DIP1000 once activated by default? That "rule 5" looks like a straight up mistake. As for D3... IMHO, no, not by a long shot. There's 1014 and 1016, 1008, there's `shared`, there are improved move-assignments, there's `__mutable` and `@__future`, there are tons of issues in Bugzilla, the standard library is long overdue for a huge look-over...
Re: dip1000: why can't the addressee come into existence later?
On Sat, 10 Nov 2018 16:25:40 +, Stanislav Blinov wrote: > Yep, you just over-simplified the first case. It is too simple to clearly illustrate why the code is invalid, but not so simple that the compiler accepts that code. > Consider: > > int* p; > { > int i; > p = > } > *p = 42; In that example, the scope for i ends before the scope for p ends. It's not at all surprising that that code is wrong. In the other examples I gave, both i and p go out of scope at the same time. But there's a total ordering for when variables' lifetimes end, which is the key (and non-obvious) difference between the two.
Re: dip1000: why can't the addressee come into existence later?
On Saturday, 10 November 2018 at 06:56:29 UTC, Neia Neutuladh wrote: The following code doesn't work with @safe -dip1000: int* p; int i; p = i has a shorter lifetime than p, the compiler complains. But this code does: int i; int* p; p = The compiler does this even in the absence of scope guards and destructors because simple, obvious rules will be easier to understand and implement than nuanced ones, even if it makes you reorder declarations sometimes. Is this right? Yep, you just over-simplified the first case. Consider: int* p; { int i; p = } *p = 42; or even: module thing; int* global; void foo() { int i; global = } ...much simpler to just go by the lifetime, instead of attempting to do a complex analysis. Because for the latter, it would then *need* to be deep to be of any use at all. Especially in a language that has static ifs: // parameter is not scope, function is not pure, etc. void nasty(int* p) { /* ... */ } void main() { int *p; int i; p = static if (someCondition) nasty(p); }
Re: dip1000: why can't the addressee come into existence later?
On Sat, 10 Nov 2018 11:47:24 +, Nicholas Wilson wrote: > On Saturday, 10 November 2018 at 06:56:29 UTC, Neia Neutuladh wrote: >> Is this right? > > Are you sure you added @safe to the second example? > https://run.dlang.io/is/2RbOwK fails to compile. Maybe take another look at the post you're replying to? I was saying that, if the compiler allowed one thing that looked safe to me, it would either require nuance (check for scope guards, destructors, and the like before saying something is un-@safe) or allow other code that is obviously invalid.
Re: dip1000: why can't the addressee come into existence later?
On Saturday, 10 November 2018 at 06:56:29 UTC, Neia Neutuladh wrote: Is this right? Are you sure you added @safe to the second example? https://run.dlang.io/is/2RbOwK fails to compile.
Re: dip1000 issue
On 9/7/18 7:59 AM, Orfeo wrote: On Friday, 7 September 2018 at 14:36:18 UTC, rikki cattermole wrote: On 08/09/2018 2:29 AM, Orfeo wrote: ==> And why (maybe a silly question) `-dip1000` breaks my project so badly without warning.. DIP 1000 is an experimental addition to D, that is yet to be complete. It is a compiler switch for a reason, it isn't ready for usage, only some experimentation. Thank you very much... I agree with you, but if someone adds `dip1000` in a library and I link it, my project inherits this setting. What do you think? is it correct? Some suggestions to avoid it? The sub-project is being compiled with dip1000. I don't know what the rules are for dip1000 and dub, but it's likely the flags are propagated. One of the main drawbacks of dip1000 is that if you don't have it enabled on ALL projects, you will likely run into linker errors. It's like compiling 2 libraries with different versions and expecting them to link. It's probably the reason dub forwards the switches. Separately, if dmd is failing with signal 11 (SEGFAULT), this is a compiler bug. The compiler should never segfault. At this point, it's hard to tell from what you have given what may cause the error. But maybe if your project is open source, you can file a bug with the link to the project? Or if you can narrow down the code in your project to a minimum that causes the error, it can be diagnosed further. -Steve
Re: dip1000 issue
On Friday, 7 September 2018 at 14:36:18 UTC, rikki cattermole wrote: On 08/09/2018 2:29 AM, Orfeo wrote: ==> And why (maybe a silly question) `-dip1000` breaks my project so badly without warning.. DIP 1000 is an experimental addition to D, that is yet to be complete. It is a compiler switch for a reason, it isn't ready for usage, only some experimentation. Thank you very much... I agree with you, but if someone adds `dip1000` in a library and I link it, my project inherits this setting. What do you think? is it correct? Some suggestions to avoid it?
Re: dip1000 issue
On 08/09/2018 2:29 AM, Orfeo wrote: ==> And why (maybe a silly question) `-dip1000` breaks my project so badly without warning.. DIP 1000 is an experimental addition to D, that is yet to be complete. It is a compiler switch for a reason, it isn't ready for usage, only some experimentation.
Re: dip1000 issue
Sorry, I pressed send too quickly On Friday, 7 September 2018 at 14:04:47 UTC, Orfeo wrote: I've a project that link FuzzyCopy [1], that was compiled without problems. So I add FuzzyCopy library [1], I update dmd, then: ==> I've a project that was compiled without problems. So I add FuzzyCopy library [1], I update dmd, then: And why (maybe a silly question) `-dip1000`dip1000 my project so badly without warning.. ==> And why (maybe a silly question) `-dip1000` breaks my project so badly without warning..
Re: -dip1000 @safe scope wrapper
On Thursday, 28 June 2018 at 13:29:58 UTC, vit wrote: Hello, Is it possible to create scope wrapper initialized by non default constructor with scope parameter? something like this: struct Wrapper{ int* p; static Wrapper create(scope return int* p)@safe{ Wrapper w; w.p = p; return w; } /++ This doesn't work: this(scope return int* p)@safe scope{ this.p = p; }+/ } void main()@safe{ scope int i; scope Wrapper w1 = Wrapper.create(); scope Wrapper w2 = Wrapper(); } I'm not sure why create works in this case either. I get the following when I uncomment the constructor test.d(12): Error: scope variable p assigned to this with longer lifetime Is there a subtle difference I'm missing?