Escape Analysis & Owner Escape Analysis

Dennis dkorpel at gmail.com
Wed Sep 4 10:24:51 UTC 2024


On Wednesday, 4 September 2024 at 03:02:10 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
> It would be an easy enough swap to change ``@safe`` to 
> ``@tsafe``. But that isn't a decision we need to make here. We 
> can make that prior to launch.

`@safe` `@trusted` and `@system` are already misunderstood as 
they are, we really don't want to throw a fourth attribute into 
the mix.

> But I do want to make a point here, owner escape analysis only 
> kicks in and forces effectively const on the owner if:

That's not consistent with this example from the DIP, where 
there's no `scope` or `&field`:

```D
struct Top {
	int* field;
}

void func(ref Top owner) @safe {
	int* field = owner.field;
	// owner is now effectively const, it cannot be mutated
	
	owner = Top.init; // Error: The variable `owner` has a borrow 
and cannot be mutated
```

> This is the same meaning it has today with DIP1000.

Today, `scope` doesn't imply 'strong relationship with input 
variable', only `return ref` does.

> It needs to mean something, so got an alternative?

No, because I don't like this escape set definition syntax in the 
first place.

> Giving ``scope`` a default escape set is to allow it to match 
> existing understanding, which does help with communicability.

That's sending mixed messages. On the one hand, this DIP 
completely redefines lifetime semantics and syntax, trying to 
forget DIP1000 ever existed. On the other hand, it adds a special 
meaning to `scope` feigning some sort of backward compatibility, 
but adding a new double meaning to the keyword, which is the very 
thing the new syntax is supposed to fix!

> Yes you are correct.
>
> If you were allowed to take a pointer to a by-ref variable and 
> then store it some place you are most likely escaping a pointer.

The address of the variable and the pointer value it holds are 
two different things. So the following becomes impossible to 
express with this DIP:

```D
int* global;

int** f(return ref int* v) @safe
{
     global = v;
     return &v;
}
```

> I'm going to need an example of what you think is not addressed 
> here.

To clarify, the headings in my post are common DIP1000 woes that 
alternative DIPs should have an answer to. Timon has brought up 
the composability problem before:

```D
import std.typecons;
int* y;
int* foo(){
     int x;
     auto t=tuple(&x,y); // type has to be Tuple!(scope(int*),int*)
     return t[1];
}
```

https://forum.dlang.org/post/qqgjop$kan$1@digitalmars.com

The example could compile, but it doesn't because the entire 
tuple shares one lifetime.
Another example is item 1 of my post: 
https://forum.dlang.org/post/icoavlbaxqpcnkhijcpy@forum.dlang.org

> From my perspective the field gets conflated with its 
> containing instance variable and that covers composability.

So this DIP's answer is: tough luck, we're still conflating.

> ``scope`` is not transitive, at least as far as the language 
> knows transitive to mean.

Same here, I meant to say that "lack of transitive scope" is a 
DIP1000 woe that the DIP should address. The DIP doesn't have a 
single example where a pointer gets dereferenced and then 
escaped. What happens to the following examples?

```D
// Assuming -preview=dip1000

int* deref(scope int** x) @safe => *x; // currently allowed
// because x gets dereferenced and scope only applies to first 
indirection

void main() @safe
{
     int x, y;
     scope int[] arr = [&x, &y]; // currently not allowed
     // because it requires scope to apply to two levels of 
pointer indirection
}
```

> I focus upon multiple outputs, because to make flattening to a 
> function signature to work, you have to do this. If you don't 
> you are not going to model enough code, and will be going 
> against the literature on this subject making it harder to use.

Walter has stated that he's not looking for a complete lifetime 
tracking solution for all possible situations, just something 
simple and pragmatic to cover common cases. In the [DIP1000 woes 
thread](https://forum.dlang.org/post/xvzzmgwibbjhuvmnhrgi@forum.dlang.org), the only multiple output-related issue is with `swap`. This DIP's syntax is overkill to solve just that problem. It would help if there were examples of actual code that really needs to use @escape(parametername).



More information about the dip.ideas mailing list