Go Generics Laboratory

Lesson, slides, and applied problem sets.

View Slides

Lesson

Go Generics Laboratory

This module moves from "what generics look like" to "how to write API-friendly generics".

1) Type parameters are constraints-first design

Start with constraints, not types.

  • Are you deduplicating by keys? you need comparable.
  • Are you calculating max/min? you need ordered operations.
  • Are you transforming values? prefer narrow ~ constraints if you need aliases.

If constraints are too broad, compile-time checks become weaker and code paths become less precise.

2) The ~ operator in type sets

  • ~int means "any type whose underlying type is int."
  • This helps support type MyInt int without forcing a cast.

Use this when you want APIs that feel custom-type friendly.

3) Two-parameter patterns with slice return types

For data-shaping helpers, one parameter often controls element type, one controls caller-facing alias.

Example: func F[S ~[]T, T any](in S) S

This preserves a typed alias like: type IDs []int and returns IDs, not just []int.

4) API shape: keep semantics explicit

For generic helpers:

  • keep argument shape obvious
  • avoid hidden behavior
  • document zero values and nil cases

The caller should infer why a result changed, not reverse engineer your constraints.

5) Performance notes for generics

Generics are not always slower and not always faster:

  • some monomorphized specializations are excellent,
  • some are optimized poorly when constraints are loose,
  • and any can erode compile-time specialization.

Benchmark against hand-written versions if this is in a hot path.

6) Practical exercise

The module practice problem asks you to build DeduplicateByKey with:

  • stable order retention,
  • first-seen semantics,
  • generic key extraction,
  • custom slice type preservation via a second type parameter.

This demonstrates:

  • higher-order constraints,
  • map-backed dedupe,
  • practical generic API ergonomics in real learner workflows.

7) Self-check before moving on

  • Can your function accept aliases like type RowSlice []Row?
  • Do you preserve first occurrence order?
  • Does zero input return zero output predictably?

Module Items

Join Discord