Skip to content

Support restriction of access to this object #757

Open
@eernstg

Description

@eernstg

This issue is a proposal that we add support for marking instance members as this protected (alternatively: protected) to indicate that they can only be accessed on the current object (as in this.myMember or, if this is added implicitly: myMember).

Given that we may well add support for sound variance (starting with declaration site variance), the ability to constrain access to instance members to the enclosing object only gains new urgency.

A typical example would be that an immutable data structure naturally lends itself to sound covariance. However, an implementation may well wish to cache some values for performance reasons, and that cannot be done in a type safe manner with the sound discipline that is applied to member signatures where a soundly covariant type variable is used. Similarly, an implementation may well benefit from the ability to express sub-computations as instance methods, and they cannot accept arguments whose type is a soundly covariant type variable.

For example:

class Link<out X extends num> {
  final X x;
  final Link<X>? next;
  Link(this.x, this.next);
  X? _max; // Error!
  X get max {
    X? result = _max;
    if (result != null) return result;
    result = next?.max;
    return result != null
        ? (_max = result >= x ? result : x)
        : (_max = x);
  }
}

The example above would give rise to a compile-time error at the comment, because the mutable instance variable _max induces a setter whose parameter type is X?, which is not allowed when X is out. In general, this kind of restriction is required in order to maintain the soundness properties that are the whole point of having explicit variance control in the first place.

However, there is no soundness issue for code in a scope where the type variable X is in scope, which means that there is no soundness issue in having an instance variable like _max as long as it is only accessed on this. (It is not sufficient that the receiver is some other object of type Link<X>, because that other object could, by covariance, have an actual value for X which is different from the one of the current object).

We could use the keyword sequence this protected in order to express the property that a given instance member can only be accessed on this. We could also use a plain protected, if we don't insist on reserving that keyword for the standard meaning (where it is allowed to access the feature on any object with the enclosing type, not just this). We could then make the example work as follows:

class Link<out X extends num> {
  final X x;
  final Link<X>? next;
  Link(this.x, this.next);
  this protected X? _max;
  X get max {
    X? result = _max;
    if (result != null) return result;
    result = next?.max;
    return result != null
        ? (_max = result >= x ? result : x)
        : (_max = x);
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureProposed language feature that solves one or more problems

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions