The Prism Primer - Part 6
From The Oxygene Language Wiki
This is a General topic
Feel free to add your notes to this topic below.
The Prism Primer: Part 1 – Part 2 – Part 3 – Part 4 – Part 5 – Part 6 – Part 7 – Part 8 – Part 9
Arrays
Hint: Arrays in .NET are not as important as they were in non-.NET languages. Often generic lists and dictionaries (we'll get to them later) are a much better approach. But as they are still a basic element for programming, we'll take a look at them.
Arrays are a way to store data in a structured way. They consist of an arbitrary number of elements of the same type. Every element has a unique "address"* inside the array. The address is a tuple of n numbers, where n is the array's dimension.
To get an association of an array, you can think of a one-dimensional array as a table with just one line:
Value [0] Value [1] Value [2] Value [3]
This address in this case is just one number (0..3), which describes the position of an element inside the array completely.
A two-dimensional array is a table with columns and rows:
Value [0,0] Value [0,1] Value [0,2] Value [0,3] Value [1,0] Value [1,1] Value [1,2] Value [1,3] Value [2,0] Value [2,1] Value [2,2] Value [2,3]
For a 2d-array the tuple has to consist of two numbers to get a unique address. You need row- and column-number.
You can see the difference between size and dimension of an array. The size of the table above is arbitrary, but the dimension remains two. Regardless of the tables's size, you always need only two numbers to get a unique address for an element inside the table. Of course you can have arrays with a dimension bigger than two.
By the way: You access the elements of an array in Delphi Prism just like it's written in the tables, you only have to omit the blank between "Value" and the tuple and you get with Value[0,0] an element from an array called "Value".
We'll stick to one-dimension arrays in this crash course, this will cover 95% of your daily array-usage.
To have a nice sample, we'll again extend our calculator. It's supposed to get the senseless feature of calculating Fibonacci numbers, using an even more senseless implementation using arrays. ;-) Fibonacci numbers are a sequence following the rule that a number is the sum of its two predecessors, the first two numbers are 0 and 1. Therefore the third number is 1 (0+1), the fourth number is 2 (1+1), etc.
Please add a btFibonacci button to the calculator sample and switch to its click event handler. Put the first number into the firstNumber variable, parsing it into an integer.
The next step is to create the array. Without type inference you have to first declare an array variable and then create the array "in it". Using type inference as the first step is obsolete, but to show how to declare an array, we'll do it anyway:
var numbers : Array of Integer; numbers := new Integer[firstNumber];
The first line is the declaration. If you want to use type inference, you can omit that one. The declaration only speicifies the array's type and its dimension, but it does not specifiy its size. This is done in the second line, when the array is instantiated.
When creating an array you use the new keyword, then the type of the array elements and then (in squared brackets) the size of the array. The memory for this number of elements is allocated. You cannot change the size of an array afterwards.
The first two numbers of the Fibonacci sequence are fixed, so we can set them directly:
numbers[0] := 0; numbers[1] := 1;
Note that the first index of an array is zero (by default). We fill the rest of the array using a for-loop:
for i : Integer := 2 to numbers.Length - 1 do numbers[i] := numbers[i-1] + numbers[i-2];
The upper bound of the loop variable is the highest accessable index of the array. numbers.Length gives you the size of the array and because indexes start with zero, the highest index is one less than the size. In the body of the loop the values of the two predecessors are added and the sum assigned to the current array element.
After the loop has finished, the array contains the Fibonacci numbers. We want to show them as result.
The for each Loop
At this point I want to introduce another loop Delphi Prism offers. We couldn't look at it before now, because it works on sequences only. And the only sequence we know until now is an array. But there will be much more when this crashcourse is finished.
The task at hand is to create a string containing the Fibonacci numbers as comma-seperated list. Lets start with the most simple version:
var numberString := ''; for each n in numbers do numberString := numberString + n.ToString + ',';
In the first line an empty string is created. The second line is the head of the for each-loop. You can omit the "each", if you want. The loop variable is n.
But this time n is not a counter variable: The for-loop iterates through a sequence of elements and in every step n will have the value of the current element in the sequence. So in this case n is not the index of an element in the array, it has the value of the element in the array. The type of n is inferred from the type of the array's elements: n is an Integer.
The third line builds the string. It takes the existing string and appends first the string-representation of n and then a comma.
Important: Don't get used to this way of building strings! A string in .NET is immutable and therefore every time you append something to a string actually a new string is created, copying the old string and the appended string into it, which is very slow and uses a lot of memory. In real-world applications, you should always use the StringBuilder class. You'll see how to use that after you've learned more about classes.
Besides that there's something wrong with the prior sourcecode: There's a comma after the last number. We can solve that problem by using another feature of the for-loop:
for n in numbers index i do numberString := numberString + n.ToString + iif(i < numbers.Length-1, ',', '');
i now is a second loop variable representing the index of n in the sequence numbers. Because we know the array's length (and thus its last index), we can check if we already reached the last element and omit appending the comma then. We do that by using the iif function.
Last thing to do: Assign numberString to the Text-property of tbResult. Finished :-)
Arrays as Parameters
Arrays are so-called "reference types". This means, the variables of these types are only references to a place in the memory. That's important if you want to use arrays as parameters in methods. Even if you pass them using "call by value", the value that is copied is only the reference which then still points to the same memory region.
The consequence: If you change the elements of an array inside a method, even if it was passed using "call by value", you'll change the elements of the array outside the method, too.
Now you'll wonder what effect the "call by reference" method has on arrays. That can be shown on a simple sample:
method MainForm.CreateArrayByReference(var a : Array of Integer); begin a := new Integer[5]; end; method MainForm.CreateArrayByValue(a : Array of Integer); begin a := new Integer[5]; end; (* ... *) var testArray := new Integer[10]; CreateArrayByValue(testArray); MessageBox.Show(testArray.Length.ToString); CreateArrayByReference(var testArray); MessageBox.Show(testArray.Length.ToString);
You have two methods that do nearly the same thing, only one is using "call by reference" the other one "call by value". These methods are called on a previously created array. After each call the length of the array is displayed.
First the "call by value"-method is used. After that call the messagebox will show 10 as length. A new array was created inside the method, but because the array was passed "by value", outside the method the variable still points to the old array, which has its old length.
After the second call the messagebox will show 5 as length. This time the array was passed "by reference" and so the variable outside the method now points to the new array, too.
Notes
- not a good term - maybe it's worth to refer to as something like "index" or "multiindex"
See Also
The Prism Primer: Part 1 – Part 2 – Part 3 – Part 4 – Part 5 – Part 6 – Part 7 – Part 8 – Part 9
Glossaries — Keywords — Types — FAQ — How To