ExamplesBy LevelBy TopicLearning Paths
143 Advanced

Associated Type Bounds

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "Associated Type Bounds" functional Rust example. Difficulty level: Advanced. Key concepts covered: Functional Programming. When a trait has associated types, callers often need to constrain those associated types — "give me an iterator whose items are `Clone`" or "give me a container whose element type implements `Display`." Before Rust 1.79, this required verbose `where Item: Clone` clauses in every bound. Key difference from OCaml: 1. **Syntax location**: Rust's associated type bounds are inline in the trait reference; OCaml's `with type` constraints are applied at the module signature level.

Tutorial

The Problem

When a trait has associated types, callers often need to constrain those associated types — "give me an iterator whose items are Clone" or "give me a container whose element type implements Display." Before Rust 1.79, this required verbose where Item: Clone clauses in every bound. Associated type bounds (Iterator<Item: Clone>) compress this into the bound itself, making complex generic signatures readable and reducing repetition in library code.

🎯 Learning Outcomes

  • • Understand associated types in traits and why they are preferred over type parameters for output types
  • • Learn the associated type bound syntax Trait<AssocType: Bound> (stabilized in Rust 1.79)
  • • See how associated type bounds simplify generic function signatures
  • • Compare with where clauses and understand when each form is clearest
  • Code Example

    #![allow(clippy::all)]
    // Stub — awaiting conversion from OCaml source.

    Key Differences

  • Syntax location: Rust's associated type bounds are inline in the trait reference; OCaml's with type constraints are applied at the module signature level.
  • Expressiveness: Both can express "this associated type must implement this constraint"; Rust's is terser for simple cases, OCaml's is more powerful for complex module constraints.
  • Inference: Rust infers the concrete associated type from the concrete implementation; OCaml's module system similarly infers types through with type elaboration.
  • Error messages: Both can produce complex error messages when associated type constraints conflict; Rust 1.79+ improved this significantly with the new bound syntax.
  • OCaml Approach

    OCaml's module system handles associated type constraints via module type constraints:

    module type CONTAINER = sig
      type t
      type item
      val items : t -> item list
    end
    module type DISPLAY_CONTAINER = CONTAINER with type item = string
    

    The with type refinement is OCaml's mechanism for constraining associated types. Functors then take modules satisfying specific refined signatures. This is more verbose than Rust's inline bound syntax but is the standard OCaml pattern.

    Full Source

    #![allow(clippy::all)]
    // Stub — awaiting conversion from OCaml source.

    Deep Comparison

    OCaml vs Rust: Associated Type Bounds

    Overview

    See the example.rs and example.ml files for detailed implementations.

    Key Differences

    AspectOCamlRust
    Type systemHindley-MilnerOwnership + traits
    MemoryGCZero-cost abstractions
    MutabilityExplicit refmut keyword
    Error handlingOption/ResultResult<T, E>

    See README.md for detailed comparison.

    Exercises

  • Write fn find_max<C: Container<Item: Ord>>(c: C) -> Option<C::Item> using associated type bounds, returning the largest element.
  • Implement a Mappable trait with type Item and fn map<B>(self, f: impl Fn(Self::Item) -> B) -> Self::Mapped<B> using GATs.
  • Create fn collect_display<I: Iterator<Item: Display + Clone>>(it: I) -> Vec<String> and test it with vec!["a", "b"].into_iter().
  • Open Source Repos