# Nim Type System Faq

> Nim type system patterns and pitfalls

- Skill: `mratsim/nim-type-system-faq` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mratsim/nim-type-system-faq`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mratsim/nim-type-system-faq/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: MIT
- Author: mratsim (https://skillmd.com/u/mratsim)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mratsim/nim-type-system-faq

---


## Problem: Union types in generics require same concrete type

When you define a generic with a union type like `T: int|Nullopt_t`, Nim requires ALL parameters of that type to be the SAME concrete type:

```nim
template handleNegativeIndex[T: int|Nullopt_t](idx: T, axisLen: int): T =
  when idx is Nullopt_t:
    idx
  else:
    if idx < 0:
      idx + axisLen
    else:
      idx
```

- Calling `handleNegativeIndex(start, len)` with `start: int`
  and `nullopt` for `stop` fails: `int` and `Nullopt_t` are
  different types even though both belong to the union.

## Solution: Use `distinct` type

Define a distinct wrapper type that "unifies" the union:

```nim
type OptInt* = distinct int | Nullopt_t

template handleNegativeIndex*[T: int|Nullopt_t](idx: T, axisLen: int): T =
  when idx is Nullopt_t:
    idx
  else:
    if idx < 0:
      idx + axisLen
    else:
      idx

func normalizedSlice*(
        start, stop: distinct OptInt,
        step: OptInt = nullopt, axisLen: int): TorchSlice {.inline.} =
  let normStart = handleNegativeIndex(start, axisLen)
  let normStop = handleNegativeIndex(stop, axisLen)
  torchSlice(normStart, normStop, step)
```

`distinct` creates a new type with these effects:
1. Is compatible with all types in the union at runtime
2. Allows parameters to have DIFFERENT concrete types from the same union
3. Preserves type safety while enabling flexible APIs

## When to use this pattern

- API functions that accept either a value OR "none"/"default"
- Slice/indexing functions where parameters can be int or nullopt
- Callbacks that may receive typed or untyped values

## Related patterns

- `option[T]` from stdlib for explicit optional values
- `nullopt` singleton for "no value provided"
- `when defined(T)` branches for type-specific logic

