|
| 1 | +=begin pod |
| 2 | +
|
| 3 | +=head1 Perl 6 Containers: a low-level approach |
| 4 | +
|
| 5 | +This article started as a conversion on IRC explaining the difference between |
| 6 | +the C<Array> and the C<List> type in Perl 6. It explains the levels of |
| 7 | +indirection involved in dealing with variables and container elements. |
| 8 | +
|
| 9 | +=head2 What is a variable? |
| 10 | +
|
| 11 | +Some people like to say "everything is an object", but in fact a variable is |
| 12 | +not a user-exposed object in Perl 6. |
| 13 | +
|
| 14 | +When the compiler encounters a variable declaration like C<my $x>, it |
| 15 | +registers it in some internal symbol table. This internal symbol table is used |
| 16 | +to detect undeclared variables, and to tie the code generation for the |
| 17 | +variable to the correct scope. |
| 18 | +
|
| 19 | +At run time, a variable appears as an entry in a I<lexical pad>, short |
| 20 | +I<lexpad>. This is a per-scope data structure that stores a pointer for each |
| 21 | +variable. |
| 22 | +
|
| 23 | +In the case of C<my $x>, the lexpad entry for the variable C<$x> is a pointer |
| 24 | +to an object of type C<Scalar>, usually just called I<the container>. |
| 25 | +
|
| 26 | +=head2 Scalar containers |
| 27 | +
|
| 28 | +Although objects of type C<Scalar> are everywhere in Perl 6, you usually never |
| 29 | +see them directly as objects, because most operations I<decontainerize>, which |
| 30 | +means they act on the C<Scalar> container's contents instead of the container |
| 31 | +itself. |
| 32 | +
|
| 33 | +In a code like |
| 34 | +
|
| 35 | + my $x = 42; |
| 36 | + say $x; |
| 37 | +
|
| 38 | +the assignment C<$x = 42> stores a pointer to the C<Int> object 42 in the |
| 39 | +scalar container to which the lexpad entry for C<$x> points. |
| 40 | +
|
| 41 | +The assignment operator asks the container on the left to store the value on |
| 42 | +its right. What exactly that means is up to the container type. For C<Scalar> |
| 43 | +it means "replace the previously stored value with the new one". |
| 44 | +
|
| 45 | +Note that subroutine signatures allow passing around of containers: |
| 46 | +
|
| 47 | + sub f($a is rw) { |
| 48 | + $a = 23; |
| 49 | + } |
| 50 | + my $x = 42; |
| 51 | + f($x); |
| 52 | + say $x; # 23 |
| 53 | +
|
| 54 | +Inside the subroutine, the lexpad entry for C<$a> points to the same |
| 55 | +container that C<$x> points to outside the subroutine. Which is why assignment |
| 56 | +to C<$a> also modifies the contents of C<$x>. |
| 57 | +
|
| 58 | +=head2 Binding |
| 59 | +
|
| 60 | +Next to assignment, Perl 6 also supports I<binding> with the C<:=> operator. |
| 61 | +When binding a value or a |
| 62 | +container to a variable, the lexpad entry of the variable is modified (and not |
| 63 | +just the container it points to). If you write |
| 64 | +
|
| 65 | + my $x := 42; |
| 66 | +
|
| 67 | +then the lexpad entry for C<$x> directly points to the C<Int> 42. Which means |
| 68 | +that you cannot assign to it anymore: |
| 69 | +
|
| 70 | + $ perl6 -e 'my $x := 42; $x = 23' |
| 71 | + Cannot modify an immutable value |
| 72 | + in block at -e:1 |
| 73 | +
|
| 74 | +You can also bind variables to other variables: |
| 75 | +
|
| 76 | + my $a = 0; |
| 77 | + my $b = 0; |
| 78 | + $a := $b; |
| 79 | + $b = 42; |
| 80 | + say $a; # 42 |
| 81 | +
|
| 82 | +Here after the initial binding, the lexpad entries for C<$a> and C<$b> both |
| 83 | +point to the same scalar container, so assigning to one variable also changes |
| 84 | +the contents of the other. |
| 85 | +
|
| 86 | +You've seen this situation before: it is exactly what happened with the |
| 87 | +signature parameter marked as C<is rw>. |
| 88 | +
|
| 89 | +=head2 Scalar Containers and Listy Things |
| 90 | +
|
| 91 | +There are a number of positional container types with slightly different |
| 92 | +semantics in Perl 6. The most basic one is I<Parcel>, short for I<Parenthesis |
| 93 | +cell>. It is created by the comma operator, and often delimited by round |
| 94 | +parenthesis -- hence the name. |
| 95 | +
|
| 96 | + say (1, 2, 3).WHAT; # (Parcel) |
| 97 | +
|
| 98 | +A parcel is immutable, which means you cannot change the number of elements in |
| 99 | +a parcel. But if one of the elements happens to be a scalar container, you can |
| 100 | +still assign to it: |
| 101 | +
|
| 102 | + my $x = 42; |
| 103 | + ($x, 1, 2)[0] = 23; |
| 104 | + say $x; # 23 |
| 105 | + ($x, 1, 2)[1] = 23; # Error: Cannot modify an immutable value |
| 106 | +
|
| 107 | +So the parcel doesn't care about whether its elements are values or |
| 108 | +containers, they just store and retrieve whatever was given to them. |
| 109 | +
|
| 110 | +A C<List> has the same attitude of indifference towards containers. But it |
| 111 | +allows modifying the length (for example with C<push>, C<pop>, C<shift> and |
| 112 | +C<unshift>), and it is also lazy. |
| 113 | +
|
| 114 | +An C<Array> is just like a list, except that it forces all its elements to be |
| 115 | +containers. Thus you can say |
| 116 | +
|
| 117 | + my @a = 1, 2, 3; |
| 118 | + @a[0] = 42; |
| 119 | + say @a; # 42 2 3 |
| 120 | +
|
| 121 | +and C<@a> actually stores three scalar containers. C<@a[0]> returns one of |
| 122 | +them, and the assignment operator replaces the integer value stored in that |
| 123 | +container with the new one, C<42>. |
| 124 | +
|
| 125 | +=head2 Assigning and Binding to Array Variables |
| 126 | +
|
| 127 | +Assigning to a scalar variable and to an array variable both do basically the |
| 128 | +same thing: discard the old value(s), and enter some new value(s). |
| 129 | +
|
| 130 | +Still it's easy to observe how different they are: |
| 131 | +
|
| 132 | + my $x = 42; say $x.WHAT; # (Int) |
| 133 | + my @a = 42; say @a.WHAT; # (Array) |
| 134 | +
|
| 135 | +This is because the C<Scalar> container type hides itself well, but C<Array> |
| 136 | +makes no such effort. |
| 137 | +
|
| 138 | +To place a non-C<Array> into an array variable, binding works: |
| 139 | +
|
| 140 | + my @a := (1, 2, 3); |
| 141 | + say @a.WHAT; # (Capture) |
| 142 | +
|
| 143 | +=head2 Binding to Array Elements |
| 144 | +
|
| 145 | +As a curious side note, Perl 6 supports binding to array elements: |
| 146 | +
|
| 147 | + my @a = (1, 2, 3); |
| 148 | + @a[0] := my $x; |
| 149 | + $x = 42; |
| 150 | + say @a; # 42 2 3 |
| 151 | +
|
| 152 | +If you've read and understood the previous explanations, it is now time to |
| 153 | +wonder how this can possibly work. After all binding to a variable requires a |
| 154 | +lexpad entry for that variable, and while there is one for an array, there |
| 155 | +aren't lexpad entries for each array element (you cannot expand the lexpad at |
| 156 | +run time). |
| 157 | +
|
| 158 | +The answer is that binding to array elements is recognized at the syntax |
| 159 | +level, and instead of emitting code for a normal binding operation, a special |
| 160 | +method on the array is called that knows how to do the binding itself. |
| 161 | +
|
| 162 | +=end pod |
0 commit comments