Thread overview
New attribute to control references
Apr 25, 2022
Loara
Apr 26, 2022
Salih Dincer
Apr 26, 2022
Loara
Apr 27, 2022
Loara
Apr 27, 2022
Dennis
Apr 27, 2022
Loara
Apr 27, 2022
Dennis
Apr 27, 2022
Loara
April 25, 2022

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:

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:

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:

    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:

    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.

April 26, 2022

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

April 26, 2022

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.

April 27, 2022

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.

April 27, 2022

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:

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?

April 27, 2022

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:

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.

April 27, 2022

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.

April 27, 2022

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.