Difference between revisions of "User:Schuetzm/scope2"

From D Wiki
Jump to: navigation, search
(RCArray)
Line 6: Line 6:
 
It usually refers to a local variable or parameter; additionally, an infinite scope is defined that corresponds to global/static variables or GC managed memory.
 
It usually refers to a local variable or parameter; additionally, an infinite scope is defined that corresponds to global/static variables or GC managed memory.
 
Scopes and lifetimes are defined purely based on lexical scope and order of declaration of their corresponding variables. Therefore, for any two lifetimes, one is either completely contained in the other, or they are disjoint.
 
Scopes and lifetimes are defined purely based on lexical scope and order of declaration of their corresponding variables. Therefore, for any two lifetimes, one is either completely contained in the other, or they are disjoint.
By annotating a variable with <code>scope</code>, it's scope is defined to be equal to the variables lifetime, instead of the default (infinity).
+
By annotating a variable with <code>scope</code>, it's scope is defined to be equal to the variable's lifetime, instead of the default (infinity).
  
 
For any expression involving at least one scope value, two lifetimes (''LHS lifetime'' and ''RHS lifetime'') are computed in a way that ensures that the resulting RHS lifetime will not be greater than that of any of the expression's parts, and the LHS lifetime will not be smaller.
 
For any expression involving at least one scope value, two lifetimes (''LHS lifetime'' and ''RHS lifetime'') are computed in a way that ensures that the resulting RHS lifetime will not be greater than that of any of the expression's parts, and the LHS lifetime will not be smaller.
 
The exact rules will be defined in one of the following sections.
 
The exact rules will be defined in one of the following sections.
An assignment (i.e., <code>=</code> operator, passing to a function, returning from a function, capturing in a closure, throwing, etc.) involving scope values is only permissible, if the destination's LHS lifetime is fully contained in the source's RHS lifetime.
+
An ''assignment'' (i.e., <code>=</code> operator, passing to a function, returning from a function, capturing in a closure, throwing, etc.) involving scope values is only permissible, if the destination's LHS lifetime is fully contained in the source's RHS lifetime.
 
Throwing is considered assignment to a variable with static lifetime.
 
Throwing is considered assignment to a variable with static lifetime.
  
The following invariant is enforced to always be true on every assignment: A location with scope ''a'' will never contain references pointing to values with a lifetime shorter than ''a''.
+
The following invariant is enforced to always be true on every ''assignment'': A location with scope ''a'' will never contain references pointing to values with a lifetime shorter than ''a''.
  
 
To allow a function to return a value it received as a parameter, the parameter can be annotated with the <code>return</code> keyword,
 
To allow a function to return a value it received as a parameter, the parameter can be annotated with the <code>return</code> keyword,
 
as in [[DIP25]].
 
as in [[DIP25]].
 
It's also possible to express that a parameter escapes through another parameter (including <code>this</code>) by using the <code>return!identifier</code> syntax.
 
It's also possible to express that a parameter escapes through another parameter (including <code>this</code>) by using the <code>return!identifier</code> syntax.
Multiple such annotations can appear for each parameter; parameters referring to each other in a circular manner are disallowed.
+
Multiple such annotations can appear for each parameter.
 
When a function is called, the compiler checks (for each argument and the return value) that only expressions with a lifetime longer than those of all the corresponding <code>return</code> annotations are passed in, and that the return value is used in a conforming way.
 
When a function is called, the compiler checks (for each argument and the return value) that only expressions with a lifetime longer than those of all the corresponding <code>return</code> annotations are passed in, and that the return value is used in a conforming way.
  
Line 24: Line 24:
 
are necessary; the compiler can figure them out by itself.
 
are necessary; the compiler can figure them out by itself.
 
Additionally, inference of annotations is done in the usual situations, i.e. nested functions and templates.
 
Additionally, inference of annotations is done in the usual situations, i.e. nested functions and templates.
In a subsequent section, an algorithm is presented that can be used for inference of associated lifetimes of local variables as well as annotations of parameters.
+
In a subsequent section, an algorithm is presented that can be used for inference of scopes of local variables as well as annotations of parameters.
  
 
In parameters of <code>@safe</code> functions, all reference types (class references, pointers, slices, <code>ref</code> parameters) or aggregates containing references are implicitly treated as <code>scope</code> unless the parameter is annotated with the keyword <code>static</code>. This does however not apply to the return value.
 
