Array, WeakArray, SharedArray

Argentum has no built-in Arrays

Other languages have built-in arrays (and some even have built-in maps), but these built-in data structures quickly become insufficient. So the parallel containers from the standard libraries emerge. They quickly surpass and replace the built-in ones in everyday use:

  • in C++ it's Type[] vs std::array (std::vector etc.).
  • in Java it's Type[] vs ArrayList etc.

This creates mess and multiple incompatibilities. That's why Argentum does not have built-in arrays. Instead its arrays are just runtime library classes. And since all argentum classes are open to adding new methods and interfaces, different libraries can extend existing arrays without need of creating new ones.

using sys { Array }

// `arrays` module adds lots of extensions to Array classes
// including `each` and `resize`
using arrays;

a = Array(String).resize(10);
x = a[3];
a[0] := "Hello";
a.each(i \ log(i : "None");

Array is just an object.

  • Operator a[i] is just a handy form of call to method a.getAt(i),
  • Operator a[i] := v calls method a.setAt(i, v).

Array indexation produces optional<T> results

Result of array indexing is an optional, where none value indicate the index-out-of-bounds condition.

fn doSomething(a Array(String)){
   log(a[0]); // error: log expects String, while a[0] returns ?String
   log(a[0] : "None"); // ok, operator `:` unwraps optional with "None" default
   a[0] ? log(_); // ok, operator `?` unwraps optional LHS and calls RSH if it has value
}

As a result you cannot write code that doesn't handle indexation errors. And this handling is extremely simple.

Semantic of Arrays reflects the semantic of pointers

There are three standard arrays of pointers:

  • Array - that holds @OwningPointers, has ownership over its mutable elements.
    It models 1-parent-many-children relations in tree-like structure of ownership.
    Examples: when paragraphs belong to a text block, when functions reside in a compilation unit, when controls live inside UI panel or window, there is always exists some Array-field in the parent object.
  • SharedArray - holds *SharedFrozenPointers. It shares immutable elements with other SharedArrays and scalar shared pointers.
    It models many-owners-to-many-immutable-resources relation.
    Examples: when a document holds a collection of icons or fonts, this document probably has somewhere in its field a SharedArray of pointers to immutable resources, that can be referenced not only from this document, but from other places too, but since these resources are immutable, it's ok.
  • WeakArray - stores &WeakReferences to objects stored elsewhere.
    It models one-knows-about-many non-owning relations.
    Example: a graph node stores the outgoing edges to the other nodes.
class Cat{
   name = *"";
   color = rgb(0, 0, 0);
   init(aName *String, aColor Color) this { name:= aName; color := aColor }
}
cats = Array(Cat);  // aggregating array of owning unique pointers to mutable Cats
cats.add(Cat.init("Bars", rgb(100, 0, 0));  // Ok, storing new instance
cats[0] ? cats.add(_) // Error, Cat returned by cats[0] already owned somewhere
cats[0] ? cats.add(@_) // Ok, we insert into array a copy of Cat
cats[1] ? _.name := "Lucky"; // we change the name of this exact copy/instance of cat

class Person {
   name = *"";

   // Person knows about cats, but cat can outlive Person
   // So lifetimes of person and pet are independent,
   // and as such it is not ownership but a association/relation.
   // One to one relation is &WeakPointer, one to many - WeakArray
   pets = WeakArray(Cat);
}
p = Person;
cats[0] ? p.pets.insert(_);
cats[4] ? p.pets.insert(_);

class Person {
   // Person can have many nicknames,
   // Nicknames are immutable strings, and as such they can be shared among many persons.
   nickNames = SharedArray(String);
}
p.nickNames.add("Bars");
// Now the same immutable String is referenced by p.nickNames[0] and cats[0].name

There are no Arrays of temporary pin-pointers or arrays of conform pointers. Because arrays are objects and their elements play roles of their fields, but pin-pointers and conform pointers can't be stored in object fields.

Scalar fields of type @OwnPointer support "splice" operation a @= b. Splice operation allows to extract an object from one hierarchy and insert it to another one without making copy. Of course it's performed will all necessary runtime checks to guarantee from loops in graph of ownership (details: reattachments). Array class has a spliceAt method that does the same for array items.

Arrays have variable size

All arrays are initially created empty without any allocated space for objects. All arrays have methods that insert and delete elements and move groups of elements inside the container.

Immutable arrays

Arrays like all other objects in Argentum can be frozen and become shared-immutable instances. Thus Argentum has no separate "immutable array" classes.

Arrays of value types

Right now Argentum has one class Blob that represents a sequence of bytes of variable size. These bytes can be accessed by indexes as 8-16-32-64-bit data.

Blob has methods that insert, and delete byte ranges and copy them within single Blob and between Blobs. There are methods to byte-serialize utf8 characters in Blobs and to create Strings out of Blobs' byte ranges.

Blobs can be frozen, shared and unfrozen (by creating separate mutable copy) with standard Argentum operators.

Blobs can be sub-classed with defining getAt/setAt methods to turn them in into generic byte-word-dword-qword-double-float-bit arrays. It is not done yet, but if needed, it can be implemented in pure Argentum.

Leave a Reply

Your email address will not be published. Required fields are marked *