<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/implementing-type-contracts-via-mutually-referencing-type-parameters-sdleexg2r" -->

---
title: Implementing Type Contracts via Mutually Referencing...
description: A deep dive into how Dolt implements a shared data model for MySQL&#x27;s AUTO_INCREMENT and Postgres&#x27;s SERIAL/Sequence semantics across its Dolt and Doltgres...
canonical: https://daily.dev/posts/implementing-type-contracts-via-mutually-referencing-type-parameters-sdleexg2r
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Implementing Type Contracts via Mutually Referencing Type Parameters | daily.dev
og:description: A deep dive into how Dolt implements a shared data model for MySQL&#x27;s AUTO_INCREMENT and Postgres&#x27;s SERIAL/Sequence semantics across its Dolt and Doltgres...
og:url: https://daily.dev/posts/implementing-type-contracts-via-mutually-referencing-type-parameters-sdleexg2r
og:image: https://api.daily.dev/og/posts/sdlEEXg2r.png
og:image:alt: Implementing Type Contracts via Mutually Referencing Type Parameters
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Implementing Type Contracts via Mutually Referencing Type Parameters

**[DoltHub Blog](https://daily.dev/sources/dolthub-blog)** · 12 min read · 3 upvotes · 0 comments

## Summary

A deep dive into how Dolt implements a shared data model for MySQL's AUTO_INCREMENT and Postgres's SERIAL/Sequence semantics across its Dolt and Doltgres products, then generalizes the underlying Go language problem: how to express a contract that spans multiple mutually-related types. The piece walks through failed approaches (plain interfaces, a single generic interface wrapping all types) before landing on mutually referential type parameters, a technique from Go's original type parameters proposal, and explains how Go 1.26's recursive/self-referential type constraints make interface definitions more self-documenting without adding further type safety. The author also revisits and corrects mistakes from an earlier blog post on the same topic.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://dolthub.com/blog/2026-08-28-mutually-referencing-type-parameters>

## Questions this post answers

### How do I write a Go generic contract that spans two mutually related types, like a mutable and immutable pair?

Define each type as a generic interface with an any-typed parameter (for example ImmutableValue[T any] with a Mutate() T method, and MutableValue[T any] with a Flush() T method), then reference them against each other only at the point of use, in a generic function's type parameter list, such as ApplyMutations[ImmutableType ImmutableValue[MutableType], MutableType MutableValue[ImmutableType]]. This keeps the interface definitions simple while making the calling function fully type-safe.

_daily.dev surfaces practical Go generics patterns like this for engineers designing type-safe shared code._

### What changed with self-referential type constraints in Go 1.26?

Go 1.26 added recursive type parameters, allowing an interface's type constraint to reference the interface type being defined itself, for example SequenceState[Self SequenceState[Self, ValueType], ValueType any]. This makes interface definitions more self-documenting, but it does not reduce the type constraints that must still be duplicated in every function or struct that uses those interfaces, nor does it add additional type safety beyond what was already possible since Go 1.18.

_developers tracking Go generics changes across versions can follow releases like this on daily.dev before upgrading._

### What is the difference between MySQL AUTO_INCREMENT and Postgres SERIAL columns?

MySQL AUTO_INCREMENT values are always unsigned, while Postgres SERIAL values are always signed. Postgres SERIAL columns are backed by a Sequence data type with configurable parameters such as minimum and maximum values, increment or decrement direction, and whether values wrap around when they reach the end, none of which exist for MySQL's simpler AUTO_INCREMENT mechanism.

_engineers comparing MySQL and Postgres behavior can track these nuances on daily.dev when choosing a database._

## Similar posts on daily.dev

- [What's New With Golang Generics](https://daily.dev/posts/what-s-new-with-golang-generics-vxxadjrrz) · DoltHub Blog · 18 upvotes · 2 comments

---

Tags: [#golang](https://daily.dev/tags/golang), [#type-systems](https://daily.dev/tags/type-systems)

[View this post on daily.dev](https://daily.dev/posts/implementing-type-contracts-via-mutually-referencing-type-parameters-sdleexg2r)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Implementing Type Contracts via Mutually Referencing Type Parameters","url":"https://daily.dev/posts/implementing-type-contracts-via-mutually-referencing-type-parameters-sdleexg2r","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/implementing-type-contracts-via-mutually-referencing-type-parameters-sdleexg2r"},"datePublished":"2026-08-31T20:13:27.640Z","dateModified":"2026-08-31T21:02:19.476Z","description":"A deep dive into how Dolt implements a shared data model for MySQL's AUTO_INCREMENT and Postgres's SERIAL/Sequence semantics across its Dolt and Doltgres...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/3e59a6d0b3b7332f42369ed31f304cff?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/3e59a6d0b3b7332f42369ed31f304cff?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"DoltHub Blog","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"DoltHub Blog","logo":"https://media.daily.dev/image/upload/s--LXDlvjS4--/f_auto,q_auto/v1780213587/logos/dolthub-blog?_a=BAMAMiWQ0","url":"https://daily.dev/sources/dolthub-blog"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/implementing-type-contracts-via-mutually-referencing-type-parameters-sdleexg2r","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":3},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"golang,type-systems","timeRequired":"PT12M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"DoltHub Blog","item":"https://daily.dev/sources/dolthub-blog"},{"@type":"ListItem","position":3,"name":"Implementing Type Contracts via Mutually Referencing Type Parameters"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/implementing-type-contracts-via-mutually-referencing-type-parameters-sdleexg2r#faq","mainEntity":[{"@type":"Question","name":"How do I write a Go generic contract that spans two mutually related types, like a mutable and immutable pair?","acceptedAnswer":{"@type":"Answer","text":"Define each type as a generic interface with an any-typed parameter (for example ImmutableValue[T any] with a Mutate() T method, and MutableValue[T any] with a Flush() T method), then reference them against each other only at the point of use, in a generic function's type parameter list, such as ApplyMutations[ImmutableType ImmutableValue[MutableType], MutableType MutableValue[ImmutableType]]. This keeps the interface definitions simple while making the calling function fully type-safe. daily.dev surfaces practical Go generics patterns like this for engineers designing type-safe shared code."}},{"@type":"Question","name":"What changed with self-referential type constraints in Go 1.26?","acceptedAnswer":{"@type":"Answer","text":"Go 1.26 added recursive type parameters, allowing an interface's type constraint to reference the interface type being defined itself, for example SequenceState[Self SequenceState[Self, ValueType], ValueType any]. This makes interface definitions more self-documenting, but it does not reduce the type constraints that must still be duplicated in every function or struct that uses those interfaces, nor does it add additional type safety beyond what was already possible since Go 1.18. developers tracking Go generics changes across versions can follow releases like this on daily.dev before upgrading."}},{"@type":"Question","name":"What is the difference between MySQL AUTO_INCREMENT and Postgres SERIAL columns?","acceptedAnswer":{"@type":"Answer","text":"MySQL AUTO_INCREMENT values are always unsigned, while Postgres SERIAL values are always signed. Postgres SERIAL columns are backed by a Sequence data type with configurable parameters such as minimum and maximum values, increment or decrement direction, and whether values wrap around when they reach the end, none of which exist for MySQL's simpler AUTO_INCREMENT mechanism. engineers comparing MySQL and Postgres behavior can track these nuances on daily.dev when choosing a database."}}]}
```

