Table of contents
Takes
Formal definition
Taking is a relation :
holding when is a named input parameter of — cannot execute without an instance being supplied as input.
One invariant. iff:
- Parameter necessity: requires an instance of as a named input to execute. Taking is a necessary-input relation: not merely that could use in principle, but that ’s interface specifies as a parameter that must be supplied. The mode of use (read, write, consume) is additional information beyond taking.
Taking is the coarsest of the input relations: implies ; implies ; implies . The converse does not hold: taking does not specify the access mode.
Lambda calculus: function domains
Alonzo Church (The Calculi of Lambda-Conversion, 1941): in typed lambda calculus, a function takes an argument of type — is the domain. The application requires . The function takes in the broadest sense: it requires an instance of without specifying whether is consumed (as in linear lambda calculus) or shared (as in classical lambda calculus).
In linear lambda calculus (the lambda calculus corresponding to linear logic): taking is disambiguated by the type:
- takes and consumes
- takes and reads (non-destructively)
- takes both and
In dependent type theory (Martin-Löf 1984): a function takes an argument and produces a result of type (which may depend on ). Taking is the domain of the dependent function type.
Separation logic: pre-heap assertions
In separation logic, an operation takes heap cells by requiring them in the precondition. The Hoare triple asserts that requires exclusive ownership of pointing to as input. Taking means requiring the points-to assertion in the precondition.
The access mode is determined by the postcondition: if the postcondition retains for some (possibly unchanged), the operation writes/reads ; if the postcondition has for ’s position, the operation consumed .
Atkey: quantitative type theory and usage grades
Robert Atkey (Syntax and Semantics of Quantitative Type Theory, LICS 2018) makes the precise relationship between taking and its refinements rigorous. In quantitative type theory, every binding carries a usage grade from a semiring :
- : the parameter is declared but not accessed — it is taken but never used (weakening)
- : the parameter is consumed — taken and used exactly once (linear take)
- : the parameter may be accessed freely — taken and readable any number of times (unrestricted take)
without further specification corresponds to the generic grade — the parameter appears in ’s signature with some grade not yet specified. The refinements are:
- : grade
- : grade
- Grade is the limiting case where the parameter is declared but unused
Taking is the generic binder before grade annotation. The grade lattice $0 \leq 1 and \0 \leq \omega (with \1\omega$ incomparable) orders the access modes by specificity: taking is below both consuming and reading in the information order.
In Rust’s ownership system — a practical implementation of linear types — taking manifests as receiving a value as a parameter:
- Take with grade 1 (consume):
fn f(x: T)— value moved in, caller loses ownership - Take with grade ω (read):
fn f(x: &T)— shared borrow, caller retains ownership - Take with grade ω exclusive (write):
fn f(x: &mut T)— exclusive borrow, caller retains ownership but no others may access during the call
Open questions
- Whether “takes” should be separated into “takes-for-reading” vs “takes-for-consuming” in a type system at the parameter declaration level, rather than inferred from the access pattern — and whether Atkey’s grade annotation is the right mechanism or whether more expressive grading semirings (e.g., for bounded-use resources) are needed.
- Whether taking corresponds to a coend in category theory — whether means is a profunctor with in the contravariant position, and whether the various access modes (grades) correspond to different strengths of profunctor morphism or different enrichments of the profunctor category.