www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - New attribute to control references

reply Loara <loara noreply.com> writes:
I wrote a simple article about an extended `scope` attribute that 
manages pointers and types that contains indirections:

https://github.com/Loara/Rethink_scope_in_D/blob/main/README.md

I called this new attribute `rscope` (this is a temporary name, 
I'll change it in future in order to avoid misunderstandings), 
any variable or function parameter marked as `rscope` can be 
referenced only by other variables that are also `rscope`:

````d
rscope int i = 1;
int j = i; //ok, doesn't share references
//ref int k = i; error: k holds a reference to i
rscope ref int h = i; //ok, both rscope

rscope int *ip = new int (3);
//int *iq = ip; error: reference sharing
int *ik = new int(*ip); //ok
//rscope *ih = ik; error: ik is not rscope, see the link

struct A{
   int a;
   int *b;
}
rscope A a = {1, &i}; //ok, i rscope
//A b = a; //error, A has indirections, a rscoped but b no
````

Also you can use labelled `rscope` in order to avoid to share 
references between two or more `rscope` variables:
````d
rscope(A) int *a = ...;
rscope(A) int *b = a;//ok
//rscope(B) int *c = a; error: different rscope groups
````

Why and where use this new attribute? Everywhere you need to 
avoid references escape:
- when dealing with unsafe casts:

     ````d
     class A{...}
     ...
     const A a = ...
     ...
     rscope{//every variable declared inside this block is 
automatically rscope
       A a_unsafe = cast(A) a;
       //now you can use a_unsafe inside this block
       ...
     }
     //Now any reference to a_unsafe should be expired
     ````
- inside a `synchronized` block:

     ````d
     shared int i;
     Mutex mutex;
     ....
     synchronized(mutex){
       rscope{
         rscope ref int i_ref = get_rscoped_ref!int(i);
         ....
       }
     }
     ````

If you think these features would be interesting I'll write a new 
DIP and propose it, so I'm waiting your feedbacks.
Apr 25 2022
next sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Monday, 25 April 2022 at 16:06:00 UTC, Loara wrote:
 I wrote a simple article about an extended `scope` attribute 
 that manages pointers and types that contains indirections:
 https://github.com/Loara/Rethink_scope_in_D/blob/main/README.md
It sounds good! I will definitely read it, but it should not stay in theory. Is there a way to try it? For example, with the UDA... On Monday, 25 April 2022 at 16:06:00 UTC, Loara wrote
 I called this new attribute `rscope` (this is a temporary name, 
 I'll change it in future in order to avoid misunderstandings), 
 any variable or function parameter marked as `rscope` can be 
 referenced only by other variables that are also `rscope`:
I think it makes a lot of sense! I think rscope here means (referenceScope)? SDB 79
Apr 25 2022
parent Loara <loara noreply.com> writes:
On Tuesday, 26 April 2022 at 00:16:23 UTC, Salih Dincer wrote:
 It sounds good!

 I will definitely read it, but it should not stay in theory.  
 Is there a way to try it?  For example, with the UDA...
Actually I haven't implemented it yet, since I don't know how to scan functions body and expressions in order to test code. Nothing forbits us to implement a ` rscope` UDA but it'd be useless until the compiler checks the code. On Tuesday, 26 April 2022 at 00:16:23 UTC, Salih Dincer wrote:
 I think it makes a lot of sense!  I think rscope here means 
  (referenceScope)?
A bit, since we're working with references the classical meaning of block scope is too restrictive since an object allocated via `new` can exist among different scopes.
Apr 26 2022
prev sibling next sibling parent Loara <loara noreply.com> writes:
On Monday, 25 April 2022 at 16:06:00 UTC, Loara wrote:
 I wrote a simple article about an extended `scope` attribute 
 that manages pointers and types that contains indirections:

 [...]
Since adding new attributes to D language also increases the "attribute pollution" (even now for each new function you should usually add at least three attributes) I want to be sure that this feature would be useful for more than a few people, otherwise it's better to move to some more popular proposals.
Apr 27 2022
prev sibling parent reply Dennis <dkorpel gmail.com> writes:
On Monday, 25 April 2022 at 16:06:00 UTC, Loara wrote:
 https://github.com/Loara/Rethink_scope_in_D/blob/main/README.md
The first section notes that DIP1000's documentation is lacking, which is true and something I'm working on (see for example https://github.com/dlang/dlang.org/pull/3284). It then mentions the lack of transitive scope, a known limitation, but with a curious example: ```D scope int **b = stack_allocate!(int *)(); ``` How would that function return a non-dangling stack pointer?
 A simple solution could be force scope variables to be used 
 only as scope function parameters (...) but in this way we've 
 made set completely useless, why we have to define a set 
 function if we can't use it to set a member?
Indeed, that's how it currently works, so you can't assign `scope` variables to a class field because `scope` only applies to the class reference itself. You can make a `set` function for a struct by marking the `p` parameter `return scope`.
 So the scope attribute is not what the manual-memory managment 
 fans are waiting [for]
That's assuming the given examples are representative of actual code. They could be, but personally, I usually only manually manage flat arrays. I know the current `scope` storage class leaves some things to be desired, but I don't understand why you propose a completely new attribute. Can a 'transitive scope' extension also suffice?
Apr 27 2022
parent reply Loara <loara noreply.com> writes:
On Wednesday, 27 April 2022 at 14:58:12 UTC, Dennis wrote:
 It then mentions the lack of transitive scope, a known 
 limitation, but with a curious example:
 ```D
 scope int **b = stack_allocate!(int *)();
 ```
 How would that function return a non-dangling stack pointer?
It could initialize the stack allocated pointer to `null` if no argument is passed, but it could be also a ` trusted` function, this is not the point, the point is that with a not transitive `scope` it's still possible to transfer references to non `scope` pointers without explicit casts.
 A simple solution could be force scope variables to be used 
 only as scope function parameters (...) but in this way we've 
 made set completely useless, why we have to define a set 
 function if we can't use it to set a member?
Indeed, that's how it currently works, so you can't assign `scope` variables to a class field because `scope` only applies to the class reference itself. You can make a `set` function for a struct by marking the `p` parameter `return scope`.
I admit the `return scope` attribute is a bit esoteric for me, I need to study it better.
 I know the current `scope` storage class leaves some things to 
 be desired, but I don't understand why you propose a completely 
 new attribute. Can a 'transitive scope' extension also suffice?
Originally I wrote these articles in order to specify how to implement a transitive `scope` attribute, but this would be too restrictive if the primary scope of `scope` is to allow stack allocation of objects. A transitive scope is more appropriate for `synchronized` access to a `shared` variable that contains indirections rather than a stack allocated object. But these are only my personal opinions.
Apr 27 2022
parent reply Dennis <dkorpel gmail.com> writes:
On Wednesday, 27 April 2022 at 15:51:36 UTC, Loara wrote:
 this is not the point, the point is that with a not transitive 
 `scope` it's still possible to transfer references to non 
 `scope` pointers without explicit casts.
I think it's unclear what the example is demonstrating then. If the point is "the lack of an error here shows a hole in` safe`" then that's incorrect, because a function `stack_allocate!int(1);` can't return a scope pointer, and if you changed the signature so it could, dip1000 wouldn't allow you to assign it to `*b`. If the point is "a transitive `scope` enables this pattern" then that's also incorrect, because you still can't actually implement `stack_allocate!int(1);`. If, like you just clarified, the point is simply "`scope` isn't transitive", then that's correct, but that doesn't explain why there's a need for improvement in that regard.
 A transitive scope is more appropriate for `synchronized` 
 access to a `shared` variable that contains indirections rather 
 than a stack allocated object.
I've never thought about using `scope` in combination with shared data, but it's an interesting thing to consider.
Apr 27 2022
parent Loara <loara noreply.com> writes:
On Wednesday, 27 April 2022 at 17:12:04 UTC, Dennis wrote:
 On Wednesday, 27 April 2022 at 15:51:36 UTC, Loara wrote:
 this is not the point, the point is that with a not transitive 
 `scope` it's still possible to transfer references to non 
 `scope` pointers without explicit casts.
I think it's unclear what the example is demonstrating then.
That examples were written because I didn't understand many features about `scope` since the official documentation wasn't so clear. But once I focus on the `synchronized` access to `shared` data the initial purpose of these pages have changed and now them are no longer useful.
 A transitive scope is more appropriate for `synchronized` 
 access to a `shared` variable that contains indirections 
 rather than a stack allocated object.
I've never thought about using `scope` in combination with shared data, but it's an interesting thing to consider.
Since I don't know if a transitive `scope` would be useful also for stack-allocated variables or not, I've chosen the `rscope` name only to distinguish it from the standard and not transitive `scope` attribute.
Apr 27 2022