References, values, and slices

Lists are an example of a Limbo reference type: list variables hold a reference to the data of the list, not the list itself. When list variables are assigned, only the reference is assigned, not the whole list. This saves storage and makes execution much more efficient. For example, after executing

	reals = newlist; 

the two variables hold references to the same data; there are two variables but only one list. However, any modifications to one variable will not affect the other. If we now say

	newlist = tl newlist;

reals will still point to the complete original list.

Arrays are also a reference type, but, unlike lists, we can modify the individual elements of an array. This means that changes made using one array variable can be seen in another if it points to the same data. For example,

	a1 := array[] of {1, 2, 3};
	a2 := a1;
	a2[2] = 4;
	sys->print("values are now %d %d\n", a1[2], a2[2]);

will show that both arrays have been modified. This property would apply to lists, too, except that we cannot directly assign list elements:

	hd l = 4;	# illegal

is forbidden.

Strings behave differently: they are values like integers. Assigning a string creates a copy of the data, not a reference, so changes to the original do not affect the copy. This program

	s1 := "sniffle";
	s2 := s1;
	s1[6] = 'y';
	sys->print("strings are now %s and %s\n", s1, s2);

will show that the strings are independent: s2 remains "sniffle" although s1 is now "sniffly".

Sometimes it's useful to be able to make a reference or copy of only part of an array or string, not the whole thing. Limbo has a construct called a slice for this purpose. Slices are made by indexing with a consecutive range of elements specified by a starting index, a colon (:), and one past the last index. For example, given string s1 from the previous example,

	s1[2:4]

is a slice holding the string "if" and

	s1[0:len s1]

is a copy of all of s1. The last index is one beyond the last element, so the difference between the indices is the number of elements of the slice.

There is a shorthand for slices: if the end of the slice is the end of the original array, that is, if the second index of a slice of array A is len A, we can leave it out altogether. For example, these two expressions are equivalent:

	s1[2:len s1]
	s1[2:]

Similarly, we can omit the first index if it is zero.

Slices behave like regular strings or arrays; after

	s2 = s1[2:4];

s2[0] is the character 'i' and len s2 is 2. Slices of strings are values and slices of arrays are references, as one would expect.

Slices of arrays can also be assigned, which makes it possible to copy blocks of data from one array to another or within a single array. This example moves all the data in array a left one unit:

	a[0:] = a[1:len a];

Notice that the second index on the left hand side is missing; it is computed automatically from the length of the slice on the right. (Don't confuse this with a missing second index on the right, which is shorthand for the end of the array.) The assignment leaves unchanged the length of a and its last character; it is equivalent to the loop

	for(i:=1; i<len a; i++)
		a[i-1] = a[i];

Slices are common in Limbo programs; they simplify array and string processing.

previous next

© Rob Pike and Howard Trickey 1997. All rights reserved.