Foundation
Foundation is xcc’s standard object library: the root Object,
value wrappers (Number, String,
Data), containers (Array,
Map, Set), and the protocols they
are built on.
#import "Foundation.xc" // the umbrellaThe umbrella pulls in Object, Comparable, Hashable, Enumerable, Copying, CharacterSet,
Number, String, Data, Array, Map and Set. That is everything below except the
Error protocol, which you import by name (#import <Error.xc>).
All of it needs a real heap (-falloc=heap), which is the default on the
6502 xt layouts and on every native backend.
Members
Section titled “Members”Object | The universal root class — pointer-identity equals, an address-derived hash, and the description hook every class inherits and overrides. |
Number | Wraps any sized integer or float; cross-kind conversion is lazy and cached. The box a typed collection stores a primitive in. |
String | A heap-owned, NUL-terminated UTF-8 string. Methods name their unit — byteAt counts bytes, charAt counts code points. |
Data | An owned heap byte block — opaque bytes, no trailing NUL, with growth, slicing, hex, and the String-encoding bridge. |
Array | An ordered, resizable list of Object* with sorting and the callback-based functional methods (filtered, mapped, …). |
Map | A hash map keyed by anything Hashable + Comparable; iterates in insertion order. |
Set | A hash set with set algebra (unionWith, intersect, subtract, …). |
Protocols
Section titled “Protocols”Comparable | Required equals; optional compare (<0/0/>0). Every value has equality but not every value has an order, so a class may have one without the other. |
Hashable | hash + equals: equal keys must hash equally. Required for a value to be a Map/Set key. |
Enumerable | enumLength + enumAt — the two methods for (x in collection) dispatches through. The loop variable is borrowed. |
Copying | copy — an independent duplicate. String and Data conform. |
Error | A single message(), so anything thrown can describe itself. Not in the umbrella — import by name. |
Every parentless class X inherits from the runtime’s built-in
Object root, so a Number*, a String*, or any
class of your own fits wherever an Object* is expected. No : Object
annotation is needed.
Two implementations, one API
Section titled “Two implementations, one API”Foundation exists twice. support/generic/lib/ is the 32-bit build (arm64,
arm9, m68k, x86_64), with u32 indices and a u32 hash, bounded only by
memory. support/xt6502/lib/ is the 6502 build, with u16 indices and a
u8 hash, because four-byte index arithmetic on every compare is too costly on
an 8-bit CPU.
Portable source compiles against both builds. A narrower caller index widens at
the call boundary, so for (u16 i = 0; i < a.count(); i++) behaves the same on
either target. The per-class pages list anything that differs. The most visible
difference is Array<i64> / Array<double>, which need -DENABLE_64BIT=1 on
xt6502 (see Number § availability).
Element types are erased generics
Section titled “Element types are erased generics”Every container takes an optional element type in angle brackets. It is a
compile-time check that is erased at run time: one Array implementation
serves every element type, so there is no code-size cost per instantiation.
Array<String>* names = new Array(); // new Array() needs no type argumentnames.add(String.withCString("ada"));String* s = names.get((u32)0); // a String*, no cast
names.add(Number.withU32((u32)7)); // error: Number is not a subclass of StringMap<V> names the value type; keys are anything conforming to Hashable.
Each collection takes one type argument; there is no Map<K,V> spelling yet. A
primitive element type works and is enforced (Array<i32> refuses a float),
but the value is stored boxed in a Number, and
unboxing happens in assignment context: i32 v = a.get(i). Untyped
Array* / Map* / Set* remain valid everywhere. See
Collections & strings for the full
discussion and the for … in caveat.
Ownership
Section titled “Ownership”Containers hold a strong reference to everything they store, and release it
when the element is removed or the container is deallocated. Sorting and
reversing move pointers only, with no refcount changes. sorted(), filtered(),
mapped(), subarray() and the Set algebra all return new containers and
leave the originals untouched.
The default Object.hash is derived from an
instance’s address, so hash order is not reproducible for a Map or Set
keyed by objects of your own classes. For this reason both enumerate in
insertion order. Override equals/hash together to give your class value
semantics, as Number,
String and Data do.