Skip to content

Coherence, Visibility, and Contract Method Lookup

Accepted

Accepted for V1 conformance visibility and contract operation method lookup; depends on Semantic Contracts and Modules, Imports, and Module Roots.

Coherence and Visibility

Conformance is scoped by normal module visibility/import rules.

For a given concrete type and fully applied contract, there must be at most one visible implementation in a scope. If multiple visible implementations exist, use is ambiguous and is a compile error.

Different contract arguments are distinct contracts:

TextBuffer implements Sequence(u8)
TextBuffer implements Sequence(Rune)

These may coexist. Method lookup may still be ambiguous if the contract argument cannot be inferred.

The owning module of a type should usually export the canonical implementation. Third-party adapter modules are allowed, but importing competing adapters creates an explicit conflict.

Catalyst's conformance visibility is scoped by imports: an impl can exist in a module without becoming visible everywhere. Public canonical impls usually live with the implementing type and travel with selected type declarations. Public adapter impls live in adapter namespaces and become visible only when those namespaces are imported.

Importing an impl makes it visible for local checking, but does not re-export it from the importing namespace. To expose an impl as part of a module's main namespace, declare the pub impl in that namespace rather than importing it privately from elsewhere.

Contract Operation Method Lookup

Fields and inherent methods share the ordinary member namespace. Inherent members win over contract operations considered for method-call lookup:

buf.len() // Buffer.len if it exists

If no inherent member exists, visible contract operations from implemented contracts may participate in method-call lookup:

buf.len() // Sequence(f32).len if uniquely available

If multiple visible contract operations provide the same member name, lookup is ambiguous:

buf.len() // error: multiple visible contract operations named `len`

The programmer can resolve ambiguity with an inherent forwarding method or a qualified contract call:

Sequence(f32).len(&buf)

Qualified contract calls are V1 syntax. The expression before the final member name is a fully applied semantic contract Type; the member name selects one operation identity from that contract surface; the receiver is passed explicitly as the first argument:

Iterator(Item).next(&iter)
PartialEq(Point).eq(&a, &b)
Sequence(T).len(xs)

Qualified calls do not search structurally for matching members. The receiver type must visibly implement the named applied contract, or be a borrowed dynamic object whose visible erased surface includes that contract operation. Concrete receiver contract calls dispatch statically. Calls through *dyn C or *const dyn C dispatch dynamically through the visible erased surface. For dynamic intersections, a qualified call may select a visible component operation directly without first upcasting the receiver to that component.

Qualified calls are the explicit escape hatch for ambiguous contract operation method lookup, generated lowering, diagnostics, and generic helpers. Normal code should prefer ordinary method or operator syntax when lookup is unambiguous.