Skip to content

Taking is a relation O takes R — operation O takes resource R as input — asserting that O receives R as a named structural parameter: R is passed to O, O may use R in any way (read, write, or consume), and R's lifecycle after O depends on O's type. The defining structure: taking specifies the input interface — what the operation receives as a named parameter — without specifying the access mode (read-only, modifiable, or destructive). Taking is the most general input relation; reads, writes, and consumes are all refinements of takes that specify the access mode. Taking corresponds to a function's domain: the type of values that must be supplied to invoke the operation.
Table of contents

Takes

Formal definition

Taking is a relation O takes RO \text{ takes } R:

(O:Operation,  R:ParameterType)(O : \mathrm{Operation},\; R : \mathrm{ParameterType})

holding when RR is a named input parameter of OOOO cannot execute without an instance r:Rr : R being supplied as input.

One invariant. O takes RO \text{ takes } R iff:

  1. Parameter necessity: OO requires an instance of RR as a named input to execute. Taking is a necessary-input relation: not merely that OO could use RR in principle, but that OO’s interface specifies RR 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: O reads RO \text{ reads } R implies O takes RO \text{ takes } R; O writes RO \text{ writes } R implies O takes RO \text{ takes } R; O consumes RO \text{ consumes } R implies O takes RO \text{ takes } R. 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 f:ABf : A \to B takes an argument of type AAAA is the domain. The application f  af\; a requires a:Aa : A. The function ff takes AA in the broadest sense: it requires an instance of AA without specifying whether aa 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:

  • f:ABf : A \multimap B takes and consumes AA
  • f:!ABf : !A \multimap B takes and reads AA (non-destructively)
  • f:ABCf : A \otimes B \multimap C takes both AA and BB

In dependent type theory (Martin-Löf 1984): a function f:Πx:AB(x)f : \Pi_{x:A} B(x) takes an argument x:Ax : A and produces a result of type B(x)B(x) (which may depend on xx). Taking is the domain of the dependent function type.

Separation logic: pre-heap assertions

In separation logic, an operation OO takes heap cells by requiring them in the precondition. The Hoare triple {xv}  O  {Q}\{x \mapsto v\}\; O\; \{Q\} asserts that OO requires exclusive ownership of xx pointing to vv as input. Taking xx means requiring the points-to assertion xvx \mapsto v in the precondition.

The access mode is determined by the postcondition: if the postcondition retains xvx \mapsto v' for some vv' (possibly unchanged), the operation writes/reads xx; if the postcondition has emp\mathrm{emp} for xx’s position, the operation consumed xx.

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 x:ρAx :_\rho A carries a usage grade ρ\rho from a semiring {0,1,ω}\{0, 1, \omega\}:

  • ρ=0\rho = 0: the parameter is declared but not accessed — it is taken but never used (weakening)
  • ρ=1\rho = 1: the parameter is consumed — taken and used exactly once (linear take)
  • ρ=ω\rho = \omega: the parameter may be accessed freely — taken and readable any number of times (unrestricted take)

O takes RO \text{ takes } R without further specification corresponds to the generic grade — the parameter appears in OO’s signature with some grade ρ{0,1,ω}\rho \in \{0, 1, \omega\} not yet specified. The refinements are:

  • O consumes RO \text{ consumes } R: grade ρ=1\rho = 1
  • O reads RO \text{ reads } R: grade ρ=ω\rho = \omega
  • Grade ρ=0\rho = 0 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 \1and and \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., {0,1,ω,ω2,}\{0, 1, \omega, \omega^2, \ldots\} for bounded-use resources) are needed.
  • Whether taking corresponds to a coend in category theory — whether O takes RO \text{ takes } R means OO is a profunctor with RR 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.

Relations

Ast
Date created
Date modified
Defines
Takes
Operation
Relational universe morphism
Output
Relational universe morphism
Parameter type
Relational universe
Related
Reads, writes, consumes, produces, returns, uses, function domain, linear logic