In parameters of <code>@safe</code> functions, all reference types (class references, pointers, slices, <code>ref</code> parameters) or aggregates containing references are implicitly treated as <code>scope</code> unless the parameter is annotated with the keyword <code>static</code>. This does however not apply to the return value.
Line 30: Line 30:
 
<code>ref</code> and <code>out</code> parameters can also be treated as implicitly scoped, but this has the potential to break lots of code and needs to be considered carefully.
 
<code>ref</code> and <code>out</code> parameters can also be treated as implicitly scoped, but this has the potential to break lots of code and needs to be considered carefully.
  
A <code>scope</code> annotation on a member variable shall be equivalent to a corresponding property returning a reference to that member.
+
A <code>scope</code> annotation on a member variable shall be equivalent to a <code>@property</code> function returning a reference to that member, scoped to <code>this</code>.
  
 
== Examples ==
 
== Examples ==

Revision as of 20:15, 4 March 2015

Overview

scope is a storage class. It applies to function parameters (including this), local variables, the return value (treated as if it were an out parameter), and member variables of aggregates. It participates in overloading.

With every variable, a particular lifetime (called scope) is associated. It usually refers to a local variable or parameter; additionally, an infinite scope is defined that corresponds to global/static variables or GC managed memory. Scopes and lifetimes are defined purely based on lexical scope and order of declaration of their corresponding variables. Therefore, for any two lifetimes, one is either completely contained in the other, or they are disjoint. By annotating a variable with scope, it's scope is defined to be equal to the variable's lifetime, instead of the default (infinity).

For any expression involving at least one scope value, two lifetimes (LHS lifetime and RHS lifetime) are computed in a way that ensures that the resulting RHS lifetime will not be greater than that of any of the expression's parts, and the LHS lifetime will not be smaller. The exact rules will be defined in one of the following sections. An assignment (i.e., = operator, passing to a function, returning from a function, capturing in a closure, throwing, etc.) involving scope values is only permissible, if the destination's LHS lifetime is fully contained in the source's RHS lifetime. Throwing is considered assignment to a variable with static lifetime.

The following invariant is enforced to always be true on every assignment: A location with scope a will never contain references pointing to values with a lifetime shorter than a.

To allow a function to return a value it received as a parameter, the parameter can be annotated with the return keyword, as in DIP25. It's also possible to express that a parameter escapes through another parameter (including this) by using the return!identifier syntax. Multiple such annotations can appear for each parameter. When a function is called, the compiler checks (for each argument and the return value) that only expressions with a lifetime longer than those of all the corresponding return annotations are passed in, and that the return value is used in a conforming way.

Because all relevant information about lifetimes is contained in the function signature, no explicit scope annotations for local variables are necessary; the compiler can figure them out by itself. Additionally, inference of annotations is done in the usual situations, i.e. nested functions and templates. In a subsequent section, an algorithm is presented that can be used for inference of scopes of local variables as well as annotations of parameters.

In parameters of @safe functions, all reference types (class references, pointers, slices, ref parameters) or aggregates containing references are implicitly treated as scope unless the parameter is annotated with the keyword static. This does however not apply to the return value.

ref and out parameters can also be treated as implicitly scoped, but this has the potential to break lots of code and needs to be considered carefully.

A scope annotation on a member variable shall be equivalent to a @property function returning a reference to that member, scoped to this.

Examples

RCArray

Walter's RCArray, adjusted to this proposal:

@safe:

struct RCArray(E) {
    this(E[] a)
    {
        array = a.dup;
        count = new int;
        *count = 1;
    }

    ~this() @trusted
    {
        if (count && --*count == 0)
        {
            // either `delete` in `@system` code will accept `scope`:
            delete array;
            // or a helper needs to be used to remove `scope`:
            delete assumeStatic(array);
        }
    }

    this(this)
    {
        if (count)
            ++*count;
    }

    @property size_t length()
    {
        return array.length;
    }

    ref E opIndex(size_t i)
    {
        return array[i];
    }

    E[] opSlice(size_t lwr, size_t upr)
    {
        return array[lwr .. upr];
    }

    E[] opSlice()
    {
        return array[];
    }

private:
    scope E[] array;    // this is the only explicit annotation
    int* count;
}