Vector is a subclass Array that combines the reference semantics of Array with the dynamic sizing of a List. A Vector is essentially an Array that you can dynamically resize. Some of the important differences between Vector and Array:
To use vectors, you must define the Vector intrinsic class in your source code. The easiest way to do this is to include the system header "vector.h", which is included with the compiler.
The Array, List, and Vector classes are all very similar; all of these classes allow you to manage collections of values as a group. The differences between the classes are a little subtle, but they're important.
Lists offer two unique features. First, List is an intrinsic T3 VM datatype, which makes it the "universal" collection type; some functions and methods require list values, and will not accept other collection types. Second, Lists use "value semantics," so you never have to worry about the effects of changing a list value to which other parts of your program might be retaining references.
Arrays use "reference semantics," which are sometimes trickier to work with than a List's value semantics, but offer advantages in some situations. Reference semantics also make Arrays more efficient when you're performing an iterative process that involves repeated updates to a collection's elements: if you use a List for such a process, each update to an element would create a new list value, whereas changes to an array's elements simply change the existing array object.
Like Arrays, Vectors use reference semantics. However, unlike an Array, you can dynamically change the size of a Vector. Vectors thus combine the reference semantics of an Array with the dynamic sizing of a List.
In general, you can decide which type of collection to use based on what you're going to do with it:
To create a Vector, you use the "new" operator. You must pass an integer argument to the Vector constructor; this is an advisory value specifying the initial allocation size for the Vector.
// create a Vector with an initial allocation of 10 elements
x = new Vector(10);
The initial allocation size does not set an upper bound for the number of elements in the Vector, nor does it specify the initial number of elements; this is purely an advisory figure that lets you make the Vector more efficient by providing a guess about how big the Vector might ultimately be.
After creation, a Vector always has zero elements, regardless of the initial allocation size.
x = new Vector(100);
say(x.length());
The code above displays zero, because a Vector never has any elements initially.
x = new Vector(1);
x += 1;
x += 2;
x += 3;
say(x.length());
The above code displays 3, because three elements have been added to the vector. This is perfectly legal; even though the vector's initial allocation size is only 1, you can still add any number of elements to the vector.
So, if the initial allocation size doesn't set the initial number of elements in the vector, and it doesn't set a maximum size for the vector, what good is it, and what does it matter what the value is? The answer is that the initial allocation size is purely advisory, and affects the memory efficiency of the vector. When you first create the vector, the system internally allocates the number of slots you specify in the initial allocation size; these slots are marked as "not yet in use," because the vector contains no elements at this point, but they're available for future use when you add elements. Later, if you add more elements than there are slots available, the vector automatically re-allocates its memory at a larger size.
If you make the initial allocation size too small, the system will have to re-allocate the vector's memory, possibly more than once, as you add new elements. If you make the initial allocation too large, the vector will take up more memory than it will ever actually need.
Don't worry about this too much, though. TADS 3 manages memory for you automatically, so it is not too dire a problem if your initial allocation is too high or too low. Any loss in efficiency resulting from an inaccurate initial allocation size will be fairly small. This parameter is provided only so that you can fine-tune your program's performance in cases where you have a pretty good idea in advance of how large a vector will be; in cases where you don't have any way of knowing, just pick a number that seems in the ballpark for a typical case.
The "+" operator adds new elements to the end of a Vector. If the operand on the right side of the "+" is a list, the elements of the list are each individually added to the vector; otherwise, the value on the right side of the "+" is added as a single new element.
The "-" operator removes elements from the Vector. If the operand on the right side of the "-" is a list, each element of the list is individually removed from the vector. If the operand on the right side of the "-" is not a list, each element of the vector whose value equals the right operand is deleted from the vector.
Because a Vector uses reference semantics, the "+" and "-" operators change the target vector object. Consider the following:
local x, y;
x = new Vector(5);
x += 1;
x += 2;
x += 3;
y = x + 4;
say(length(x));
In the code above, we create a vector and add three elements. Next, we calculate the value "x + 4" and assign it to the local variable y. If we were to display the values in y, we would expect to find four elements; but what does the last line display, when we calculate the length of x? The answer is four elements, which might be surprising. The "+" operator directly modifies the vector, then returns the modified vector, so after the assignment to y, x and y have the same value! Even though we haven't re-assigned x, it still refers to the modified vector, because the "+" operator modifies the original vector object.
Vector is a subclass of Array, so all Array methods are available on a Vector object, and behave just as they do with an Array. Note one difference, though: the Array methods that return a new Array object (subset, mapAll, getUnique, appendUnique) will return a new Vector object when used with a Vector.
In addition to the Array methods, Vector provides some methods of its own, shown below.
append(val) – appends the value val to the end of the vector, increasing the vector's length by one. This method has almost the same effect as the "+" operator, except for the treatment if val is a list: this method simply appends a list value as a single new element, whereas the "+" operator appends each element of the list value as a separate new element. Returns 'self'.
insertAt(startingIndex, val, …) – inserts one or more values into the vector at the giving starting index. The size of the vector is increased to accommodate the new elements. Note that, if any of the values are lists or other collections, they are simply inserted as single elements; this contrasts with the "+" operator, which adds each element of a list as a separate element of the vector.
The startingIndex value must be at least 1, and at most one higher than the length of the vector. If the starting index value is 1, the new elements are inserted before the first existing element of the vector. If the starting index is one higher than the length of the vector, the new elements are appended after the last existing element of the vector. If the starting index is out of this valid range, the method throws an error ("index out of range").
Returns the 'self' object.
removeElementAt(index) – deletes one element from the vector at the given index. This reduces the length of the vector by one. The index value must refer to an existing element of the array, or the method throws an error ("index out of range"). Returns 'self'.
removeRange(startingIndex, endingIndex) – deletes elements from the vector from startingIndex through and including endingIndex. If startingIndex equals endingIndex, this method simply deletes one element. This reduces the length of the vector by the number of elements removed.
Both startingIndex and endingIndex must refer to existing elements of the vector, and the ending index must be greater than or equal to the starting index; if these conditions don't hold, the method throws an error ("index out of range").
Returns the "self" object.
setLength(newLength) – sets the number of elements of the vector to newLength. If newLength is smaller than the number of elements currently in the vector, this discards elements at the end of the vector. If newLength is larger than the current size, this adds new elements and sets their values to nil. Returns the 'self' object.