Skip to content

Volume 08: Protocols

1. Introduction

This volume defines protocols in the Rethon programming language. It describes protocol declarations, protocol names, protocol requirements, method requirements, property requirements, associated types, protocol conformance, explicit conformance, struct conformance, class conformance, generic constraints, protocol composition, protocol inheritance, existential types, equality and hashing protocols, dispatch considerations, and future extension points.

This document is part of the official Rethon Language Specification. It is normative rather than descriptive. Implementations, tooling, documentation systems, and other source-processing tools shall treat the rules in this volume as authoritative.

This volume does not define backend dispatch tables, witness-table layout, ABI details, or runtime-specific representation mechanisms. It defines the source-level and language-level behavior of protocols as programmer-visible behavior contracts.

Rethon is Python-inspired in language philosophy and Python-first in surface syntax where practical. It uses static typing, protocols as behavior contracts, structs as value types, classes as reference types, protocol-oriented design, value-oriented design, memory safety by default, and ownership transparency. Protocols are the primary abstraction mechanism in Rethon.

Protocols shall describe behavior, not storage.

Protocols shall be preferred over inheritance.

2. Protocol Declarations

A protocol declaration shall introduce a named behavior contract.

A protocol declaration shall use the protocol keyword.

Example:

protocol Printable:
    def print(self) -> None

A protocol declaration shall define requirements that conforming types must satisfy.

A protocol declaration shall introduce a new type name and a new requirement scope for the members declared within its body.

A protocol declaration may appear at module scope or within other later-defined type or namespace constructs if the surrounding syntax permits it.

A protocol body may contain method requirements, property requirements, associated type declarations, and inherited protocol declarations.

A protocol body shall use indentation-based structure.

A protocol declaration shall be a declaration in the sense defined by the declarations and bindings volume.

A protocol shall not define instance storage.

A protocol shall not define object state.

A protocol shall define a contract that other types may explicitly adopt.

3. Protocol Names

A protocol name shall be an identifier that names the protocol declaration.

Protocol names shall be case-sensitive.

Protocol names should normally use PascalCase.

Examples:

protocol Printable:
    def print(self) -> None

protocol Hashable:
    def hash(self) -> int

A protocol name shall not be reserved solely because it names a protocol. Ordinary identifier rules shall apply, subject to keyword reservation and any later contextual restrictions defined by the language.

A protocol name should clearly express the behavior or capability being modeled.

Protocol names should describe capabilities such as formatting, comparison, hashing, iteration, serialization, conversion, or other abstract behaviors.

Examples of preferable naming patterns include:

  • Printable
  • Hashable
  • Comparable
  • Iterable
  • Serializable
  • Cloneable

A protocol name should not obscure meaning through unnecessary abbreviation when a clearer name is available.

4. Protocol Requirements

A protocol requirement is a member that conforming types must provide.

Protocols may declare zero or more requirements.

A protocol requirement may be a method requirement, property requirement, or associated type requirement.

Example:

protocol Drawable:
    def draw(self) -> None

Protocol requirements shall describe observable behavior, not storage implementation.

Protocol requirements shall be expressed in source form that is compatible with the language's static typing and readable syntax goals.

A protocol requirement shall be satisfied by an explicit member on the conforming type or by another language-defined mechanism that is itself explicit and statically checkable.

A protocol shall not require hidden storage or secret runtime state from conforming types.

Protocols may include requirements that are inherited from other protocols.

5. Method Requirements

A protocol may require methods.

Example:

protocol Printable:
    def print(self) -> None

A method requirement shall specify the method name, parameter structure, and return type expected of conforming types.

A method requirement shall not specify a body in ordinary protocol declarations.

A method requirement may refer to self or another explicit receiver form if the language's member syntax requires one.

Method requirements shall be type-checked against conforming types during conformance analysis.

A method requirement shall be satisfied when the conforming type provides a compatible method according to the language's method compatibility rules.

Method requirements may be generic and may refer to associated types or protocol constraints when appropriate.

6. Property Requirements

A protocol may require properties.

Example:

protocol Named:
    name: str

A property requirement shall specify a named value that conforming types must provide.

Property requirements shall describe observable access to data, not necessarily stored fields.

A property requirement shall not require a specific storage strategy.

A property requirement may be read-only or read-write if later specification work defines those distinctions for protocol members.

A property requirement shall be satisfied when the conforming type exposes a compatible property or field-like member according to the language's conformance rules.

Property requirements shall remain compatible with structs and classes alike.

7. Associated Types

A protocol may declare associated types.

Example:

protocol Iterable:
    associatedtype Item
    def next(self) -> Item?

An associated type is a named type placeholder that a conforming type must bind during conformance.

Associated types shall be part of the protocol's contract and may be referenced by protocol requirements.

Associated types shall support generic and reusable abstractions without forcing the protocol to commit to a single concrete type argument.

A conforming type shall provide or satisfy each associated type according to the language's conformance rules.

Associated types shall be usable in generic constraints and protocol compositions.

8. Protocol Conformance

Protocol conformance shall be explicit.

A type shall conform to a protocol only when the source declares that conformance or when a later language rule explicitly defines another explicit conformance path.

Example:

class Logger: Printable:
    def print(self) -> None:
        ...

A conforming type shall satisfy all required members and associated types of the protocol.

Conformance shall be checked statically.

Conformance shall not be inferred merely from structural similarity unless the language explicitly defines a future structural-conformance rule for a specific context.

Protocol conformance shall be available to both structs and classes.

Protocol conformance shall be the preferred mechanism for shared behavior and polymorphic APIs.

