A self-similar structure: a value of S whose immediate sub-terms are themselves S. The single member plate is a Traversal[S, S] focusing those immediate children — the cats-eo analogue of Haskell lens's Plated class (plate :: Traversal' a a).
The recursion combinators in the companion (Plated.transform, Plated.rewrite, Plated.children, Plated.universe) build on plate to walk the whole tree. They are stack-safe on deep trees: transform recurses on the call stack while shallow and falls back to a heap-stack machine past a depth bound, rewrite trampolines through cats.Eval, and universe / children use an explicit worklist — a degenerate 100k-deep tree is fine.
The children are carried as a PSVec (the MultiFocus[PSVec] carrier's focus vector), so the read path and the write path share one representation with no List round-trips — see childrenVec.
Get an instance by hand via Plated.fromChildren / Plated.fromChildrenVec, by deriving one with dev.constructive.eo.generics.plate[S], or — when you have already built the self-traversal as an optic — by calling .asPlated on it (see the extension methods below).
The immediate children as a fresh Array[AnyRef] the caller may mutate in place. The default copies (childrenVec(s).toAnyRefArray) so it is safe for any instance; Plated.fromChildrenVec overrides it to hand back the freshly-built backing array copy-free. The recursion-scheme cata engine folds each child's result into this array in place, reusing the one array instead of allocating a separate result accumulator per node.
The immediate children as a fresh Array[AnyRef] the caller may mutate in place. The default copies (childrenVec(s).toAnyRefArray) so it is safe for any instance; Plated.fromChildrenVec overrides it to hand back the freshly-built backing array copy-free. The recursion-scheme cata engine folds each child's result into this array in place, reusing the one array instead of allocating a separate result accumulator per node.
Immediate children as a PSVec — the representation both the read path (Plated.children / Plated.universe) and the write path (Plated.transform / Plated.rewrite, through the carrier) share. Defaults to reading the carrier directly (plate.to(s)._2); Plated.fromChildren / Plated.fromChildrenVec (hence every generics.plate[S]-derived instance) override it to return the children with no tuple allocation. Either way nothing is converted to a List and back — that round-trip was the read/write hot-path tax.
Immediate children as a PSVec — the representation both the read path (Plated.children / Plated.universe) and the write path (Plated.transform / Plated.rewrite, through the carrier) share. Defaults to reading the carrier directly (plate.to(s)._2); Plated.fromChildren / Plated.fromChildrenVec (hence every generics.plate[S]-derived instance) override it to return the children with no tuple allocation. Either way nothing is converted to a List and back — that round-trip was the read/write hot-path tax.
Reassemble parent with children swapped in (same arity / order) — the write-path counterpart to childrenVec. Defaults to threading the carrier; Plated.fromChildren / Plated.fromChildrenVec (hence every generics.plate[S]-derived instance) override it with the raw rebuild function so Plated.transform rebuilds without allocating the carrier's (x, PSVec) tuple per node. On the default (.asPlated) path this and childrenVec each call plate.to, so a transform over a hand-built optic pays two to calls per internal node — derived / fromChildrenVec instances override both and pay none.
Reassemble parent with children swapped in (same arity / order) — the write-path counterpart to childrenVec. Defaults to threading the carrier; Plated.fromChildren / Plated.fromChildrenVec (hence every generics.plate[S]-derived instance) override it with the raw rebuild function so Plated.transform rebuilds without allocating the carrier's (x, PSVec) tuple per node. On the default (.asPlated) path this and childrenVec each call plate.to, so a transform over a hand-built optic pays two to calls per internal node — derived / fromChildrenVec instances override both and pay none.