dart-lang / dart-lang/language

API variables

Open
#4,137 8 comments 2 reactions 0 assignees View on GitHub
request
Dominant language
TeX
Stars
2.9k
Forks
239
Avg merge
2d 18h
Merged PRs (30d)
14

Description

The [stable getters](https://github.com/dart-lang/language/issues/1518) proposal aims to make immutable properties of objects an API matter. That is, we can declare that a particular member of an interface type (class, mixin, etc) will return the same value every time it returns a value. It is a compile-time error if this property is not statically known to hold, and (when the getter is an instance member) it is a compile-time error to override or implement it in a way that violates this constraint.

The fact that a given property of an object is immutable can be important when reasoning about the correctness of a piece of code; for example, the value of any such property can safely be cached and reused, which might not be correct for a getter which isn't stable.

This issue is intended to promote the idea that "being a plain variable", in particular a variable that supports mutation, could also be an API property. The point is that it could be important for correctness and code comprehension to know this when reading code where the variable is used.

---

The specification of an **_API variable_** is that its getter/setter invocation history faithfully determines the behavior of the getter:

Assume that `x` is an API variable whose value at a given time _t_ is _v0_. Assume that the getter/setter invocations that occurred at time _t_ or higher is _i1 .. ik_, where _ij_ is either a getter invocation _get:u_ that returned the value `u`, or a setter invocation _set:w_ where the value `w` was assigned to `x`. We do not include throwing invocations in the list _i1 .. ik_, only invocations that completed normally are included.

The value `u` of a getter invocation _ij_ of the form _get:u_ is then the value `w` which was stored in the most recent setter invocation _ik_ for some _k < j_ of the form _set:w_, or the initial value _v0_ in the case where no such setter invocation exists.

---

In other words, the API variable will return the value which was assigned to it most recently, and it isn't playing around in any way.

It is allowed for the API variable to be implemented in terms of a getter and a setter that may have other side effects. It is a matter of good style to keep those side effects non-observable in a suitable sense. The simplest way to obtain an API variable is to declare a regular non-local variable (a top-level variable, a static variable, or an instance variable).

But it is not allowed for the API variable to obtain a new value for any other reason than having had a setter invocation as described above. In particular, it can't be a getter/setter pair with a backing variable whose value is sometimes changed by other means than calling said setter, and it can't be a getter/setter pair whose setter at times doesn't set the backing variable at all, or sets it with another value than the actual argument of the setter invocation.

It _can_ be a setter/getter pair where the getter is stable and the setter always throws. In general, being an API variable doesn't prevent invocations (of the getter or setter) that throw. It just specifies that _when the invocation doesn't throw_, the value follows this "return the most recently stored value" semantics. Also, it's not allowed for a setter to change the value and then throw, it must leave the value unchanged in the case where it throws.

---

A very simple language mechanism that supports API variables as instance members would be (1) a way to mark an instance variable declaration _D_ as an API variable, (2) a compile-time error for every override of the getter or setter of _D_ that isn't an API variable declaration.

```dart
// As a strawman, `API` is a modifier that declares an API variable.
// It can only be specified on a variable declaration, and it must be non-final.

class A {
API int i;
A(this.i);
}

class B1 implements A {
API int i;
B1(this.i);
}

class B2 implements A {
int get i => 42; // Error, this is not the getter of an API variable.
set i(int _) {} // Error, this is not the setter of an API variable.
}
```

Contributor guide

Open the contributing guide

Research direction

Read this issue and the linked stable getters proposal first. The payload names no implementation files or tests; progress would mean resolving the language-design questions and defining the API-variable specification and modifier semantics.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.