9. Explicit Conformance

Explicit conformance shall be required in ordinary source code.

A type declaration shall state the protocols it conforms to when the language syntax permits such a declaration.

Example:

struct Point: Printable, Hashable:
    x: int
    y: int

Explicit conformance makes behavior contracts visible at the declaration site and supports static analysis, tooling, and readability.

A conformance declaration shall not imply storage or runtime machinery beyond the language's source-level contract.

A type may conform to multiple protocols when all requirements are satisfied.

10. Struct Conformance

Structs shall be able to conform to protocols.

Example:

struct Point: Printable:
    x: int
    y: int

    def print(self) -> None:
        ...

Struct conformance shall support value-oriented design by allowing data types to adopt reusable behavior contracts without becoming reference types.

A struct shall satisfy protocol requirements through its explicitly declared members.

Struct conformance shall remain compatible with value semantics, copy semantics, and the field rules established elsewhere in the specification.

11. Class Conformance

Classes shall be able to conform to protocols.

Example:

class Logger: Printable:
    def print(self) -> None:
        ...

Class conformance shall support reference-oriented design by allowing identity-bearing objects to adopt reusable behavior contracts.

A class shall satisfy protocol requirements through its explicitly declared members.

Class conformance shall remain compatible with reference semantics, initialization rules, and the field rules established elsewhere in the specification.

12. Generic Constraints

Protocols shall be usable as generic constraints.

Example:

def print_item<T: Printable>(item: T) -> None:
    item.print()

A generic constraint may require that a type conform to one or more protocols.

A generic constraint may refer to associated types, protocol compositions, and protocol inheritance chains when permitted by the language's generic rules.

Protocols are the canonical way to express behavior-based requirements for generic code.

Generic constraints shall remain statically checkable and compatible with the language's specialization goals.

13. Protocol Composition

Protocols shall support composition.

Example:

type PrintableHashable = Printable & Hashable

A protocol composition shall represent the combined requirements of its member protocols.

A type that conforms to a composition shall satisfy all requirements of each composed protocol.

Protocol composition shall be usable in type positions and generic constraints when the language syntax permits it.

Protocol composition shall support expressive APIs without forcing the language into inheritance-centric design.

14. Protocol Inheritance

Protocols shall be able to inherit from other protocols.

Example:

protocol Serializable: Printable:
    def serialize(self) -> str

A protocol may extend one or more other protocols, subject to the language's composition and name-resolution rules.

Protocol inheritance shall add requirements to the derived protocol rather than introducing storage or object identity.

Protocol inheritance shall remain a contract-level feature, not an object hierarchy feature.

Protocol inheritance shall be preferred over class inheritance when the goal is to describe related behaviors or layered contracts.

15. Existential Types

Protocols shall support existential type usage.

A value may be treated as satisfying a protocol without the caller naming the value's concrete type.

Example:

let item: Printable = Logger()

An existential protocol type shall represent some value that conforms to the protocol, with the concrete type hidden behind the protocol boundary.

Existential protocol types shall preserve the distinction between the protocol contract and the concrete type that satisfies it.

Existential use shall remain compatible with static typing, protocol conformance, and the language's memory safety goals.

16. Equality and Hashing Protocols

Equality and hashing shall be expressible as explicit protocol-based contracts.

Protocols may define the requirements that a type must satisfy to participate in equality or hashing behavior.

Example:

protocol Equatable:
    def equals(self, other: Self) -> bool

protocol Hashable: Equatable:
    def hash(self) -> int

Equality and hashing shall not be automatic merely because a type is a struct or a class.

If a type participates in equality or hashing, it shall do so through explicit conformance or through a later language-defined synthesis mechanism that remains source-visible and contract-based.

Equality and hashing protocols shall remain consistent with the language's value-oriented and reference-oriented distinctions.

17. Dispatch Considerations

Protocol-based dispatch shall be source-level and contract-based.

The language shall treat protocol calls as operations on values known to satisfy the protocol contract, without exposing backend dispatch machinery in ordinary source code.

The specification does not require a particular dispatch representation such as witness tables, vtables, or indirect call sequences.

Implementations may choose any backend strategy that preserves the observable source-level behavior defined by this volume and the type system.

Dispatch shall remain compatible with static typing, explicit conformance, and the language's performance goals.

18. Future Extensions

This volume defines the current direction for protocols in Rethon, but future specification work may refine the model in carefully controlled ways.

Possible future extensions include:

  • richer property requirement syntax
  • additional constraint forms for associated types
  • explicit variance rules for protocol positions
  • more detailed existential behavior
  • refinement of equality and hashing synthesis rules
  • additional protocol-composition syntax
  • better interoperability between protocols and pattern matching

Any future extension shall preserve the current direction:

  • protocols are behavior contracts
  • protocols do not define storage
  • explicit conformance remains the default model
  • structs and classes may conform
  • protocols are preferred over inheritance
  • protocols are the primary abstraction mechanism
  • generic constraints may use protocols
  • protocol composition and protocol inheritance remain available

19. Summary

Protocols shall be behavior contracts in Rethon.

A protocol shall define requirements that conforming types must satisfy without defining storage or object identity.

Protocol conformance shall be explicit and statically checked.

Structs and classes shall both be able to conform to protocols.

Protocols shall support methods, properties, associated types, generic constraints, composition, inheritance, existential use, and explicit equality and hashing contracts.

Protocols shall therefore serve as the primary abstraction and polymorphism mechanism in Rethon, with inheritance remaining secondary and carefully limited.