The Sway Reference Manual/Arrays and Lists

There are three main data structures built into Sway: arrays, lists, and objects. A data structure is simply a collection of bits of information [1] that are somehow glued together into a single whole. Each of these bits can be be accessed individually. Usually, the bits are somehow related, as well, so the data structure is a convenient way to keep all these related bits nicely packaged together.

Arrays edit

An array is a data structure with the property that each bit of information can be accessed just as quickly as the others. To create an array, one uses the array function:

   var a = array(42,64.0,"hello",:world);

This call creates an array that packages together four items or elements. The variable a is created and set to point at the package.

To access individual elements, one uses the 'square bracket' notation or the 'dot' notation. For example, here's how to access the first item in an array:

   sway> a[0];
   INTEGER: 42
    
   sway> a . 0
   INTEGER: 42

Note that array indexing (the number between the brackets or after the dot is known as an index) is zero-based. That is, the first element is at index 0, the second at index 1, and so on. Usually, the 'dot notation' is not used for arrays, because of the high precedence of 'dot'. For example:

   a[row * cols + col]

is not the same as:

   a . row * cols + col

as in the later, the element at the row index is retrieved and then multiplied by cols and then that number is added to col. To make the latter the same as the former, one would parenthesize the index calculation:

   a . (row * cols + col)

With bracket notation, the parenthesization is performed automatically.

One can assign to arrays as well:

   sway> a[0] = :forty-two;
   SYMBOL: :forty-two
    
   sway> a[0];
   SYMBOL: :forty-two

One can also look at the tail end of an array. The tail end of an array is the array without the first, or head, element.

   sway> tail(a);
   ARRAY: [64.000000000,"hello",:world]
    
   sway> tail(a)[0];
   REAL_NUMBER: 64.000000000

If you keep taking the tail of an array, eventually you end up with :null:

   sway>tail(tail(tail(tail(a))));
   SYMBOL: :null;

Allocating empty arrays edit

It is possible to allocate an array without specifying the actual elements:

   var b = alloc(10);

This creates an array of ten elements (with indices ranging from zero to nine).

   sway> b[0];
   SYMBOL: :null;

Each of the elements is initialized to :null.

Lists edit

A list is a data structure that has the property that it can be lengthened and shortened by adding or removing elements anywhere in the list. The trade-off for this flexibility is that elements further down in the list take longer to access than those elements earlier in the list. Creating and accessing elements in a list is very similar to arrays:

   var a = list(42,64.0,"hello",:world);
    
   sway> a[2];
   STRING: "hello"
   
   sway> a[3] = 13;
   INTEGER: 13

To make a list longer, one can easily add an element to the front of an existing list to make a new list:

   var b = "apple" join a;
   LIST: ("apple",42,64.000000000,"hello",:world)

Lists can share elements edit

It is very important to note that both a and b above share elements and changes to a will affect b:

   sway> a[1] = :pie;
   SYMBOL: :pie
    
   sway> a;
   LIST: (42,:pie,"hello",:world);
    
   sway> b;
   LIST: ("apple",42,:pie,"hello",:world);

Making b independent of a is a task that seems easier than it actually is. Here is a function that makes the attempt:

   function join*(item,items)
       {
       function copy(stuff)
           {
           if (stuff == :null,:null,stuff[0] join copy(tail(stuff)));
           }
       item join copy(items);
       }

This works in some cases:

   var x = list(:apples,:pears,:bananas);
   var y = :kumquats join* x;               //note join*, not join
   
   x[1] = :persimmons;
   sway> x;
   LIST: (:apples,:persimmons,:bananas);
    
   sway> y;
   LIST: (:kumquats,:apples,:pears,:bananas);

The problems is that the copy made by join* is a shallow copy. That is, the incoming list was copied, but the elements were not. In the case of a list of symbols, the elements do not need to be copied, but that is not always the case:

   var m = list(2,3,4);
    
   sway> var p = list(1,m,5);
   LIST: (1,(2,3,4),5)
   sway> var q = 0 join* p;       // note, join*, not join
   LIST: (0,1,(2,3,4),5)

Got it so far? Not only does q share the elements of p, they both share elements of m. Consider this move:

   p[1][1] = 333; 

where we change the first element of the first element of p:

   sway> p;
   LIST: (1,(2,333,4),5)
    
   sway> q;
   LIST: (0,1,(2,333,4),5)

A change made through p has still changed q. To solve this problem, one needs to make a deep copy, where the elements of the list are copied and the elements of the elements are copied, and so on.

Changing the tail of a list edit

One can use the tail= function to change the tail of a list:

   var a = list(1,2,3);
    
   a tail= list(222,333);
   sway> a;
   LIST: (1,222,333);

You can use tail= on any kind of list, even those produced by tail:

   var b = list(1,2,3);
    
   tail(b) tail= list(333);
   sway> b;
   LIST: (1,2,333);

Inserting into the middle of a list edit

One uses a combination of join, tail, and tail= to insert into the middle of a list. Here's how to insert an item after the first element:

   var c = list(1,3,4);
   c tail= (3 join tail(c));
   sway> c;
   LIST: (1,2,3,4);

The parentheses are needed to insure that the tail of c is not set to the number 3 and the result joined with the tail of c.

This method of insertion changes the original list. It is also possible to make a new list with the inserted element by writing an insertion function:

   function insert(item,items,index)
       {
       if (index == 0)
           {
           item join items; //put the item at the head of the list
           }
       else
           {
           items[0] join insert(item,tail(items),index - 1);
           }
       }
   var d = list(1,3,4);
   var e = insert(2,d,1); //insert at the second element
   sway> d;
   LIST: (1,3,4);
   sway> e;
   LIST: (1,2,3,4);

Note that insert does a combination of a shallow copy of the elements preceding the inserted element and creates a sharing of the elements after the inserted element.

Objects edit

Objects are discussed in the next chapter.

Footnotes edit

  1. Bits in the informal sense, not zeros and ones.


Input and Output · Objects