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
:
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:
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:
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?
// 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, 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).