cwal

whcl: Data Types Intro
Login

whcl: Data Types Intro

(⬑Table of Contents)

Jump to...

Per-type pages:

Introduction

cwal, the underlying scripting engine, supports a fairly rich set of JavaScript-like data types, plus a few more exotic ones. All "basic" types are, as is conventional, immutable (their values cannot be changed), but "containers" (types which hold other values) may of course be modified (or they'd be quite useless (in this language)). All values are, in effect, passed by pointer. There is no such thing as "deep copy" in cwal1.

The built-in data types exposed via whcl and constant values are...

Note that the underlying engine supports several other types which we do not currently plan on exposing to script code, most notably the hashtable class, as that one is functionally obsolete since the object type was changed to use hashtable storage.

Boolean Contexts

A "boolean context" is whenever the engine needs to reduce a problem's answer to a simple true or false. All value types can be implicitly converted to a boolean true or false, and their interpretations are set in stone at the cwal engine level, so neither scripts nor whcl may modify them:

Prototypes

whcl does not have classes, in the sense that high-level languages like C++ and Java have classes. It has a hard-coded core set of types (okay, "classes") with which clients can compose their data structures. whcl uses a prototypal inheritance model, similar to JavaScript's but has a few subtle, yet significant, semantic differences. A "class" in whcl is simply a specific use case for a specific Value, for which the language provides a very small amount of extra support. Specifically:

All of the base types except for the booleans, null, and undefined have a prototype object which provides common member methods. They are described in the sections of this document dedicated to each data type.

Clients may change the prototypes of any container-type value via assignment to the __prototype pseudo-property, but properties set on an object are always set on that instance, and never its prototype. Note, however, that assigning over the prototype of a built-in class will not have the desired effect because those prototypes are mapped at a lower level in C code. Clients may freely modify the prototypes of built-in classes but not outright replace them.

Clients may not (for at least two long, boring reasons4) reassign the prototypes for the non-container types (numbers and strings), and trying to do so will trigger an exception.

There is nothing specifically magical about prototypes except that the __prototype property is not really a property. Rather, it is intercepted internally as needed as a proxy for the C-level prototype getter/setter APIs. This property does not show up in any property iteration, for example. Prototype objects, in and of themselves, do not get any special treatment as prototypes - only access to the prototype (pseudo-)property is handled individually5.

cwal only supports container types as prototypes. Trying to set a non-container value as a prototype will fail, with two special-case exceptions (handled whcl-side, not in cwal): assigning either null or undefined to $anObject[__prototype] will remove that object's prototype. This is often useful for "plain properties objects" when a user wants to ensure that looked-up properties are not inherited from a prototype.

Unlike JavaScript, modifying prototype objects does not have any outwardly visible effects on objects which refer to them. e.g. when adding methods to the base Object prototype in JavaScript, traversal of properties in client-created objects can get very strange indeed (they suddenly include their prototype's properties when iterating, requiring the use of JS's Object.hasOwnProperty() method to work around it). To demonstrate this JavaScript oddity:

js> var o = {a:1}
undefined
js> Object.prototype.foo = 1
1
js> o.foo
1
js> for(var i in o) { console.debug(i, o.hasOwnProperty(i)); }
// outputs:
a true
foo false // this is the weird bit: modifying the prototype changes
          // how iteration of all instances works.
// And yet:
js> Object.keys(o)
Array [ "a" ]

(Wha?!?!)

In whcl, the effect is more intuitive: only the object being modified is modified, and iteration of other instances is most certainly not changed. Note that whcl's core Object type does indeed have a has-own-property method, but it's essentially never needed.

For info about whcl's approaches to creating classes, see the new command.

Listing all Builtin Prototypes and Methods

The prototypes of all of whcl's core/built-in types are accessible from script code via whcl[prototypes][TYPENAME].

To get the complete list of type names try:

foreach k v whcl[prototypes] {echo $k $v}

Noting that whcl's property storage is unordered, so the keys will not be sorted except by wild random chance.

To get a list of all of the built-in prototypes and their methods:

foreach k v whcl[prototypes] {
  echo $k $v
  foreach kk vv $v {echo "    " $kk $vv}
}

Noting that the Number prototype is the shared prototype of both the Integer and Double prototypes.

Creating Objects and Arrays

Though objects and arrays are core data types in whcl, there is no "literal" syntax for creating them like there is in JavaScript or s2 because interpretation of such syntax is highly context-dependent in whcl. Instead, the object or array builtin command is used to create them. Similarly, many different APIs return values of these types.

Footnotes


  1. ^ But making deep copies via intermediate expressions is often possible. e.g. (decl a 300; decl b (a * 2 / 2) ends up with two unique copies of integers with the value 300.
  2. ^ In 30+ years(!) of programming, i've never once needed scientific notation numbers.
  3. ^ We should arguably eval empty buffers as false, seeing as they are basically used like mutable strings.
  4. ^ 1) cwal only supports a single shared prototype for non-containers because doing otherwise would cost more memory for all values just to cover an as-yet-unneeded use case. 2) Sanity's sake.
  5. ^ Minor internal exception: for C-level prototypes we have to place the instances somewhere with an "indefinite" lifetime, to avoid that they get GC'd before they are used or when the last "subclass" instance goes out of scope. Yes, prototypes are subject to normal lifetime rules.