mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
I don't know why my machine at home is suddenly being stricter than the one at work, but it found these legitimate formatting mistakes. Swift SVN r13635
1162 lines
50 KiB
ReStructuredText
1162 lines
50 KiB
ReStructuredText
:orphan:
|
|
|
|
=================
|
|
Weak References
|
|
=================
|
|
|
|
:Author: John McCall
|
|
:Date: 2013-05-23
|
|
|
|
**Abstract:** This paper discusses the general concept of weak
|
|
references, including various designs in other languages, and proposes
|
|
several new core language features and a more sophisticated runtime
|
|
support feature which can be exploited in the standard library.
|
|
|
|
Reference Graphs
|
|
================
|
|
|
|
Let's run through some basic terminology.
|
|
|
|
Program memory may be seen abstractly as a (not necessarily connected)
|
|
directed graph where the nodes are objects (treating transient
|
|
allocations like local scopes as objects) and the edges are
|
|
references. (Multi-edges and self-edges are permitted, of course.)
|
|
|
|
We may assign a level of strength to each of these edges. We will
|
|
call the highest level *strong*; all others are some flavor of *weak*.
|
|
|
|
Every object has a *strength of reference* which arises from the
|
|
reference graph. This can be any level of strength or the special
|
|
value *unreferenced*. The strength of a path is the minimum strength
|
|
of any edge in the path. The strength of a set of paths is the
|
|
maximum strength of all the paths, unless the set is empty, in which
|
|
case it is *unreferenced*.
|
|
|
|
In general, the implementation is only outright forbidden to
|
|
deallocate an object if it is strongly referenced. However,
|
|
being somehow weakly referenced may trigger some sort of additional
|
|
guarantee; see the Language Precedents section.
|
|
|
|
In a cycle-collecting environment, certain nodes are given special
|
|
treatment as *roots*; these nodes are always strongly referenced.
|
|
Otherwise, the strength of reference for an object is the strength
|
|
of all paths from any root to the object.
|
|
|
|
In a non-cycle-collecting environment, the strength of reference for
|
|
an object is the strength of all the direct references to that
|
|
object, taken as length=1 paths. Note that this environmental
|
|
consideration becomes a language guarantee: even if the implementation
|
|
can trivially prove that an object is referenced only by itself, it
|
|
is still not permitted to deallocate the object.
|
|
|
|
It is common for certain kinds of reference to not receive a full
|
|
guarantee. For example, a strong reference from a local variable
|
|
may lose effectiveness as soon as the variable is no longer needed
|
|
(but before it formally leaves scope). This is pervasive in GC
|
|
environments but also true in e.g. ObjC ARC.
|
|
|
|
In some programs, especially event-driven programs like UIs or
|
|
servers, it can be useful to consider the *static* reference graph as
|
|
captured during a notional steady state. Local scopes may form many
|
|
references to objects in the static graph, but unless the scope
|
|
persists indefinitely or a major restructuring is triggered, these
|
|
references are likely to have no effect on the reference graph, and so
|
|
their strength of reference has no semantic importance. Understanding
|
|
this helps to explain why many environments provide no direct way to
|
|
form a local weak reference.
|
|
|
|
Language and Library Precedents
|
|
===============================
|
|
|
|
We're only going to discuss *managed* precedents here.
|
|
|
|
It is possible to create a kind of weak reference by just not
|
|
providing any special behavior to an object reference; if the
|
|
object is deallocated, the reference will dangle and uses of it
|
|
will likely crash or cause corruption. This could happen by
|
|
e.g. declining to insert reference-count manipulations for a
|
|
particular variable (in an ARC-like environment) or not mapping
|
|
a variable's frame offset as a pointer in a type map (in a
|
|
precise-GC environment). We will call this *dangling weak*.
|
|
|
|
Objective-C
|
|
-----------
|
|
|
|
All modes of Objective-C automate memory management for
|
|
synthesized properties. In GC and ARC, accessors just
|
|
use the normal semantics for the underlying ivar (plus
|
|
copy/atomic guarantees, of course). In MRC, accessors
|
|
use dangling weak semantics unless they're :code:`retain`
|
|
or :code:`copy`, in which case they maintain a +1 refcount
|
|
invariant on the referent.
|
|
|
|
In GC and ARC, variables qualified with :code:`__weak` are
|
|
immediately zeroed out when the referenced object begins
|
|
deallocation. There is no syntactic difference on use;
|
|
it's just possible that the value read will be :code:`nil`
|
|
instead of whatever was last written there, possibly causing
|
|
the loading code to crash (e.g. on an ivar access) or silently
|
|
do nothing (e.g. on a message send). There is an opt-in
|
|
warning in ARC for certain uses of values loaded from
|
|
:code:`__weak` ivars.
|
|
|
|
In GC, it is also possible to construct a dangling
|
|
weak reference by storing an object pointer into (1) unscanned
|
|
heap memory or (2) an instance variable that's not of
|
|
object-pointer type and isn't qualified with :code:`__strong`
|
|
or :code:`__weak`. Otherwise, object references are strong
|
|
(including all references from local scopes).
|
|
|
|
In ARC, it is possible to construct a dangling weak reference
|
|
by using the :code:`__unsafe_unretained` qualifier or by
|
|
bridging a pointer value to a C pointer type.
|
|
|
|
C++
|
|
---
|
|
|
|
C++ smart pointers (e.g. :code:`std::unique_ptr`) typically
|
|
permit the creation of a dangling-weak reference by
|
|
providing an accessor to get the pointer as a normal C
|
|
pointer. (Even if they didn't have :code:`get()`, you could
|
|
manually call :code:`operator->` to get the same effect.)
|
|
|
|
C++'s :code:`std::shared_ptr` permits the formation of
|
|
weak pointers (:code:`std::weak_ptr`) from shared pointers.
|
|
It is not possibly to directly use a weak pointer; it must
|
|
first be converted back to a :code:`shared_ptr`, either by
|
|
using the :code:`lock()` operation (which produces a null
|
|
pointer if the referent has been deallocated) or by directly
|
|
constructing a :code:`shared_ptr` with the :code:`weak_ptr`
|
|
(which throws an exception if the referent has been deallocated).
|
|
There is also a way to explicitly query whether a
|
|
:code:`weak_ptr` is still valid, which may be more efficient
|
|
than checking the result of the cast.
|
|
|
|
Java
|
|
----
|
|
|
|
Java does not provide any facility for dangling weak references.
|
|
The standard library does provide three levels of weak reference
|
|
(in :code:`java.lang.ref`). References cannot be re-seated
|
|
(although they can be explicitly cleared), and users must call
|
|
:code:`get()` in order to access the value, which may yield
|
|
:code:`null`.
|
|
|
|
There is a great deal of interesting discussion of these
|
|
reference classes `here <http://www.kdgregory.com/index.php?page=java.refobj>`_.
|
|
|
|
Java :code:`Reference` objects may be constructed with an
|
|
optional :code:`ReferenceQueue`; if so, then when the
|
|
object's reachability changes, the reference object will be
|
|
added to that queue. This permits data structures to clean
|
|
up after cleared soft references without needing to either
|
|
periodically scan the entire structure or be fully lazy.
|
|
Additional data may be added to the reference object by
|
|
subclassing it.
|
|
|
|
The references are presented in order of decreasing strength.
|
|
|
|
:code:`SoftReference` is a sort of quasi-strong reference
|
|
which holds onto the object until the VM begins to run out
|
|
of memory. Soft references to softly-referenced objects are
|
|
guaranteed to have been cleared before the VM can throw an
|
|
:code:`OutOfMemoryError`. The reference will be cleared
|
|
before it is added to its reference queue (and so the
|
|
reference queue cannot resurrect the object). The intent
|
|
of soft references is to enable memory-sensitive caches,
|
|
but in practice a memory-sensitive cache would probably
|
|
want to implement a more subtle replacement strategy than
|
|
"drop things at random as soon as memory runs low". A
|
|
more interesting use is a memory-guided circuit-breaker:
|
|
when building up a very large structure, hold it in a
|
|
soft reference, and if that references goes null during
|
|
construction, just bail out. But that's a pretty tricky
|
|
use-case to get right.
|
|
|
|
:code:`WeakReference` is intended for use in non-memory-sensitive
|
|
weak caches, like a uniquing cache; it persists only as long
|
|
as the referent is more strongly referenced. The reference
|
|
will be cleared before it is added to its reference queue (and
|
|
so the reference queue cannot resurrect the object).
|
|
|
|
:code:`PhantomReference` provides a way to attach extra
|
|
finalization to an object without actually using finalizers
|
|
(which have several problems, including the ability to
|
|
resurrect the object). The phantom reference *always*
|
|
presents :code:`null` as its value and is therefore itself
|
|
useless as a reference. Phantom references are enqueued
|
|
after the object is finalized and therefore at a point when
|
|
there can be no references to the object within the VM
|
|
at all. However, the object itself cannot be deallocated
|
|
until the phantom references are all cleared or themselves
|
|
deallocated, which I believe is for the convenience of native
|
|
code that may hold a dangling weak reference to the referent
|
|
(or which may be able to directly read the reference).
|
|
|
|
.NET
|
|
----
|
|
|
|
The :code:`WeakReference` class in .NET is similar to
|
|
Java's :code:`WeakReference` class in that the value
|
|
cannot be accessed directly; it must be accessed
|
|
via the :code:`Target` property, which may yield
|
|
:code:`null`. The reference may be reseated to a
|
|
different value.
|
|
|
|
Weak references may be created *long*, which permits the
|
|
target object to be finalized but not actually deallocated.
|
|
|
|
Python
|
|
------
|
|
|
|
A :code:`weakref` acts like a function object; it is created
|
|
with a particular value, which cannot be reseated. The
|
|
function will yield :code:`None` if the referent is collected.
|
|
|
|
There is library functionality to automatically proxy a value
|
|
as a weak reference. An exception is thrown if an operation
|
|
is performed on the proxy but the referent has been collected.
|
|
|
|
A :code:`weakref` may be constructed with a callback function.
|
|
The callback will be called after the weak reference is cleared;
|
|
it is, however, passed the weak ref object itself.
|
|
|
|
Ruby
|
|
----
|
|
|
|
A :code:`WeakRef` is automatically a proxy for an object.
|
|
There is a :code:`weakref_alive` method to query whether the
|
|
reference is still alive; another other operation will cause
|
|
an exception to be thrown.
|
|
|
|
Rust
|
|
----
|
|
|
|
As far as I can tell, there is nothing like a weak reference
|
|
in Rust at the moment.
|
|
|
|
A *managed pointer* (:code:`@int`) is a strong reference
|
|
subject to GC.
|
|
|
|
An *owning pointer* (:code:`~int`) is a strong reference
|
|
that cannot be cloned (copying the pointer actually copies the
|
|
underlying data).
|
|
|
|
A *borrowed pointer* (:code:`&int`) is essentially a dangling
|
|
weak reference that is subject to static restrictions which
|
|
ensure that it doesn't actually dangle. It is thus primarily
|
|
a performance optimization.
|
|
|
|
A *raw pointer* (:code:`*int`) is a dangling weak reference.
|
|
|
|
Haskell
|
|
-------
|
|
|
|
Yes, of course Haskell has weak references.
|
|
|
|
A :code:`Weak t` is an association between a hidden key
|
|
and a visible value of type :code:`t`.
|
|
:code:`doRefWeak theRef` is an :code:`IO (Maybe t)`.
|
|
|
|
A weak reference may be constructed with an optional
|
|
:code:`IO ()` which will be run when the referent is
|
|
collected. This finalizer may (somehow) refer to the key
|
|
and value without itself keeping them alive; it is also
|
|
explicitly permitted to resurrect them.
|
|
|
|
|
|
Use Cases
|
|
=========
|
|
|
|
There are many problems that are potentially addressable with
|
|
functionality like weak references. It is not at all obvious
|
|
that they should be addressed with the same language feature.
|
|
|
|
Back references
|
|
---------------
|
|
|
|
Given that Swift is not cycle-collecting, far and away the most
|
|
important use case in the static reference graph is that of the
|
|
*back-reference*: a reference *R* to an object which holds a strong
|
|
reference (possibly indirectly) to the object holding *R*. Examples
|
|
include:
|
|
|
|
- A 'previousNode' pointer in a doubly-linked list.
|
|
|
|
- A 'parent' pointer in a render tree.
|
|
|
|
- An edge in a general graph structure.
|
|
|
|
These have several properties in common:
|
|
|
|
- Using strong references would require a lot of explicit
|
|
code to tear down the reference cycles.
|
|
|
|
- These references may be accessed very frequently, so
|
|
performance is important.
|
|
|
|
- It is not always feasible to make these references valid
|
|
immediately on construction.
|
|
|
|
- Traversing a reference after the referent is deallocated is likely a
|
|
sign that something has been kept alive longer than it was meant to
|
|
be. However, programmers may reasonably differ about the correct
|
|
response to this: crashing, and therefore encouraging the programmer
|
|
to track down a root cause, or simply writing the operation to
|
|
handle both cases correctly. Ultimately, this choice comes down to
|
|
philosophy.
|
|
|
|
Caches
|
|
------
|
|
|
|
Weak caches are used in order to prevent a cache from taking
|
|
over all available memory. By being tied to the reachability
|
|
of a value, the cache prevents entries from spuriously
|
|
expiring when their values are still in active use; but by
|
|
using weak references, the cache permits the system to
|
|
deallocate values that are no longer in use.
|
|
|
|
Generally, a data structure using weak references extensively
|
|
also needs some way to receive notification that the weak
|
|
reference was collected. This is because entries in the data
|
|
structure are likely to have significant overhead even if the
|
|
value is collected. A weak data structure which receives no
|
|
notification that a reference has been invalidated must either
|
|
allow these entries to accumulate indefinitely or must
|
|
periodically scan the entire structure looking for stale entries.
|
|
|
|
A weak reference which permits immediate deallocation of its
|
|
referent when the last strong reference is dropped is
|
|
substantially less useful for the implementation of a weak
|
|
cache. It is a common access pattern (for, say, a memoizing
|
|
cache) for a value to be looked up many times in rapid
|
|
succession, but for each use to be temporarlly disjoint
|
|
from the others. A naive use of weak references in this case
|
|
will simply cause the cache to thrash. This problem is less
|
|
likely to arise in an environment with nondeterministic
|
|
collection because the entry is likely to service multiple
|
|
lookups between collections.
|
|
|
|
It is likely that users implementing weak data structures
|
|
would prefer a highly flexible infrastructure centered around
|
|
resurrection and notifications of reaching a zero refcount
|
|
than a more rigid system built directly into the language.
|
|
Since the Swift model is built around statically-inserted
|
|
operations rather than a memory scanner, this is much more
|
|
workable.
|
|
|
|
External Finalization
|
|
---------------------
|
|
|
|
Finalization models built around calling a method on the
|
|
finalized object (such as Objective-C's :code:`-dealloc`)
|
|
suffer from a number of limitations and problems:
|
|
|
|
- Since the method receives a pointer to the object being
|
|
deallocated, the implementation must guard against
|
|
attempts to resurrect the object. This may complicate
|
|
and/or slow down the system's basic reference-management
|
|
logic, which tends to be quite important for performance.
|
|
|
|
- Since the method receives a pointer to the object being
|
|
deallocated, the implementation must leave the object at
|
|
least a minimally valid state until the user code is
|
|
complete. For example, the instance variables of a
|
|
subclass cannot be destroyed until a later phase of
|
|
destruction, because a superclass finalizer might invoke
|
|
subclass behavior. (This assumes that the dynamic type
|
|
of the object does not change during destruction, which
|
|
is an alternative that brings its own problems.)
|
|
|
|
- Finalization code must be inherent to the object; other
|
|
objects cannot request that code be run when the object
|
|
is deallocated. For example, an object that registers
|
|
itself to observe a certain event source must explicitly
|
|
deregister itself in a finalizer; the event source cannot
|
|
simply automatically drop the object when it is
|
|
deallocated.
|
|
|
|
Optimization
|
|
------------
|
|
|
|
Functions often create a large number of temporary references. In a
|
|
reference-counting environment like Swift, these references require
|
|
the implementation to implicitly perform operations to incremenet and
|
|
decrement the reference count. These operations can be quite fast,
|
|
but they are not free, and our experience has been that the
|
|
accumulated cost can be quite significant. A straightforward local
|
|
static analysis can eliminate many operations, but many others will be
|
|
blocked by abstraction barriers, chiefly dynamically-dispatched calls.
|
|
Therefore, if Swift is to allow precise performance control, it is
|
|
important to be able to allow motivated users to selectively control
|
|
the emission of reference-counting operations.
|
|
|
|
This sort of control necessarily permits the creation of dangling weak
|
|
references and so is not safe.
|
|
|
|
Proposal Overview
|
|
=================
|
|
|
|
Looking at these use-cases, there are two main thrusts:
|
|
|
|
- There is a general need to set up back references to objects.
|
|
These references must be designed for convenient use by non-expert
|
|
users.
|
|
|
|
- There are a number of more sophisticated use cases which require
|
|
notification or interruption of deallocation; these can be used in
|
|
the implementation of higher-level abstractions like weak caches.
|
|
Here it is reasonable to expect more user expertise, such that
|
|
power and flexibility should take priority over ease of use.
|
|
|
|
The second set of use cases should addressed by library types working
|
|
on top of basic runtime support.
|
|
|
|
The first set of use cases will require more direct language support.
|
|
To that end, I propose adding two new variable attributes,
|
|
:code:`[weak]` and :code:`[unowned]`. I also propose a small slate of
|
|
new features which directly address the problem of capturing a value
|
|
in a closure with a different strength of reference than it had in the
|
|
enclosing context.
|
|
|
|
Proposed Variable Attributes
|
|
============================
|
|
|
|
In the following discussion, a "variable-like" declaration is any
|
|
declaration which binds a name to a (possibly mutable) value of
|
|
arbitrary type. Currently this is just :code:`var`, but this proposal
|
|
also adds :code:`capture`, and we may later add more variants, such as
|
|
:code:`const` or :code:`val` or the like.
|
|
|
|
:code:`[weak]`
|
|
--------------
|
|
|
|
:code:`weak` is an attribute which may be applied to any
|
|
variable-like declaration of reference type :code:`T`. For
|
|
type-system purposes, the variables behaves like a normal
|
|
variable of type :code:`Optional<T>`, except:
|
|
|
|
- it does not maintain a +1 reference count invariant and
|
|
|
|
- loading from the variable after the current referent (if present)
|
|
has started destruction will result in a :code:`Nothing` value,
|
|
indistinguishable from the normal case.
|
|
|
|
The semantics are quite similar to weak references in other
|
|
environments (particularly Objective-C) except that the change in
|
|
formal type forces the user of the value to check its validity before
|
|
using it.
|
|
|
|
It doesn't really matter how the compiler would find the type
|
|
:code:`Optional<T>`; compiler-plus-stdlib magic, most likely. I do
|
|
not think the type should be :code:`Weak<T>` because that would
|
|
effectively make this a type attribute and thus make it too easy to
|
|
accidentally preserve the value as a weak reference. See the section
|
|
discussing type attributes vs. declaration attributes.
|
|
|
|
Giving the variable a consistent type of :code:`Optional<T>` permits
|
|
the user to assign :code:`Nothing` into it and therefore removes the
|
|
somewhat odd expressive possibility of a reference that can only be
|
|
missing if the object has been deallocated. I think this is an
|
|
acceptable cost of making a cleaner feature.
|
|
|
|
One alternative to using :code:`Optional<T>` would be to simply treat
|
|
the load as a potentially-failing operation, subject to the (not yet
|
|
precisely designed) language rules for error handling. This would
|
|
require the runtime to potentially synthesize an error event, which
|
|
could then propagate all the way to the end-user if the programmer
|
|
accidentally failed to check the result in a context that permitted
|
|
error propagation outwards. That's bad.
|
|
|
|
A slightly different alternative would be to treat it as a form of
|
|
error orthogonal to the standard user-error propagation. This would
|
|
be cleaner than changing the type of the variable but can't really be
|
|
designed without first having a solid error-handling design.
|
|
|
|
|
|
:code:`[unowned]`
|
|
-----------------
|
|
|
|
:code:`unowned` is an attribute which may be applied to any
|
|
"variable-like" declaration of reference type :code:`T`. For
|
|
type-system purposes, the variable behaves exactly like a normal
|
|
variable of type :code:`T`, except:
|
|
|
|
- it does not maintain a +1 reference count invariant and
|
|
|
|
- loading from the variable after the referent has started
|
|
destruction causes an assertion failure.
|
|
|
|
This is a refinement of :code:`weak` focused more narrowly on the case
|
|
of a back reference with relatively tight validity invariants. This
|
|
is also the case that's potentially optimizable to use dangling weak
|
|
references; see below.
|
|
|
|
This name isn't really optimal. We've considered several different
|
|
candidates:
|
|
|
|
- :code:`weak` is a poor choice because our semantics are very
|
|
different from weak references in other environments where it's
|
|
valid to access a cleared reference. Plus, we need to expose
|
|
those semantics, so the name is claimed.
|
|
|
|
- :code:`backref` is strongly evocative of the major use case in the
|
|
static reference graph; this would encourage users to use it for
|
|
back references and to consider alternatives for other cases, both
|
|
of which I like. The latter also makes the husk-leaking
|
|
implementation (see below) more palatable. It also contrasts very
|
|
well with :code:`weak`. However, its evocativeness makes it
|
|
unwieldy to use for local reference-counting optimizations.
|
|
|
|
- :code:`dangling` is more general than :code:`backref`, but it has
|
|
such strong negative associations that it wouldn't be unreasonable
|
|
for users to assume that it's unsafe (with all the pursuant
|
|
debugging difficulties) based on the name alone. I don't think
|
|
we want to discourage a feature that can help users build tighter
|
|
invariants on their classes.
|
|
|
|
- :code:`unowned` is somewhat cleaner-looking, and it isn't as tied
|
|
to a specific use case, but it does not contrast with :code:`weak`
|
|
*at all*; only someone with considerable exposure to weak
|
|
references would understand why we named each one the way we did,
|
|
and even they are likely to roll their eyes at us. But it's okay
|
|
for a working proposal.
|
|
|
|
Asserting and Uncheckable
|
|
.........................
|
|
|
|
There should not be a way to check whether a :code:`unowned`
|
|
reference is still valid.
|
|
|
|
- An invalid back-reference is a consistency error that
|
|
we should encourage programmers to fix rather than work
|
|
around by spot-testing for validity.
|
|
|
|
- Contrariwise, a weak reference that might reasonably be
|
|
invalidated during active use should be checked for validity
|
|
at *every* use. We can provide a simple library facility
|
|
for this pattern.
|
|
|
|
- Permitting implicit operations like loads to fail in a
|
|
recoverable way may end up complicating the language model
|
|
for error-handling.
|
|
|
|
- By disallowing recovery, we create a model where the only
|
|
need to actually register the weak reference with the system
|
|
is to enable a consistency check. Users who are confident
|
|
in the correctness of their program may therefore simply
|
|
disable the consistency check without affecting the semantics
|
|
of the program. In this case, that leaves the variable a
|
|
simple dangling-weak reference.
|
|
|
|
Implementation
|
|
..............
|
|
|
|
The standard implementation for a weak reference requires the
|
|
address of the reference to be registered with the system so
|
|
that it can be cleared when the referent is finalized. This
|
|
has two problems:
|
|
|
|
- It forces the runtime to maintain a side-table mapping
|
|
objects to the list of weak references; generally this
|
|
adds an allocation per weakly-referenced object.
|
|
|
|
- It forces the representation of weak references to either
|
|
be non-address-invariant or to introduce an extra level of
|
|
indirection.
|
|
|
|
For some use cases, this may be warranted; for example, in
|
|
a weak cache it might come out in the noise. But for a simple
|
|
back-reference, these are substantial penalties.
|
|
|
|
Dave Z. has proposed instead using a weak refcount, analogous to a
|
|
strong refcount. Ownership of a weak retain can be easily transferred
|
|
between locations, and it does not require a side-table of an object's
|
|
weak references. However, it does have a very important downside:
|
|
since the system cannot clear all the references, it is impossible to
|
|
actually deallocate an object that is still weakly-referenced
|
|
(although it can be finalized). Instead, the system must wait for all
|
|
the weak references to at least be accessed. We call this "husk
|
|
leaking".
|
|
|
|
This downside could be a problem for a general weak reference.
|
|
However, it's fine for a back-reference, which we expect to typically
|
|
be short-lived after its referent is finalized.
|
|
|
|
Declaration Attribute or Type Attribute
|
|
---------------------------------------
|
|
|
|
This proposal describes :code:`weak` and :code:`unowned` as
|
|
declaration attributes, not type attributes.
|
|
|
|
As declaration attributes, :code:`[unowned]` and :code:`weak` would be
|
|
permitted on any :code:`var` declaration of reference type. Their
|
|
special semantics would be a property only of the declaration; in
|
|
particular, they would not change the type (beyond the shift to
|
|
:code:`Optional<T>` for :code:`weak`) , and more generally the
|
|
type-checker would not need to know about them. The implementation
|
|
would simply use different behavior when loading or storing that
|
|
variable.
|
|
|
|
As a type attribute, :code:`weak` and :code:`[unowned]` would be
|
|
permitted to appear at arbitrary nested locations in the type system,
|
|
such as tuple elements, function result types, or generic arguments.
|
|
It would be possible to have both lvalues and rvalues of so-qualified
|
|
type, and the type checker would need to introduce implicit
|
|
conversions in the right places.
|
|
|
|
These implicit conversions require some thought. Consider code like
|
|
the following::
|
|
|
|
func moveToWindow(newWindow : Window) {
|
|
var oldWindow = self.window // an [unowned] back reference
|
|
oldWindow.hide() // might remove the UI's strong reference
|
|
oldWindow.remove(self)
|
|
newWindow.add(self)
|
|
}
|
|
|
|
It would be very unfortunate if the back-reference nature of the
|
|
:code:`window` property were somehow inherited by :code:`oldWindow`!
|
|
Something, be it a general rule on loading back-references or a
|
|
type-inference rule, must introduce an implicit conversion and cause
|
|
the :code:`unowned` qualifier to be stripped.
|
|
|
|
That rule, however, is problematic for generics. A key goal of
|
|
generics is substitutability: the semantics of generic code should
|
|
match the semantics of the code you'd get from copy-pasting the
|
|
generic code and substituting the arguments wherever they're written.
|
|
But if a generic argument can be :code:`[unowned] T`, then this
|
|
won't be true; consider::
|
|
|
|
func foo<T>(x : T) {
|
|
var y = x
|
|
...
|
|
}
|
|
|
|
In substituted code, :code:`y` would have the qualifier stripped and
|
|
become a strong reference. But the generic type-checker cannot
|
|
statically recognize that this type is :code:`unowned`-qualified, so
|
|
in order to match semantics, this decision must be deferred until
|
|
runtime, and the type-checker must track the unqualified variant of
|
|
:code:`T`. This adds a great deal of complexity, both to the
|
|
implementation and to the user model, and removes many static
|
|
optimization opportunities due to potential mismatches of types.
|
|
|
|
An alternative rule would be to apply an implicit "decay" to a strong
|
|
reference only when a type is known to be a :code:`unowned` type. It
|
|
could be argued that breaking substitution is not a big deal because
|
|
other language features, like overloading, can already break it. But
|
|
an overlapping overload set with divergent behavior is a poor design
|
|
which itself violates substitution, whereas this would be a major
|
|
unexcused deviation. Furthermore, preserving the weakness of a
|
|
reference is not a safe default, because it permits the object to be
|
|
destroyed while a reference is still outstanding.
|
|
|
|
In addition, any implementation model which permits the safety checks
|
|
on :code:`unowned`\ s to be disabled will require all code to agree about
|
|
whether or not the checks are enabled. When this information is tied
|
|
to a declaration, this is easy, because declarations are ultimately
|
|
owned by a particular component, and we can ask how that component is
|
|
compiled. (And we can demand that external APIs commit to one level
|
|
of safety or the other before publishing.) The setting for a type, on
|
|
the other hand, would have to be determined by the module which "wrote
|
|
the type", but again this introduces a great deal of complexity which
|
|
one can only imagine settling on the head of some very confused user.
|
|
|
|
For all these reasons, I feel that making :code:`weak` and
|
|
:code:`unowned` type attributes would be unworkable. However, there
|
|
are still costs to making them declaration attributes:
|
|
|
|
- It forces users to use awkward workarounds if they want to
|
|
make, say, arrays of back-references.
|
|
|
|
- It makes back-references less composable by, say, preventing
|
|
them from being stored in a tuple.
|
|
|
|
- It complicates SIL and IR-gen by making the rules for manipulating a
|
|
physical variable depend on more than just the type of the variable.
|
|
|
|
- It automatically enables certain things (like passing the address of
|
|
a :code:`[unowned]` variable of type :code:`T` to a :code:`[inout] T`
|
|
parameter) that perhaps ought to be more carefully considered.
|
|
|
|
The first two points can be partly compensated for by adding library
|
|
types to wrap a back-reference. Accessing a wrapped reference will
|
|
require extra syntax, and it runs the same risk of accidentally
|
|
preserving the weakness of a reference that I discussed above.
|
|
However, note that these problems are actually at odds: requiring
|
|
extra syntax to access the wrapped reference will leave breadcrumbs
|
|
making it clear when the change-over occurs. For more on this,
|
|
see the library section.
|
|
|
|
:code:`weak`-Capable Types
|
|
--------------------------
|
|
|
|
Swift reference types can naturally be made to support any kind of
|
|
semantics, and I'm taking it on faith that we could enhance ObjC
|
|
objects to support whatever extended semantics we want. There
|
|
are, however, certain Swift value types which have reference-like
|
|
semantics that it could be useful to extend :code:`weak` (and/or
|
|
:code:`unowned`) to:
|
|
|
|
- Being able to conveniently form an optional back-reference seems
|
|
like a core requirement. If :code:`weak` were a type attribute,
|
|
we could just expect users to write :code:`Optional<[weak] T>`;
|
|
as a declaration attribute, this is substantially more difficult. I
|
|
expect this to be common enough that it'll be unreasonable to ask
|
|
users to use :code:`Optional<WeakReference<T>>`.
|
|
|
|
- Being able to form a back-reference to a slice or a string seems
|
|
substantially less important.
|
|
|
|
One complication with extending :code:`weak` to value types is that
|
|
generally the implementing type will need to be different from the
|
|
underlying value type. Probably the best solution would be to hide
|
|
the use of the implementing type from the type system outside of the
|
|
well-formedness checks for the variable; SIL-gen would lower the field
|
|
to its implementing type using the appropriate protocol conformances.
|
|
|
|
As long as we have convenient optional back-references, though, we
|
|
can avoid designing a general feature for 1.0.
|
|
|
|
|
|
Generic Weak Support
|
|
--------------------
|
|
|
|
All other uses for weak references can be glossed as desiring
|
|
some amount of additional work to occur when the strong reference
|
|
count for an object reaches zero. This necessarily entails a
|
|
global side-table of such operations, but I believe that's
|
|
acceptable as long as it's relegated to less common use-cases.
|
|
|
|
It is important that the notification mechanism not require
|
|
executing code re-entrantly during the finalization process.
|
|
|
|
I suggest adopting an interface centered around the Java
|
|
concept of a :code:`ReferenceQueue`. A reference structure
|
|
is registered with the runtime for a particular object with
|
|
a particular set of flags and an optional reference queue::
|
|
|
|
struct Reference {
|
|
void *Referent; // must be non-null upon registration
|
|
struct ReferenceQueue *Queue; // must be valid or null
|
|
size_t Reserved[2];
|
|
};
|
|
|
|
void swift_registerReference(struct Reference *reference,
|
|
size_t flags);
|
|
|
|
The user/library code is responsible for allocating these structures
|
|
and initializing the first two fields, and it may include arbitrary
|
|
fields before or after the :code:`Reference` section, but while the
|
|
reference is registered with the runtime, the entire :code:`Reference`
|
|
section becomes reserved and user/library code must not access it in
|
|
any way.
|
|
|
|
The flags include:
|
|
|
|
- A priority. Should be constrained to two or three bits. References
|
|
are processed in order of decreasing priority; as long as a
|
|
reference still exists with higher priority, references with lower
|
|
priority cannot be processed. Furthermore, as long as any reference
|
|
exists, the referent cannot be finalized.
|
|
|
|
- Whether to automatically clear the reference when processing it.
|
|
Note that a cleared reference is still considered to be
|
|
registered with the runtime.
|
|
|
|
These could be combined so that e.g. even priorities cause
|
|
an automatic clear and odd priorities do not; this would avoid some
|
|
odd effects.
|
|
|
|
The runtime may assume that explicit user operations on the same
|
|
reference will not race with each other. However, user operations on
|
|
different references to the same referent may be concurrent, either
|
|
with each other or with other refcount operations on the referent.
|
|
|
|
The operations on references are as follows::
|
|
|
|
void *swift_readReference(struct Reference *reference);
|
|
|
|
This operation atomically either produces a strong reference to the
|
|
referent of the given object or yields :code:`null` if the referent
|
|
has been finalized (or if the referent is :code:`null`). The
|
|
reference must currently be registered with the runtime::
|
|
|
|
void swift_writeReference(struct Reference *reference,
|
|
void *newReferent);
|
|
|
|
This operation changes the referent of the reference to a new object,
|
|
potentially :code:`null`. The argument is taken at +0. The reference
|
|
must currently be registered with the runtime. The reference keeps
|
|
the same flags and reference queue::
|
|
|
|
void swift_unregisterReference(struct Reference *Reference);
|
|
|
|
This operation clears a reference, removes it from its reference
|
|
queue (if it is enqueued), and unregisters it from the runtime.
|
|
The reference must currently be registered with the runtime.
|
|
|
|
I propose the following simple interface to a ReferenceQueue;
|
|
arguably, however, it ought to be a reference-counted library
|
|
type with a small amount of native implementation::
|
|
|
|
struct ReferenceQueue;
|
|
struct ReferenceQueue *swift_createReferenceQueue(void);
|
|
|
|
Allocate a new reference queue::
|
|
|
|
void swift_destroyReferenceQueue(struct ReferenceQueue *queue);
|
|
|
|
Destroy a reference queue. There must not be any references with
|
|
this queue currently registered with the runtime::
|
|
|
|
struct Reference *swift_pollReferenceQueue(struct ReferenceQueue *queue);
|
|
|
|
|
|
Proposed Rules for Captures within Closures
|
|
===========================================
|
|
|
|
When a variable from an enclosing context is referenced in a closure,
|
|
by default it is captured by reference. Semantically, this means that
|
|
the variable and the enclosing context(s) will see the variable as a
|
|
single, independent entity; modifications will be seen in all places.
|
|
In terms of the reference graph, each context holds a strong reference
|
|
to the variable itself. (In practice, most local variables captured
|
|
by reference will not require individual allocation; usually they will
|
|
be allocated as part of the closure object. But in the formalism,
|
|
they are independent objects.)
|
|
|
|
Closures therefore make it fairly easy to introduce reference cycles:
|
|
for example, an instance method might install a closure as an event
|
|
listener on a child object, and if that closure refers to
|
|
:code:`this`, a reference cycle will be formed. This is an
|
|
indisputable drawback of an environment which cannot collect reference
|
|
cycles.
|
|
|
|
Relatively few languages both support closures and use
|
|
reference-counting. I'm not aware of any that attempt a language
|
|
solution to the problem; the usual solution is to the change the
|
|
captured variable to use weak-reference semantics, usually by copying
|
|
the original into a new variable used only for this purpose. This is
|
|
annoyingly verbose, clutters up the enclosing scope, and duplicates
|
|
information across multiple variables. It's also error-prone: since
|
|
both names are in scope, it's easy to accidentally refer to the wrong
|
|
one, and explicit capture lists only help if you're willing to be very
|
|
explicit.
|
|
|
|
A better alternative (which we should implement in Objective-C as
|
|
well) is to permit closures to explicitly specify the semantics under
|
|
which a variable is captured. In small closures, it makes sense to
|
|
put this near the variable reference; in larger closures, this can
|
|
become laborious and redundant, and a different mechanism is called for.
|
|
|
|
In the following discussion, a *var-or-member expression* is an
|
|
expression which is semantically constrained to be one of:
|
|
|
|
- A reference to a local variable-like declaration from an
|
|
enclosing context.
|
|
|
|
- A member access thereof, possibly recursively.
|
|
|
|
Such expressions have two useful traits:
|
|
|
|
- They always end in an identifier which on some level meaningfully
|
|
identifies the object.
|
|
|
|
- Evaluating them is relatively likely (but not guaranteed) to not
|
|
have interesting side effects, and so we feel less bad about
|
|
apparently shifting their evaluation around.
|
|
|
|
Decorated Capture References
|
|
----------------------------
|
|
|
|
Small closures are just as likely to participate in a reference cycle,
|
|
but they suffer much more from extraneous syntax because they're more
|
|
likely to be center-embedded in interesting expressions. So if
|
|
there's anything to optimize for in the grammar, it's this.
|
|
|
|
I propose this fairly obvious syntax::
|
|
|
|
button1.setAction { unowned(self).tapOut() }
|
|
button2.setAction { if (weak(self)) { weak(self).swapIn() } }
|
|
|
|
The operand is evaluated at the time of closure formation. Since
|
|
these references can be a long way from the top of the closure, we
|
|
don't want to allow a truly arbitrary expression here, because the
|
|
order of side-effects in the surrounding context could be very
|
|
confusing. So we require the operand to be an :code:`expr-var-or-member`.
|
|
More complicated expressions really ought to be hoisted out to a
|
|
separate variable for legibility anyway.
|
|
|
|
I do believe that being able to capture the value of a property
|
|
(particulary of :code:`this`) is very important. In fact, it's
|
|
important independent of weak references. It is often possible to
|
|
avoid a reference cycle by simply capturing a specific property value
|
|
instead of the base object. Capturing by value is also an
|
|
expressivity improvement: the programmer can easily choose between
|
|
working with the property's instantaneous value (at the time the
|
|
closure is created) or its current value (at the time the closure is
|
|
invoked).
|
|
|
|
Therefore I also suggest a closely-related form of decoration::
|
|
|
|
button3.setAction { capture(self.model).addProfitStep() }
|
|
|
|
This syntax would force :code:`capture` to become a real keyword.
|
|
|
|
All of these kinds of decorated references are equivalent to adding a
|
|
so-attributed :code:`capture` declaration (see below) with a nonce
|
|
identifier to the top of the closure::
|
|
|
|
button1.setAction {
|
|
capture [unowned] _V1 = this
|
|
_V1.tapOut()
|
|
}
|
|
button2.setAction {
|
|
capture [weak] _V2 = this
|
|
if (_V2) { _V2.swapIn() }
|
|
}
|
|
button3.setAction {
|
|
capture _V3 = self.model
|
|
_V3.addProfitStep()
|
|
}
|
|
|
|
If the operand of a decorated capture is a local variable, then that
|
|
variable must not be the subject of an explicit :code:`capture`
|
|
declaration, and all references to that variable within the closure
|
|
must be identically decorated.
|
|
|
|
The requirement to decorate all references can add redundancy, but
|
|
only if the programmer insists on decorating references instead of
|
|
adding an explicit :code:`capture` declaration. Meanwhile, that
|
|
redundancy aids both maintainers (by preventing refactors from
|
|
accidentally removing the controlling decoration) and readers (who
|
|
would otherwise need to search the entire closure to understand how
|
|
the variable is captured).
|
|
|
|
Captures with identical forms (the same sequence of members of the
|
|
same variable) are merged to the same capture declaration. This
|
|
permits type refinement to work as expected, as seen above with the
|
|
:code:`weak` capture. It also guarantees the elimination of some
|
|
redundant computation, such as with the :code:`state` property in this
|
|
example::
|
|
|
|
resetButton.setAction {
|
|
log("resetting state to " + capture(self.state))
|
|
capture(self.model).setState(capture(self.state))
|
|
}
|
|
|
|
I don't see any immediate need for other kinds of capture decoration.
|
|
In particular, I think back references are likely to be the right kind
|
|
of weak reference here for basically every use, and I don't think that
|
|
making it easy to capture a value with, say, a zeroable weak reference
|
|
is important. This is just an intuition deepened by hallway
|
|
discussions and close examination of a great many test cases, so I
|
|
concede it may prove to be misguided, in which case it should be easy
|
|
enough to add a new kind of decoration (if we're willing to burn a
|
|
keyword on it).
|
|
|
|
:code:`capture` Declarations
|
|
----------------------------
|
|
|
|
This feature generalizes the above, removing some redundancy in large
|
|
closures and adding a small amount of expressive power.
|
|
|
|
A :code:`capture` declaration can only appear in a closure: an
|
|
anonymous closure expression or :code:`func` declaration that appears
|
|
directly within a function. (By "directly" I mean not within, say, a
|
|
local type declaration within the function). :code:`capture` will
|
|
need to at least become a context-sensitive keyword.
|
|
|
|
A closure may contain multiple :code:`capture` declarations, but they
|
|
must all appear at the very top. One reason is that they can affect
|
|
the capture semantics within the closure, so someone reading the
|
|
closure should be able to find them easily. Another reason is that
|
|
they can involve executing interesting code in the enclosing context
|
|
and so should reliably appear near the closure formation site in the
|
|
source code::
|
|
|
|
decl ::= decl-capture
|
|
decl-capture ::= 'capture' attribute-list '=' expr-var-or-member
|
|
decl-capture ::= 'capture' attribute-list decl-capture-expr-list
|
|
decl-capture-expr-list ::= expr-var-or-member
|
|
decl-capture-expr-list ::= expr-var-or-member ',' decl-capture-expr-list
|
|
|
|
Both forms of :code:`capture` declaration cause one or more fields to
|
|
be created within the closure object. At the time of creating the
|
|
closure, these fields are initialized with the result of evaluating an
|
|
expression in the enclosing context. Since the expression is
|
|
evaluated in the enclosing context, it cannot refer to "previous"
|
|
captures; otherwise we could have some awkward ambiguities. I think
|
|
we should reserve the right to not execute an initializer if the
|
|
closure will never be called; this is more important for local
|
|
:code:`func` declarations than for anonymous closure expressions.
|
|
|
|
The fields introduced by :code:`capture` declarations should be
|
|
immutable by default, but programmers should be able to write
|
|
something like :code:`capture var ...` to make them mutable. Locking
|
|
down on mutation isn't quite as important as it is with implicit
|
|
captures (where it's easy to accidentally believe you're modifying the
|
|
enclosing variable) or even explicit captures in C++11 lambdas (where
|
|
copies of the lambda object will copy the capture field and thus
|
|
produce mystifying behavior in uncareful code), but it's still a
|
|
source of easy mistakes that should require manual intervention to
|
|
enable. This all presumes that we eventually design mutability into
|
|
the language, of course.
|
|
|
|
In the pattern-initializer form, the field names are given explicitly
|
|
by the pattern. The abbreviated form borrows the name of the captured
|
|
member or local variable. In either case, names should be subject to
|
|
the usual shadowing rules, whatever they may be, with the exception
|
|
that capturing an enclosing variable with the abbreviated form is not
|
|
problematic.
|
|
|
|
Attributes on a :code:`capture` declaration affect all the fields it
|
|
declares.
|
|
|
|
Let's spell out some examples. I expect the dominant form to be a
|
|
simple identifier::
|
|
|
|
capture [unowned] foo
|
|
|
|
This captures the current value of whatever :code:`foo` resolves to
|
|
(potentially a member of :code:`this`!) and binds it within the
|
|
closure as a back-reference.
|
|
|
|
Permitting the slightly more general form::
|
|
|
|
capture window.title
|
|
|
|
allows users to conveniently capture specific values without mucking
|
|
up the enclosing scope with tons of variables only needed for setting
|
|
up the closure. In particular, this makes it easy to capture specific
|
|
fields out of an enclosing :code:`this` object instead of capturing
|
|
the object itself; that, plus forcing uses of :code:`this` to be
|
|
explicit in closures, would help users to conveniently avoid a class
|
|
of inadvertent retain cycles.
|
|
|
|
I've included the general pattern-initializer form mostly for ease of
|
|
exposition. It adds no major expressivity improvements over just
|
|
creating a variable in the enclosing context. It does avoid
|
|
cluttering the enclosing scope with new variables and permits captures
|
|
to be locally renamed, and it can very convenient if introducing a new
|
|
variable in the enclosing scope would be complicated (for example, if
|
|
there were a reason to prefer using a single statement there). I
|
|
don't think it does any harm, but I wouldn't mourn it, either. I do
|
|
think that generalizing the initializer to an arbitrary expression
|
|
would be a serious mistake, because readers are naturally going to
|
|
overlook code which occurs inside the closure, and promoting side
|
|
effects there would be awful.
|
|
|
|
It would be nice to have a way to declare that a closure should not
|
|
have any implicit captures. I don't have a proposal for that right now,
|
|
but it's not important for weak references.
|
|
|
|
Nested Closures
|
|
---------------
|
|
|
|
It is important to spell out how these rules affect captures in nested
|
|
closures.
|
|
|
|
Recall that all of the above rules can be transformed into
|
|
``capture`` declarations at the beginning of a closure, and that
|
|
``capture`` declarations always introduce a by-value capture
|
|
instead of a by-reference capture.
|
|
|
|
A by-reference capture is always of either a local variable or a
|
|
``capture`` declaration. In neither case do we currently permit
|
|
such captures to "drag in" other declarations silently, to the extent
|
|
that this is detectable. This means that mutable ``capture``
|
|
declarations that are themselves captured by reference must be
|
|
separately allocated from the closure object, much like what happens
|
|
with normal locals captured by reference.
|
|
|
|
I've considered it quite a bit, and I think that a by-value capture of
|
|
a variable from a non-immediately enclosing context must be made
|
|
ill-formed. At the very least, it must be ill-formed if either the
|
|
original variable is mutable (or anything along the path is, if it
|
|
involves properties) or the capture adds ``[unowned]``.
|
|
|
|
This rule will effectively force programmers to use extra variables or
|
|
``capture``\ s as a way of promising validity of the internal
|
|
captures.
|
|
|
|
The motivation for this prohibition is that the intent of such
|
|
captures is actually quite ambiguous and/or dangerous. Consider
|
|
the following code::
|
|
|
|
async { doSomething(); GUI.sync { unowned(view).fireCompleted() } }
|
|
|
|
The intent of this code is to have captured a back-reference to the
|
|
value of :code:`view`, but it could be to do so at either of two
|
|
points in time. The language must choose, and in this hypothetical it
|
|
must do so without further declaration of intent and without knowledge
|
|
of when and how many times the closures will be called.
|
|
|
|
Suppose that we capture the value at the earlier point, when we form
|
|
the outer closure. This will behave very surprisingly if :code:`view`
|
|
is in fact mutated; it may be easier to imagine this if, instead of a
|
|
simple local variable, it was instead a path like :code:`self.view`.
|
|
And it's not clear that forming a back-reference at this earlier point
|
|
is actually valid; it is easy to imagine code that would rely on the
|
|
intermediate closure holding a strong reference to the view.
|
|
Furthermore, and crucially, these issues are inextricable: we cannot
|
|
somehow keep track of the mutable variable but only hold its value
|
|
weakly.
|
|
|
|
But suppose instead that we capture the value at the later point.
|
|
Then the intermediate closure will capture the :code:`view` variable
|
|
by reference, which means that in effect it will hold :code:`view`
|
|
strongly. This may actually completely subvert the user's desired
|
|
behavior.
|
|
|
|
It's not clear to me right now whether this problem applies equally to
|
|
explicit :code:`capture` declarations. Somehow decorated expressions
|
|
seem more ambiguous in intent, probably because the syntax is more
|
|
thoughtlessly convenient. On the other hand, making the decoration
|
|
syntax not just a shorthand for the explicit declarations makes the
|
|
model more complex, and it may be over-complex already.
|
|
|
|
So in summary, it would be best to enforce a strong prohibition against
|
|
these dangerous multi-level captures. We can tell users to introduce
|
|
secondary variables when they need to do subtle things across several
|
|
closure levels.
|
|
|
|
|
|
Library Directions
|
|
==================
|
|
|
|
The library should definitely provide the following types:
|
|
|
|
- :code:`UnownedReference<T>`: a fragile value type with a single
|
|
public :code:`unowned` field of type :code:`T`. There should be an
|
|
implicit conversion *from* :code:`T` so that obvious initializations
|
|
and assignments succeed. However, there should not be an implicit
|
|
conversion *to* :code:`T`; this would be dangerous because it could
|
|
hide bugs introduced by the way that e.g. naive copies into locals
|
|
will preserve the weakness of the reference.
|
|
|
|
In keeping with our design for :code:`unowned`, I think this type
|
|
should should actually be an alias to either
|
|
:code:`SafeUnownedReference<T>` or :code:`UnsafeUnownedReference<T>`
|
|
depending on the current component's build settings. The choice
|
|
would be exported in binary modules, but for cleanliness we would
|
|
also require public APIs to visibly commit to one choice or the
|
|
other.
|
|
|
|
- :code:`WeakReference<T>`: a fragile value type with a single public
|
|
:code:`weak` field of type :code:`T`. As above, there should be an
|
|
implicit conversion *from* :code:`T` but no implicit conversion to
|
|
:code:`T` (or even :code:`Optional<T>`). There is, however, no
|
|
need for safe and unsafe variants.
|
|
|
|
The library should consider providing the following types:
|
|
|
|
- A simple, memory-sensitive weak cache.
|
|
|
|
- :code:`Finalizer`: a value type which is constructed with a referent
|
|
and a :code:`() -> ()` function and which causes the function to be
|
|
run (on a well-known dispatch queue?) when the object is finalized.
|
|
|