Hey! These docs are for version 2.8, which is no longer officially supported. Click here for the latest version, 2.18!

Union rules solve the same problem that polymorphism solves in general: how to write generic code that operates on types not known about at the time of writing.

For example, Pants has many generic goals like `lint` and `test`. Those `@goal_rule` definitions cannot know about every concrete linter or test implementation ahead-of-time.

Unions allow a specific linter to be registered with `UnionRule(LintRequest, ShellcheckRequest)`, and then for `lint.py` to access its type:

This example will find all registered linter implementations by looking up `union_membership[LintRequest]`, which returns a tuple of all `LintRequest` types that were registered with a `UnionRule`, such as `ShellcheckRequest` and `Flake8Request`.

## How to create a new Union

To set up a new union, create a class for the union "base". Typically, this should be an [abstract class](🔗) that is subclassed by the union members, but it does not need to be. Mark the class with `@union`.

Then, register every implementation of your union with `UnionRule`:

Now, your rules can request `UnionMembership` as a parameter in the `@rule`, and then look up `union_membership[Vehicle]` to get a tuple of all relevant types that are registered via `UnionRule`.