(⬑Central cwal Documentation Hub)
Achtung: these docs are very much in-progress, being ported and rewritten from older documentation.
See also: Scoping and Memory Management
Value Types in cwal
cwal started life as a fork of a library for working with JSON, and that provided the basics of the data type model which was initially envisions for cwal: something more or less JavaScript-esque (noting that JSON's core data types are in no way limited to JS, though its syntax is very much derived from JS).
That then evolved, with only minor changes, into what is still the core data type model.
cwal_value
, referred to in the docs as simply Value, provides the
client-opaque base interface for all Values in the engine. The derived
family of types includes booleans, numbers, strings, memory buffers,
functions, generic objects (key/value stores), arrays, and several
others, including cwal_native
, which is dedicated to connecting
arbitrary client-side types with cwal.
Each Value has a pointer to a so-called virtual table, a.k.a. vtab. The core vtab type defines the interfaces required for type-dependent behavior in various cases, e.g. features such as comparison, cleanup, and rescoping (a topic we'll cover in more detail in the scoping docs). Each value, except for built-in constant values (see below), also has a pointer to its owning scope, a reference count, and space for a small handful of flags (packed as memory-efficiently as seems possible - a truly undue amount of effort has been expended optimizing cwal's core for low aggregate memory usage).
The internal overhead of Values makes them, of course, appreciably larger than the native C counterparts but the internal recycling mechanisms generally reduce that difference to not only negligible levels, but often reverse the trend entirely, requiring less memory (in the aggregate) than using equivalent native counterparts. i.e. the abstraction penalty, in terms of memory, tends to be very low or even negative.
Yes, we have data to prove that, and collecting it for inclusion into these docs is on the TODO list. Aggregate costs of as low as 1 byte per integer and 4 bytes per string are frequently witnessed.
Sidebar: as an optimization, cwal uses built-in constant Value instances for several cases. Such Values outwardly behave, as far as client-side code goes, just like "normal" Values, but live outside of the lifetime management system and thus do not actually take part in reference counting, cycles, and the like. It's possible, but rarely useful (outside of cwal's own core), to distinguish a builtin Value from a normal one, but the library discourages clients from having any logic which depends on that distinction. Some examples of builtin constants include empty strings, booleans, and the numeric values -1, 0, and 1.
Containers vs. Non-Containers
Values are broken into two major categories:
- Simple types cannot have children nor participate in cycles. This category includes strings and numbers, among others.
- Containers can have children and participate in cycles. The core-most of these is the Object type, which provides a generic key/value store. Most of the higher-level types derive from this one, inheriting the key/value store capability. Arrays offer two levels of children: key/value properties (inherited from the Object type) and an array-style list of Values.
A few Value types fall somewhere between those two, holding a fixed set of child values (meaning that they can participate in cyclic structures) but not being general-purposes containers nor capable of holding arbitrary key/value pairs. Examples include the so-called property references, which wrap a key/value pair referencing a separate container, and tuples (lightweight fixed-length arrays).