ExamplesBy LevelBy TopicLearning Paths
145 Advanced

GAT Collections

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "GAT Collections" functional Rust example. Difficulty level: Advanced. Key concepts covered: Functional Programming. A truly generic collection trait in Rust — one where `map` changes the element type — requires GATs. Key difference from OCaml: 1. **Native vs. GAT**: OCaml's `'a t` is a native parameterized type constructor; Rust requires the GAT feature to express the same concept in traits.

Tutorial

The Problem

A truly generic collection trait in Rust — one where map changes the element type — requires GATs. Without them, you cannot express "a Vec<T> mapped by T -> U produces Vec<U>" in a trait that also applies to HashMap<K, V>, BTreeSet<T>, and custom containers. GAT collections resolve this by making the container's output type generic over the element type, enabling unified generic algorithms over diverse collection types.

🎯 Learning Outcomes

  • • Learn how GATs enable type Mapped<U> in collection traits, changing element types through map
  • • Understand the difference between a homogeneous collection trait and a GAT-based one
  • • See how Functor for collections is expressed using GATs in Rust
  • • Practice implementing GAT-based traits for Vec<T> and Option<T>
  • Code Example

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

    Key Differences

  • Native vs. GAT: OCaml's 'a t is a native parameterized type constructor; Rust requires the GAT feature to express the same concept in traits.
  • Verbosity: OCaml's COLLECTION signature is terse; Rust's equivalent requires explicit type Item, type Mapped<U>, and where bounds.
  • Stability: OCaml's pattern is decades old; Rust's GATs stabilized in 1.65 and still have some rough edges around lifetime inference.
  • Key-value containers: Extending to HashMap<K, V> requires handling two type parameters; GATs handle this with type Mapped<K2, V2>.
  • OCaml Approach

    OCaml expresses this naturally:

    module type COLLECTION = sig
      type 'a t
      val map : ('a -> 'b) -> 'a t -> 'b t
      val filter : ('a -> bool) -> 'a t -> 'a t
    end
    module ListCollection : COLLECTION with type 'a t = 'a list = struct ... end
    

    The parameterized type 'a t is OCaml's built-in equivalent of Rust's GAT type Mapped<U>. This pattern is fundamental to OCaml's standard library design.

    Full Source

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

    Deep Comparison

    OCaml vs Rust: Gat Collections

    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

  • Implement Collection for Option<T> with type Mapped<U> = Option<U>.
  • Add a flat_map_col<U>(self, f: impl Fn(Self::Item) -> Self::Mapped<U>) -> Self::Mapped<U> method to the trait.
  • Write a generic double_all<C: Collection<Item = i32>>(c: C) -> C::Mapped<i32> that doubles every element.
  • Open Source Repos