Thread overview | |||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
March 15, 2015 The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Here's the new version of my scope proposal: http://wiki.dlang.org/User:Schuetzm/scope2 It's still missing real-life examples, a section on the implementation, and a more formal specification, as well as a discussion of backwards compatibility. But I thought I'd show what I have, so that it can be discussed early on. I hope it will be more digestible for Walter & Andrei. It's more or less an extended version of DIP25, and avoids the need for most explicit annotations. |
March 15, 2015 Re: The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On 15/03/2015 14:10, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
> Here's the new version of my scope proposal:
> http://wiki.dlang.org/User:Schuetzm/scope2
>
> It's still missing real-life examples, a section on the implementation,
> and a more formal specification, as well as a discussion of backwards
> compatibility. But I thought I'd show what I have, so that it can be
> discussed early on.
>
> I hope it will be more digestible for Walter & Andrei. It's more or less
> an extended version of DIP25, and avoids the need for most explicit
> annotations.
I too want a scope attribute e.g. for safe slicing of static arrays, etc. I'm not sure if it's too late for scope by default though, perhaps.
I like postblit overloading on whether 'this' can be scope or not, allowing efficient ref-counting.
scope T payload;
^ This is a nice way to help enforce the correctness of @safe wrapper types.
|
March 15, 2015 Re: The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nick Treleaven | On Sunday, 15 March 2015 at 17:31:17 UTC, Nick Treleaven wrote: > On 15/03/2015 14:10, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote: >> Here's the new version of my scope proposal: >> http://wiki.dlang.org/User:Schuetzm/scope2 >> >> It's still missing real-life examples, a section on the implementation, >> and a more formal specification, as well as a discussion of backwards >> compatibility. But I thought I'd show what I have, so that it can be >> discussed early on. >> >> I hope it will be more digestible for Walter & Andrei. It's more or less >> an extended version of DIP25, and avoids the need for most explicit >> annotations. > > I too want a scope attribute e.g. for safe slicing of static arrays, etc. I'm not sure if it's too late for scope by default though, perhaps. If we get @safe by default, we automatically get scope by default, too. > > I like postblit overloading on whether 'this' can be scope or not, allowing efficient ref-counting. > > scope T payload; > > ^ This is a nice way to help enforce the correctness of @safe wrapper types. Yes, it's an exception to the general rule of "scope only in function signatures", but it's so useful I think it's worth it. |
March 16, 2015 Re: The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Sunday, 15 March 2015 at 14:10:02 UTC, Marc Schütz wrote:
> Here's the new version of my scope proposal:
> http://wiki.dlang.org/User:Schuetzm/scope2
>
> It's still missing real-life examples, a section on the implementation, and a more formal specification, as well as a discussion of backwards compatibility. But I thought I'd show what I have, so that it can be discussed early on.
>
> I hope it will be more digestible for Walter & Andrei. It's more or less an extended version of DIP25, and avoids the need for most explicit annotations.
It's great to see your design evolving like this. BIG plus for `scope` by default in @safe code -- this makes the proposal much more attractive than the alternative.
"Functions and methods can be overloaded on scope. This allows efficient passing of RC wrappers for instance..."
How does the compiler figure out which of the variables it's passing to the parameters are `scope` or not? Does the caller try the scoped overloads first by default, and only if there's an error tries the non-scoped overloads? If so, what causes the error?
"To specify that the value is returned through another parameter, the return!ident syntax can be used...
struct RC(T) if(is(T == class)) {
scope T payload;
T borrow() return { // `return` applies to `this`
return payload;
}
}"
The example contains no use of `return!ident`.
Also, what exactly does the `scope` on T payload get you? Is it just a more specific version of `return` on the this parameter, i.e. `return this.payload`? Why would you need that specificity? What is the dangerous operation it is intended to prevent?
|
March 16, 2015 Re: The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On 15/03/2015 19:11, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote: > On Sunday, 15 March 2015 at 17:31:17 UTC, Nick Treleaven wrote: >> I too want a scope attribute e.g. for safe slicing of static arrays, >> etc. I'm not sure if it's too late for scope by default though, perhaps. > > If we get @safe by default, we automatically get scope by default, too. I don't follow that. In @safe code parameters could still default to escaping, causing compiler errors when passing things that can't be allowed to escape. I do see that scope parameters by default would probably cause less churn than having to put `scope` on non-template function parameters in order to be usable by non-GC-heap memory. >> scope T payload; >> >> ^ This is a nice way to help enforce the correctness of @safe wrapper >> types. > > Yes, it's an exception to the general rule of "scope only in function > signatures", but it's so useful I think it's worth it. We already have scope on local delegates (at least it's accepted by dmd): Object obj; scope del = ()=>obj; Also, what would be the 'type' of a static array slice without `scope` applying to locals? int[2] arr = [1, 2]; scope int[] s = arr; I suppose `scope` can be inferred for s, I'm just pointing out that it can apply to locals. |
March 16, 2015 Re: The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Posted in reply to Zach the Mystic | On 16/03/2015 04:00, Zach the Mystic wrote: > struct RC(T) if(is(T == class)) { > scope T payload; > T borrow() return { // `return` applies to `this` > return payload; > } > } ... > Also, what exactly does the `scope` on T payload get you? It means if you forget the `return` attribute the compiler would issue an error about escaping payload. payload only has to be annotated once and the whole body of RC is checked to prevent implicit escaping of it. |
March 16, 2015 Re: The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | Marc Schütz:
> Here's the new version of my scope proposal:
> http://wiki.dlang.org/User:Schuetzm/scope2
Let's see what Andrei and Walter think about this all :-)
Bye,
bearophile
|
March 16, 2015 Re: The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Posted in reply to Zach the Mystic | On Monday, 16 March 2015 at 04:00:51 UTC, Zach the Mystic wrote: > "Functions and methods can be overloaded on scope. This allows efficient passing of RC wrappers for instance..." > > How does the compiler figure out which of the variables it's passing to the parameters are `scope` or not? Does the caller try the scoped overloads first by default, and only if there's an error tries the non-scoped overloads? If so, what causes the error? Hmm... I guess it only makes sense for postblits and destructors. I'm not sure about constructors and opAssign, so I'll leave these out for now. I've changed the wiki page accordingly. > > "To specify that the value is returned through another parameter, the return!ident syntax can be used... > > struct RC(T) if(is(T == class)) { > scope T payload; > T borrow() return { // `return` applies to `this` > return payload; > } > }" > > The example contains no use of `return!ident`. I added an example. > > Also, what exactly does the `scope` on T payload get you? Is it just a more specific version of `return` on the this parameter, i.e. `return this.payload`? Why would you need that specificity? What is the dangerous operation it is intended to prevent? Nick already answered that. I'll expand on his explanation: Let's take the RC struct as an example. Instances of RC can appear with and without scope. Because structs members inherit the scope-ness from the struct, `payload` could therefore be an unscoped pointer. It could therefore be escaped unintentionally. By adding `scope` to its declaration, we force it to be scoped to the structs lifetime, no matter how it's accessed. |
March 16, 2015 Re: The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nick Treleaven | On Monday, 16 March 2015 at 12:21:17 UTC, Nick Treleaven wrote: > On 15/03/2015 19:11, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote: >> On Sunday, 15 March 2015 at 17:31:17 UTC, Nick Treleaven wrote: >>> I too want a scope attribute e.g. for safe slicing of static arrays, >>> etc. I'm not sure if it's too late for scope by default though, perhaps. >> >> If we get @safe by default, we automatically get scope by default, too. > > I don't follow that. In @safe code parameters could still default to escaping, causing compiler errors when passing things that can't be allowed to escape. > > I do see that scope parameters by default would probably cause less churn than having to put `scope` on non-template function parameters in order to be usable by non-GC-heap memory. It's part of the proposal, under "Implicit scope": @safe implies scope. I think this would cause the least compatibility problems, because what can be done with references in @safe code is already restricted. And as @safe is going to be used more and more, scope will spread with it. > We already have scope on local delegates (at least it's accepted by dmd): > > Object obj; > scope del = ()=>obj; Oh, I thought this was deprecated, together with scope classes. I was aware that `scope` already works (at least partially) for delegate params, but not for locals. Anyway, I think it's unnecessary for locals, because: > > Also, what would be the 'type' of a static array slice without `scope` applying to locals? > > int[2] arr = [1, 2]; > scope int[] s = arr; > > I suppose `scope` can be inferred for s, I'm just pointing out that it can apply to locals. Yes, it will be inferred. I've removed this part of the proposal from the article, because I thought it is too technical, and I wanted to describe only what would be visible to the end-user. But I moved my notes about that to the talk page [1]. The examples further up on this page are a bit chaotic; they were experiments for me to try out the algorithm. While the algorithm as described there probably works, I want to change it a bit to allow detection for the RCArray problem. The important thing is that the end-user doesn't have to annotate local variables as scope. As it's unnecessary, we can even consider disallowing it. [1] http://wiki.dlang.org/User_talk:Schuetzm/scope2#Scope_inference |
March 16, 2015 Re: The next iteration of scope | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Monday, 16 March 2015 at 13:55:43 UTC, Marc Schütz wrote:
>> Also, what exactly does the `scope` on T payload get you? Is it just a more specific version of `return` on the this parameter, i.e. `return this.payload`? Why would you need that specificity? What is the dangerous operation it is intended to prevent?
>
> Nick already answered that. I'll expand on his explanation:
>
> Let's take the RC struct as an example. Instances of RC can appear with and without scope. Because structs members inherit the scope-ness from the struct, `payload` could therefore be an unscoped pointer. It could therefore be escaped unintentionally. By adding `scope` to its declaration, we force it to be scoped to the structs lifetime, no matter how it's accessed.
If an RC'd struct is heap-allocated, but one of its members points to the stack, how is it ever safe to escape it? Why shouldn't the heap variable be treated as scoped too, inheriting the most restricted scope of any of its members? To me, the question is not how you can know that a member is scoped, so much as how you could know that it *isn't* scoped, i.e. that a sub-pointer was global while the parent was local. I think it would require a very complicated type system:
struct S {
T* p;
}
// note the elaborate new return signature
T* fun(return!(S.p) S x) {
return x.p;
}
T* run() {
S s;
s.p = new T; // s local, s.p global
return fun(s);
}
The above is technically safe, but the question is whether it's too complicated for the benefit. In the absence of such a complicated system, the safe default is to assume a struct is always as scoped as its most scoped member (i.e. transitive scoping). Your idea of `scope` members would only be valid in the absence of this safe default. But even then it would be of limited usefulness, because it would prevent all uses of global references in those members, even if the parent was global. For me, it comes down to that you can't know if anything is global or local until you define an instance of it, which you can't do in the struct definition.
|
Copyright © 1999-2021 by the D Language Foundation