Quartz v5.25

Unified Collection API Design

Status: Mostly Implemented | Created: Feb 1, 2026 | Updated: Feb 18, 2026

Overview

This document defines Quartz’s unified collection API — a consistent interface across all collection types (String, Vec, HashMap, Set, Array, StringBuilder). The goal is to provide a “trait-like” experience where common operations have identical syntax regardless of type.

Design Principles:

  1. Property-style access for zero-argument getters (.size, not .size())
  2. UFCS desugaring — methods compile to existing intrinsics, zero runtime overhead
  3. Rename to unified — deprecate prefixed functions (str_len.size)
  4. Compile-time protocols — no runtime trait objects, just consistent naming

Core Protocols

These are conceptual groupings that define which methods a type supports.

Sized Protocol

All collections that have a countable size.

PropertyTypeDescription
.sizeIntNumber of elements
.is_emptyBoolTrue if size == 0

Implementors: String, Vec, HashMap, Set, Array, StringBuilder

Desugaring:

s.size      → str_len(s)       # when s: String
v.size      → vec_len(v)       # when v: Vec<T>
m.size      → hashmap_size(m)  # when m: HashMap<K,V>
s.size      → set_size(s)      # when s: Set<T>
a.size      → arr_len(a)       # when a: Array
sb.size     → sb_len(sb)       # when sb: StringBuilder

x.is_empty  → x.size == 0      # synthesized for all Sized

Pushable Protocol

Collections that support appending elements.

MethodSignatureDescription
.push(x)(T) -> VoidAppend element

Implementors: Vec, StringBuilder

Desugaring:

v.push(x)   → vec_push(v, x)   # when v: Vec<T>
sb.push(s)  → sb_append(sb, s) # when sb: StringBuilder

Poppable Protocol

Collections that support removing the last element.

MethodSignatureDescription
.pop()() -> TRemove and return last

Implementors: Vec

Desugaring:

v.pop()     → vec_pop(v)       # when v: Vec<T>

Indexable Protocol

Collections with keyed access.

SyntaxDescription
x[i]Get element at index/key
x[i] = ySet element at index/key
.get(k)Explicit get (HashMap)
.set(k, v)Explicit set (HashMap)

Implementors: String (read-only), Vec, Array, HashMap

Desugaring:

s[i]        → str_char_at(s, i)       # when s: String (returns Int codepoint)
v[i]        → vec_get(v, i)           # when v: Vec<T>
v[i] = x    → vec_set(v, i, x)        # when v: Vec<T>
m[k]        → hashmap_get(m, k)       # when m: HashMap<K,V>
m[k] = v    → hashmap_set(m, k, v)    # when m: HashMap<K,V>
a[i]        → arr_get(a, i)           # when a: Array
a[i] = x    → arr_set(a, i, x)        # when a: Array

Clearable Protocol

Collections that can be emptied.

MethodSignatureDescription
.clear()() -> VoidRemove all elements

Implementors: Vec, HashMap, Set, StringBuilder

Desugaring:

v.clear()   → vec_clear(v)       # when v: Vec<T>
m.clear()   → hashmap_clear(m)   # when m: HashMap<K,V>
s.clear()   → set_clear(s)       # when s: Set<T>
sb.clear()  → sb_clear(sb)       # when sb: StringBuilder

Deletable Protocol

Collections that support key/element removal.

MethodSignatureDescription
.delete(k)(K) -> VoidRemove by key/element

Implementors: HashMap, Set

Desugaring:

m.delete(k) → hashmap_del(m, k)  # when m: HashMap<K,V>
s.delete(x) → set_delete(s, x)   # when s: Set<T>

Contains Protocol

Collections that support membership testing.

MethodSignatureDescription
.contains(x)(T) -> BoolTrue if element present
.has(k)(K) -> BoolTrue if key present

Implementors: Set (contains), HashMap (has), String (contains)

Desugaring:

s.contains(x) → set_contains(s, x)       # when s: Set<T>
s.contains(n) → str_find(s, n) != -1     # when s: String
m.has(k)      → hashmap_has(m, k)        # when m: HashMap<K,V>

