DIP71: 'noscope' and 'out!param' attributes

Zach the Mystic via Digitalmars-d digitalmars-d at puremagic.com
Sun Jan 18 14:51:17 PST 2015


On Sunday, 18 January 2015 at 19:05:37 UTC, Marc Schütz wrote:
> Some random comments:
>
> I like that it applies to all kinds of references, not just 
> `ref`. Do you want it to apply to structures with reference 
> members, too? What about value types in general?

I have some thoughts about `ref` that I will say at a different 
time.

I think any structure with a reference member must be treated 
like a reference type.

Value types with no references will certainly never require these 
attributes. I'm not sure if it should be an error to add them or 
not. Probably not.

> About `out!`: I think this should be placed next to the 
> escaping parameter for consistency (i.e. `out!p2 T* p1` in your 
> example), because all other annotations are already at the 
> parameters that escape.

I would disagree here. Consistency for its own sake isn't 
convincing. The outgoing parameter (p2) will probably be less 
cluttered and further to the right, enhancing overall 
readability. But more importantly, only the users of p2 will need 
to know that it's special (i.e., that its scope is restricted to 
that of p1). The relevant information is kept close to the place 
it is required. Makes sense?

> Instead of `noscope`, I suggest `static`, because that's 
> already a keyword and will not clash with existing code. (Note 
> that this can the apply to `this`, and `static` then needs to 
> be placed behind the function to distinguish it from a static 
> method declaration, where it appears in front.)

Interesting suggestion! You might be right. I should tell you how 
I got to `noscope`. There's a fourth way a reference can escape, 
which clouded my thinking such that I didn't include it in the 
DIP, because it wasn't technically necessary. But now, I'm trying 
to figure it out again. In particular, let's call it escaping by 
heap.

T** fun(return T* t) {
   T** u = new T*;
   *u = t;
   return u;
}

T** gun() {
   T v;
   T* w = &v;
   return fun(w); // no good, despite heap allocation
}

I had thought that a new heap variable was the equivalent of a 
global variable, because both have infinite lifetime. Hence, 
`noscope` rather than `global`, for example, or `heap`. But now 
I'm realizing that when a reference parameter (i.e. `t` above) 
escapes either by return or by mutable parameter, the escape must 
*always* be considered to have the same scope as the calling 
parameter. The `new T*` in `fun()` may be a heap variable, but it 
points to a stack variable in `gun()` just the same and thus must 
be treated by `gun()` as such.

Nevertheless, as I think further, I realize that there's nothing 
wrong with passing a heap variable *to* a `noscope` parameter, 
because it's not unsafe for the static data segment to point to 
the heap, as they are coordinated by the garbage collector.

Therefore, the reason to use `noscope` would be to indicate that 
anything which has not been allocated on the stack may be 
*passed* to the function, while calling it `static` would merely 
indicate where the parameter might be copied *to* once inside the 
function. As far as adding a new keyword, I think it depends on 
the keyword. `noscope` isn't so bad because it fits into the 
`throw/nothrow` pattern already. I think the most important 
question is whether anyone is normally tempted to use the keyword 
as a variable name. I consider the `body` keyword, for example, 
regrettable. But do you think anyone will shed a tear for 
`noscope`? I'm not worried about it.

> How does this proposal interact with `scope`? It seems you want 
> the compiler to track lifetimes for all reference parameters, 
> even those not marked as `scope`. At least your example doesn't 
> use `scope`.

You're right. In my head there is a scheme for doing this. I'll 
present it in due time.

> Apart from that, I'll have to think about a few things. For 
> example, I don't know yet whether and how a safe owning type/RC 
> can be implemented with this.

I don't either. I am pretty sure, however, that this will not 
harm the effort. All these attributes do is give the compiler 
more information to work with. In the back of my mind, I'm always 
thinking @systems programmers can always @trust whatever doesn't 
work for them, although I still can't think of any use cases for 
violating these principles.


More information about the Digitalmars-d mailing list