ADR-042: A View Keeps the Type It Is a View Of, and a Transparent Container Is Seen Through

Status: Accepted Related: ADR-024 (the type checker says only what is written down — D1 is that discipline failing in one direction, not an exception to it), ADR-288 (a signature naming its receiver’s type arguments, which is what makes D2 answer with what this container holds), ADR-288 D11 (why D2 takes one step and not a chain), ADR-312 D1 (the rule that needed this before it could be written).

1. Context

Two rules in one place, and neither is about sharing, though a shared value lent out without unwrapping it depends on both.

A view of a generic type has to answer something. If ref Vec[i64], ref HashMap[String, Stats] or ref Shared[Connection] came out as “nothing is known”, the checker would say nothing, the program would be emitted, and a mismatch would be reported by rustc, about the generated file — the one thing Part III C.1 forbids. That would not be a gap in what the checker knows — the type is right there — but a step that throws it away.

A transparent container has to be accepted. Part III says of fs::Mapped that “a parser cannot tell the difference”, and std’s ledger spells it out with a fs::Mapped::deref entry. A function taking a text view that refused a mapped file would break what the specification promises about the type.

The two point in opposite directions: one lets too much through, the other too little.

2. Decisions

D1 — A view keeps the type it is a view of, arguments and all.

Changed by ADR-184 D1 and D2: a view is spelled ref X, and the text view is written ref String — str is not a name a program, signature or message uses.

ref Vec[i64] is a view of a Vec[i64]. Three cases and nothing else:

A tuple and a lambda answer nothing, deliberately: a tuple of views is not a view of a tuple, and nothing writes down what a view of a lambda would be.

D2 — A type whose ledger records a deref is seen through, once, and only to rescue a comparison that has already failed.

A container that records Type::deref is one a caller is not meant to notice. So where a found type does not fit what is wanted, and the ledger says the found type derefs, the question is asked again of what the deref gives.

Only as a rescue. It runs after a direct comparison has failed, so seeing through a container can turn a refusal into an acceptance and can never turn an acceptance into a refusal. That is what makes it safe to add to a checker whose whole discipline is to say nothing where it knows nothing (ADR-024): this says more only where it was already about to refuse.

One step. A container inside a container is two questions, and this record answers the first. The second - reaching through a Shared into what the value it shares holds - is not decided here.

The receiver’s own arguments bind the signature’s variables as they do for any other method (ADR-288), so an entry written [T](self: ref Shared[T]) -> ref(self) T answers with what this container holds rather than with a variable. That is what makes D2 enough for a generic container and not only for Mapped.

3. Consequences

A program rustc would refuse is refused by Nikaia — a text view handed a ref Vec[i64] is NK1102, in this compiler’s words and with a help line.

A function taking a text view accepts a mapped file, as the specification promises.

ADR-312 D1 rests on this. A handle on a shared value is duplicated where it is handed on; lending one out is the case where nothing is handed on at all, and D1 and D2 are the rule under which serve(ref db) means something.

Shared[T] is seen through by D2 because std’s ledger records a Shared::deref, with no further decision — the shared case is a consequence of this record rather than a special case beside it. SharedMut[T] records no deref — there is no view straight through a lock, so it is opened through its doors (ADR-281).

This site is open source. Improve this page.