---
title: "Anonymous Enums"
scope: "core"
kind: "reference"
category: "features"
aliases:
  - "anonymous enum"
  - "legacy tuple migration"
id: core/features/anonymous-enums
parent: core/features
---

# Anonymous Enums

Anonymous enums are short-lived tagged values that do not need a named
`defenum` declaration. Use `_` in the definition position:

```cirru
let
    value $ %:: _ :point 10 20
  println value
  ; => $ %:: _ :point 10 20
```

The `_` marker makes the missing definition explicit. The old “tuple” name and
`&tuple:*` native APIs have been removed; diagnostics point to their `enum`
replacements.

## Accessing Values

Use `&enum:nth` when positional access is genuinely appropriate. Index `0` is
the variant tag and payload values begin at index `1`.

```cirru
let
    value $ %:: _ :point 10 20
  assert= :point $ &enum:nth value 0
  assert= 10 $ &enum:nth value 1
  assert= 3 $ &enum:count value
```

Anonymous enum access remains bounds-checked and reports ordinary diagnostics;
it never relies on unchecked indexing.

## Matching

Native `match` can match an anonymous enum even though no definition is
available for exhaustiveness analysis:

```cirru
let
    value $ %:: _ :point 10 20
  assert= 30 $ match value
    (:point x y) (+ x y)
    _ 0
```

从 Calcit 0.14.16 起，`tag-match` 已从表层语言移除；具名与匿名 enum 都直接使用原生
`match`。旧代码应先使用 Calcit 0.14.15 执行
`calcit fix --rule tag-match-to-match-v1` 再升级。对于领域数据，仍建议优先使用具名
enum，让编译器检查 variant、payload arity 与穷尽性：

```cirru
let
    Shape $ defenum Shape (:point Number Number) (:none)
    value $ Shape :point 10 20
  assert= 30 $ match value
    (:point x y) (+ x y)
    (:none) 0
```

## Named Conversion

When the expected function parameter type is a named enum, the preprocessor can
rewrite `%:: _ :variant ...` to that named definition. Variant and payload
validation then use the target `defenum` declaration.

## Migration

Use these replacements when upgrading older code:

| Removed spelling | Replacement |
| --- | --- |
| tuple value / `:tuple` | enum value / `:enum` |
| `tuple?` | `enum?` for values, `enum-def?` for definitions |
| `tuple-enum` | `enum-definition` |
| `&tuple:nth` | `&enum:nth` |
| `&tuple:count` | `&enum:count` |
| `&tuple:assoc` | `&enum:assoc` |
| `&tuple:*` | corresponding `&enum:*` API |

Compatibility readers may still load historical snapshots, but newly written
schemas and source should use `Enum`, `EnumDef`, `enum`, and `enum-def` names.

## See Also

- [Enums](enums.md) — named enums declared with `defenum`
- [Structs](structs.md) — fixed named fields declared with `defstruct`
- [Static Analysis](static-analysis.md) — enum payload and match checking