Iterable Protocol (Future)

Collections that support for..in iteration.

SyntaxDescription
for x in collIterate elements

Implementors: Vec, Array, HashMap.keys(), HashMap.values(), Set

Note: Requires iterator desugaring infrastructure. Deferred to Phase 6.

String Methods

String has additional text-specific methods.

Old APINew UFCSNotes
str_len(s)s.sizeSized protocol
str_char_at(s, i)s[i]Returns Int codepoint
str_slice(s, a, b)s.slice(a, b)Future: s[a:b]
str_find(s, needle)s.find(needle)Returns -1 if not found
str_split(s, delim)s.split(delim)Returns Vec
str_concat(a, b)a + bAlready works
str_eq(a, b)a == bAlready works
str_cmp(a, b)a.cmp(b)For ordering
str_to_lower(s)s.downcase()Primary form
str_to_upper(s)s.upcase()Primary form
str_trim(s)s.trim()
str_replace(s, old, new)s.replace(old, new)
str_starts_with(s, p)s.starts_with(p)
str_ends_with(s, p)s.ends_with(p)

Conversion Methods

Old APINew UFCSNotes
str_to_int(s)s.to_i()String to Int
str_from_int(n)n.to_s()Int to String
char_to_string(c)c.to_s()Char (Int) to String

HashMap-Specific Methods

Old APINew UFCSNotes
hashmap_keys(m)m.keys()Returns Vec
hashmap_values(m)m.values()Returns Vec

Migration Strategy

Phase 1: Add UFCS Aliases (Non-Breaking)

Add method resolution for all new UFCS forms. Old prefixed functions continue to work.

# Both work:
str_len(s)   # old
s.size       # new

Phase 2: Compiler Warnings (Soft Deprecation)

Emit warnings when prefixed functions are used:

warning: `str_len(s)` is deprecated, use `s.size` instead

Phase 3: Remove Prefixed Functions (Breaking)

Remove old APIs from public surface. Internal intrinsics remain for UFCS desugaring.

Implementation Checklist

C Bootstrap (typecheck.c)

MethodTypesStatus
.sizeVecDone
.sizeString, HashMapDone
.sizeSet, ArrayDone
.sizeStringBuilderDone
.is_emptyString, HashMapDone
.is_emptyVec, Set, Array, SBDone
.empty?String, Vec, HashMapDone
.pushVecDone
.pushStringBuilderDone (via .append())
.popVecDone
.clearVec, HashMap, Set, SBDone
.deleteHashMapDone
.deleteSetDone
.containsSet, StringPending
.hasHashMapDone
.findStringDone
.sliceStringDone
.splitStringPending
.keysHashMapDone
.valuesHashMapDone
.starts_withStringDone
.ends_withStringDone
.downcaseStringDone
.upcaseStringDone
.trimStringDone
.replaceStringDone
.to_iStringDone
.to_sIntDone
.cmpStringDone
.hashStringDone
.freeVec, HashMap, StringBuilderDone
.getHashMapDone
.setHashMapDone
.get_uncheckedVecDone
.set_uncheckedVecDone
.appendStringBuilderDone
.append_intStringBuilderDone
.append_charStringBuilderDone
.to_stringStringBuilderDone

Self-Hosted (typecheck.qz)

Self-hosted mirrors all C bootstrap UFCS mappings and adds additional methods.

Examples

# Before (inconsistent)
def process(items: Vec<String>, lookup: HashMap<String, Int>): Int
    var count = 0
    var i = 0
    while i < vec_len(items)
        name = vec_get(items, i)
        if hashmap_has(lookup, name)
            count = count + hashmap_get(lookup, name)
        i = i + 1
    count

# After (unified)
def process(items: Vec<String>, lookup: HashMap<String, Int>): Int
    var count = 0
    var i = 0
    while i < items.size
        name = items[i]
        if lookup.has(name)
            count = count + lookup[name]
        i = i + 1
    count