In this section

Foundation

Every tag form means the set of states its key may be in, and it means the same set on either side of a comparison:

Form Stored value The states it allows
missing (no entry) every state; nothing is said
?x "?" every state; nothing is said, aloud
x?=v "?=v" unset, or set to anything but v
x (=x=*) "*" set, to any value
x!=v "!=v" set, to anything but v
x=v "v" set to exactly v
!x "!" unset

A URN means the things that are in an allowed state at every key. So a URN is a description, and a description is a set: media:document;ext=pdf is every value whose ext is pdf, whatever its other tags.

Two descriptions can be asked two different questions, and a third arises when one side is not a description but a thing:

Question Relation Meaning
Is everything a describes described by b? a ⪯ b (refines) a guarantee: inclusion of meanings
Is anything described by both? a ⌢ b (meets) a possibility: the meanings overlap
Does this complete thing fit b? satisfies the thing’s omissions are absences

These are three relations on one meaning, not one relation with exceptions; Why there are three explains why they must stay separate.

The model is tagged-urn/formal (Lean), and every implementation runs code generated from it. tagMatch_iff_allows, tagMeets_iff_allows, refines_iff_holds and meets_iff_holds are the theorems that say the tables below are inclusion and overlap of the meanings above, for single keys and for whole URNs.


The guarantee: conforms_to, accepts, is_equivalent, is_comparable

conforms_to(a, b)   :⟺  a ⪯ b              a is at least as specific as b
accepts(a, b)       :⟺  b ⪯ a              the same, from the pattern's side
is_equivalent(a, b) :⟺  a ⪯ b  ∧  b ⪯ a    the same tag set
is_comparable(a, b) :⟺  a ⪯ b  ∨  b ⪯ a    on one specialization chain

Examples:

conforms_to(media:bytes;document;ext=pdf, media:bytes)   = true   # every pdf of bytes is bytes
conforms_to(media:bytes, media:bytes;document;ext=pdf)   = false  # bytes need not be a pdf
conforms_to(media:ext, media:document;ext=pdf)           = false  # "some ext" is not a promise of pdf
conforms_to(media:document;ext=pdf, media:ext)           = true   # a pdf is some ext
is_equivalent(media:ext, media:document;ext=pdf)         = false  # different tag sets
is_comparable(media:ext, media:document;ext=pdf)         = true   # one chain

The table

Instance (row) against pattern (column): ✓ when every state the instance allows, the pattern allows.

Inst ↓ \ Pat → missing ?x x?=p x x!=p x=p !x
missing ✓ ✓ ✗ ✗ ✗ ✗ ✗
?x ✓ ✓ ✗ ✗ ✗ ✗ ✗
x?=v ✓ ✓ v = p ✗ ✗ ✗ ✗
x ✓ ✓ ✗ ✓ ✗ ✗ ✗
x!=v ✓ ✓ v = p ✓ v = p ✗ ✗
x=v ✓ ✓ v ≠ p ✓ v ≠ p v = p ✗
!x ✓ ✓ ✓ ✗ ✗ ✗ ✓

An instance that omits a key, or says ?x, promises nothing about it, so it satisfies only the patterns that ask for nothing. x promises presence and no particular value. Nothing is “decided later” here: a guarantee is settled by the two descriptions alone.

Properties

  • conforms_to and accepts are reflexive and transitive (refines_refl, refines_trans): a preorder.
  • is_equivalent is an equivalence relation, and equivalent URNs say the same thing at every key, up to missing and ?x, which mean the same (equivalent_iff_same_forms). Alias lookup and stream matching by equivalence are matching by tag set.
  • Refining never scores lower (tagScore_monotone), so a source that conforms to an argument is never less specific than it.

The possibility: meets

meets(a, b)  :⟺  some thing is described by both a and b

Symmetric: neither side is the instance. This is what a search asks, and what “decided at run time” means:

meets(media:ext, media:document;ext=pdf)        = true   # some ext COULD be a pdf
conforms_to(media:ext, media:document;ext=pdf)  = false  # it is not guaranteed to be
meets(media:document;ext=pdf, media:ext=png)    = false  # excluded

The table

The same seven forms; ✓ when the two allow a common state. Symmetric, so only the cells that fail are worth listing. Two forms fail to meet exactly when:

One side The other Why
!x x, x!=p, x=p unset against set
x=v x=p, v ≠ p two different values
x=v x!=v the one value that is refused
x=v x?=v the one value that is refused

Every other pair meets.

