trait Map[K, V]), and a standard Map trait the ecosystem can build onOpen and answer this issue on GitHub.
language, decision · opened 2026-10-12 · updated 2026-10-12 · 1 comment
A trait says what a type must be able to do, so different types can be used the same way (Part I 4.7). Nikaia’s traits cannot take type parameters. The owner would like a standard Map trait for the ecosystem: one lowest-common-denominator interface so libraries can accept “a map” and be written against a shared standard, as other languages offer (Rust has none for maps; Java Map, C# IDictionary, Go map built in, Swift Dictionary/protocols, Kotlin Map). This is not needed by the repository’s own code or self-hosting; the point is to let libraries share one interface while staying fast.
trait Map[K, V] {
fn len(ref self) -> i64
fn contains_key(ref self, key: ref K) -> bool
fn get(ref self, key: ref K) -> V?
fn insert(ref mut self, key: K, value: V)
fn remove(ref mut self, key: ref K) -> V?
fn clear(ref mut self)
}
fn total[M: Map[String, i64]](m: ref M) -> i64 { return m.len() }
trait Map[K, V] { … } is a parse error: Expected { here, but found [. Traits have no type parameters.dyn), and there are no associated types.impl Trait for collections::BTreeMap[String, i64] is allowed (4.7: a trait is how a std type gets methods), but the probe for it was refused with NK2302 on self.contains_key(key) (“keeps key”), which is #585 item 4, not this issue.get_mut(&mut self) -> Option<&mut V> has no equivalent: no ref mut result (import-rust-design.md §7).The owner, in the #589 session (October 12, 2026), after the question whether a BTreeMap can be passed where a HashMap is wanted (it cannot: NK1102; they are two types, and the hasher of a HashMap is chosen by the compiler per ADR-010 D5/D9). Nothing concrete needs it now: it is ecosystem design.
Iterator-like, Stream[T], Repository[T]) needs them. Parser, ledger (a trait entry with parameters), bound checking (NK1164 with arguments), lowering (Rust traits are generic already) all change.HashMap is two Rust types (TrustedMap / keyed) chosen by the compiler; after #581 a hidden type parameter at package boundaries. A Map trait implemented for HashMap must cover that without the user naming either. #581 should land first or define the interaction.Map[K, V] for both families needs K: Hash + Eq for one and K: Ord for the other. Without named bounds the trait could only be implemented for a fixed key type. See the std-bounds issue (filed beside this one).get(ref self, key: ref K) -> V? returns something that may point into the map; the NK2302 rules (ADR-283 D25) make “a result into self only” the natural reading, but a trait method has no body, so D25 uses the receiver. ref mut results do not exist, so no get_mut; mutation goes through insert/update shapes.dyn), so a generic function over M: Map[K, V] costs nothing over the concrete map. A dyn Map would cost an indirection and is not on offer.Map[K, V] is an ordinary library trait in std::collections with impls for HashMap/BTreeMap. Needs the std-bounds decision for the key.Map trait only (the compiler special-cases it). Quick, but a second mechanism and not available to libraries for their own interfaces.(a) is a large, irreversible language addition and the first step toward associated types/default bodies/dyn, each requested later (“the pressure of import rust”, import-rust-design.md §7). The language’s stance is fewer features on purpose; generics for traits are the one Rust feature most libraries cannot work around, which argues for (a) rather than (b). A trait shared by the ecosystem is also hard to change after libraries adopt it: a method added later breaks every impl.
Missing: how Go/Swift/Kotlin/Zig do shared collection interfaces and what they paid; the NK2302 rules for a generic trait method; the interaction with #581; a measured cost (none expected, monomorphised). Prepare that basis first; this issue is the place for it.
File and keep as decision; take the std-bounds issue first (smaller, needed by this), then prepare (a) with the interaction with #581. Do not build anything yet.
Related: #581, #585, #589 (built), #514, and the std-bounds and HashMap-key issues filed beside this one.
The issues “filed beside this one” are: #591 (a HashMap/HashSet key that cannot be hashed passes the checker) and #592 (the std bounds Ord/Eq/Hash cannot be named). Take #592 first.
Generated by Claude Code