Skip to content

Blog post for Extensible Data Types Part 4: Implementing Extensible Variants #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jul 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions content/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Read the blog series **Programming Extensible Data Types in Rust with CGP** for
- [**Part 1: Modular App Construction and Extensible Builders**](/blog/extensible-datatypes-part-1/)
- [**Part 2: Modular Interpreters and Extensible Visitors**](/blog/extensible-datatypes-part-2/)
- [**Part 3: Implementing Extensible Records**](/blog/extensible-datatypes-part-3/)
- [**Part 4: Implementing Extensible Variants**](/blog/extensible-datatypes-part-4/)

# Overview

Expand Down
2 changes: 1 addition & 1 deletion content/blog/2025-07-07-extensible-datatypes-part-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ This article is the first in a five-part series exploring the examples and imple

[**Part 3: Implementing Extensible Records**](/blog/extensible-datatypes-part-3) – Here, we walk through the internal mechanics behind extensible records. We show how CGP supports the modular builder pattern demonstrated in Part 1 through its underlying type and trait machinery.

**Part 4: Implementing Extensible Variants** – This part mirrors Part 3, but for extensible variants. We examine how extensible variants are implemented, and compare the differences and similarities between extensible records and variants.
[**Part 4: Implementing Extensible Variants**](/blog/extensible-datatypes-part-4) – This part mirrors Part 3, but for extensible variants. We examine how extensible variants are implemented, and compare the differences and similarities between extensible records and variants.

# Feature Highlighs

Expand Down
2 changes: 1 addition & 1 deletion content/blog/2025-07-09-extensible-datatypes-part-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ In this second part of the series, we will explore the use of **extensible varia

[**Part 3: Implementing Extensible Records**](/blog/extensible-datatypes-part-3) – Here, we walk through the internal mechanics behind extensible records. We show how CGP supports the modular builder pattern demonstrated in Part 1 through its underlying type and trait machinery.

**Part 4: Implementing Extensible Variants** – This part mirrors Part 3, but for extensible variants. We examine how extensible variants are implemented, and compare the differences and similarities between extensible records and variants.
[**Part 4: Implementing Extensible Variants**](/blog/extensible-datatypes-part-4) – This part mirrors Part 3, but for extensible variants. We examine how extensible variants are implemented, and compare the differences and similarities between extensible records and variants.

# Extending the Visitor Pattern

Expand Down
6 changes: 3 additions & 3 deletions content/blog/2025-07-12-extensible-datatypes-part-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ We will first explore the implementation of extensible records in this part, fol

**Part 3: Implementing Extensible Records** (this post) – Here, we walk through the internal mechanics behind extensible records. We show how CGP supports the modular builder pattern demonstrated in Part 1 through its underlying type and trait machinery.

**Part 4: Implementing Extensible Variants** – This part mirrors Part 3, but for extensible variants. We examine how extensible variants are implemented, and compare the differences and similarities between extensible records and variants.
[**Part 4: Implementing Extensible Variants**](/blog/extensible-datatypes-part-4) – This part mirrors Part 3, but for extensible variants. We examine how extensible variants are implemented, and compare the differences and similarities between extensible records and variants.

# Underlying Theory

Expand Down Expand Up @@ -726,7 +726,7 @@ If any part of this explanation remains unclear, it might be helpful to paste th

With the `BuildFrom` trait in place, we can now explore how CGP implements generalized **builder dispatchers** that enable flexible and reusable ways to assemble struct fields from various sources.

## `BuildWithHandlers` Trait
## `BuildWithHandlers` Provider

In [earlier examples](/blog/extensible-datatypes-part-1/#builder-dispatcher), we used a utility called `BuildAndMergeOutputs` to combine outputs from multiple builder providers such as `BuildSqliteClient`, `BuildHttpClient`, and `BuildOpenAiClient`. Under the hood, `BuildAndMergeOutputs` is built upon a more fundamental dispatcher named `BuildWithHandlers`. The implementation of this dispatcher looks like the following:

Expand Down Expand Up @@ -965,7 +965,7 @@ With this setup, `BuildAndMergeOutputs` can now be used like any other CGP provi

The key benefit of this pattern is that it avoids boilerplate while preserving type safety. Whenever a provider's implementation is simply a thin wrapper around another provider with some added constraints, it's much more convenient to use `DelegateComponent` via `delegate_components!` than to implement the provider trait manually.

## Type-Level CGP Metaprogramming
## Type-Level Metaprogramming

The technique we just explored — wrapping providers and using `delegate_components!` — can be seen as a form of **metaprogramming** in CGP. Here, we’re leveraging **type-level programming** not just within CGP’s core component abstractions like `DelegateComponent`, but also as a tool for *programmatically defining component wiring* through the use of generic parameters and trait constraints.

Expand Down
Loading