Properties

  • Reflexive and symmetric (meets_refl, meets_symm).
  • Not transitive, and not meant to be (tagMeets_not_transitive): a pdf meets “some ext”, which meets a png.
  • Whatever conforms meets (refines_meets; no form is empty), and what meets b meets everything b refines (meets_of_refines).

meets is for exploring. Nothing is ever routed on it: a call is routed on a guarantee (Dispatch).


Complete things: satisfies, may_satisfy

A description that omits a key says nothing about it. A thing that exists omits a key because it does not have it. Two kinds of thing are complete:

  • the media of an actual value (a stream that arrived, an output that was produced, or a file that was detected);
  • a cap’s own list of cap-tags: a cap has the tags it has.

A media type on a cap’s in or out is not complete: a cap that takes media:document;ext=pdf takes compressed pdfs too.

satisfies(thing, pattern)     guaranteed, reading the thing's omissions as absences
may_satisfy(thing, pattern)   possible, on the same reading

The complete reading changes exactly one row: the thing’s missing row becomes the !x row (Constraint.closed).

Thing ↓ \ Pat → missing ?x x?=p x x!=p x=p !x
missing ✓ ✓ ✓ ✗ ✗ ✗ ✓
conforms_to(media:document;ext=pdf, media:document;ext=pdf;!compressed)  = false  # as a TYPE it may be compressed
satisfies(media:document;ext=pdf, media:document;ext=pdf;!compressed)    = true   # as a VALUE it has no such tag

satisfies is not a relation between two descriptions and is not transitive through one (refinesClosed_not_transitive): x=v satisfies the description that says nothing of x, a complete thing silent on x satisfies !x, and x=v does not. What holds is the law a satisfaction relation has: what satisfies a description satisfies everything that description refines (refinesClosed_of_refines).


Which one

You have You ask Use
two declared types does one always fit the other? conforms_to / accepts
two declared types are they the same type? is_equivalent
two declared types could they be about the same value? meets
a value’s media and a declared type does the value fit? satisfies
a value’s media and a declared type could it fit? may_satisfy
if declared_output.conforms_to(&next_input)? { /* the edge always works */ }
if declared_output.meets(&next_input)?       { /* it may; check when run */ }
if arrived_stream.satisfies(&arg_type)?      { /* this value is that arg */ }

For caps, none of these alone is the routing question; see Dispatch.


Common mistakes

Using a possibility where a guarantee is needed

if candidate_output.meets(&needed) { /* route here */ }   // WRONG

A cap that gives “some image” could give a jpeg. Routing a call that needs a jpeg to it is a failure waiting for the value to turn up.

Reading a value as a type

if stream_media.conforms_to(&pattern) { ... }   // reads the value's omissions as "anything"
if stream_media.satisfies(&pattern)   { ... }   // reads them as absences

The two agree until a pattern asks for an absence (!x) or forbids a value (x?=v).

Confusing direction

if pattern.conforms_to(&instance) { ... }  // BACKWARDS
if instance.conforms_to(&pattern) { ... }  // or: pattern.accepts(&instance)

Why there are three

A single table cannot answer all three questions. Reading an instance-side x or ?x as “whatever the pattern wants, decided later” puts a possibility inside a guarantee. Reading an omitted key as “anything” in a pattern and “absent” in an instance treats one side as a description and the other as a complete thing. A relation built that way is neither a guarantee nor a possibility: refinement stops being transitive, media:ext and media:document;ext=pdf become “equivalent”, and equivalence stops being an equivalence relation.

The separation follows established work. A description with unknown parts means the set of things it could be; a predicate can be asked to hold of all of that set or of some of it, and the two are different relations with different laws. The second is reflexive and symmetric and must not be transitive (Garcia, Clark & Tanter, Abstracting Gradual Typing, POPL 2016, Def. 1–3; Siek & Taha, Gradual Typing for Functional Languages, 2006). Subtyping as inclusion of meanings is semantic subtyping (Frisch, Castagna & Benzaken, JACM 2008). Matchmaking calls the same pair plug-in and intersection match (Li & Horrocks, 2003). And reading an omission as an absence is the closed-world assumption (Reiter, 1978), which belongs to facts, not to descriptions.


Summary

Question Predicate Symmetric Transitive
Does every instance of a fit b? conforms_to(a, b) no yes
…from the pattern’s side accepts(b, a) no yes
Are these the same? is_equivalent(a, b) yes yes
Are these on one chain? is_comparable(a, b) yes no
Could these be about the same thing? meets(a, b) yes no
Does this complete thing fit? satisfies(thing, b) no —
Could this complete thing fit? may_satisfy(thing, b) no —