In yesterday’s installment (Testing FizzBuzz in Parrot), I explained a test file for testing multiple Parrot implementations of the FizzBuzz problem. I also promised to show two different ways to solve the problem in Parrot. The test framework requires both approaches to take a single integer describing how many FizzBuzz elements to produce and to return an Array-like PMC containing the FizzBuzz strings.
Pre-populating an Array
The most straightforward approach is to create a new Array PMC and fill
it in with the appropriate strings. Despite its procedural
naïveté, it’s also the most straightforward application of the
algorithm. It all takes place in the
42 .sub 'procedural' 43 .param int end
The function starts as normal. It takes one parameter; an integer. Right
now the code assumes that it will start at position 0 in the created array
and loop until the integer counter reaches
45 .local pmc results 46 results = new .ResizableStringArray 47 48 .local int count 49 count = 1 50 51 .local int remainder 52 .local string element
Lines 45 through 52 declare a couple of interesting variables. I chose
to use a
ResizableStringArray for ease of use. It would have
been just as easy to use a
FixedStringArray, but I thought
push code later would be clearer. Notice that
count, the loop counter, starts at 1. This is important to
avoid fencepost errors in the algorithm later.
element outside of
the loop (though there’s no real sense of “outside” in PIR) out of personal
preference. I’m not aware of any real scoping issues in Parrot, except that
declarations must precede use.
54 loop_start: 55 if count > end goto loop_end 56 element = ''
This is the start of the loop. It tests the counter to see if the loop
end times. If so, it quits looping. Otherwise, it
element to an empty string.
58 check_fizz: 59 remainder = count % 3 60 if remainder goto check_buzz 61 element .= 'Fizz'
The label in line 58 exists only for clarity. It’s not necessary for the
algorithm. Lines 59 checks that the current element number is a multiple of
three, using the modulus operator. Line 60 skips ahead if there’s a
remainder. Otherwise, line 61 appends the string
Fizz to the
current value of
63 check_buzz: 64 remainder = count % 5 65 if remainder goto add_element 66 element .= 'Buzz'
No matter what’s in
element, line 64 is the next line
executed. It checks that the number of the current element is a multiple of
five. If not, another
goto skips line 66. Line 66 appends the
Buzz to the current element.
I deliberately kept the structure of
check_buzz similar to make the code clearer. There are ways to
reduce this duplication–perhaps turning this code into a parametrized
function–but with only two occurrences, it wasn’t quite worth it.
68 add_element: 69 push results, element 70 inc count 71 goto loop_start
The loop ends by pushing
element, which contains an empty
results array. It increments the loop counter and
restarts the loop.
73 loop_end: 74 .return( results ) 75 .end
When the loop ends, the function returns the entire array.
Besides the lack of control flow beyond
goto LABEL, the
straightforward algorithm in PIR looks like that in almost any high level
Creating a FizzBuzz Array PMC
My second approach was to subclass
override some of its vtable methods to generate the right data instead of
filling up an entire array all at once. This is similar to the
tie mechanism in Perl 5, except that it’s pervasive throughout
Parrot so that the implementation is much, much better.
The public function is
77 .sub 'keyed_array' 78 .param int count 79 80 .local pmc results 81 results = new [ 'FizzBuzz'; 'Array' ] 82 results = count 83 84 .return( results ) 85 .end
That’s it; like
procedural it takes a single integer
parameter, the number of elements requested.
Line 81 creates a new
FizzBuzz;Array object. The strange
bracket syntax names a class by
Key is a
hierarchical name, and it’s useful for nested namespaces.
Line 82 sets the number of elements in the array to
Parrot turns the act of assigning an integer to a PMC to a method call on
the PMC; the method is
set_integer_native. This will be
important in a moment.
It’s important to show the implementation of
87 .namespace [ 'FizzBuzz'; 'Array' ] 88 89 .sub 'init' :init :load 90 .local pmc fs_array 91 .local pmc fb_array 92 93 fs_array = getclass 'FixedStringArray' 94 fb_array = subclass fs_array, [ 'FizzBuzz'; 'Array' ] 95 96 addattribute fb_array, 'size' 97 .end
Line 87 starts a new namespace for
methods must belong to a namespace with the same name as an object’s
Line 89 begins a compilation unit of initialization code. The presence
:load is a bit of a mish-mash.
They execute at different times, depending on whether you invoke this code
directly or load it from another piece of code invoked directly. Using both
here hurts nothing; it supports both execution models I explained in my
The most important lines are 93 and 94. Line 93 fetches the
Class PMC associated with the built-in
FixedStringArray. Line 94 creates a new class named
FizzBuzz;Array as a subclass of
fb_array then contains the new
Finally, line 96 adds an attribute–an instance variable–to the class,
size. I’m sure you can imagine what that indicates.
99 .sub '__init' :method 100 .local pmc size 101 size = new .Integer 102 103 setattribute self, 'size', size 104 .end
Parrot classes need initializers. Parrot will call the
__init method when creating a new PMC. Lines 100 and 101
declare and create a new
Integer PMC. Line 103 assigns that
PMC to the
Why is it an
Integer? Attributes can only contain PMCs, not
primitive types such as integers, floats, or strings.
Strictly speaking, I don’t need this initializer, but I find it’s helpful to create a PMC with all of the necessary attributes initialized correctly than to check for their existence whenever I want to access those attributes later.
106 .sub 'set_integer_native' :vtable :method 107 .param int size 108 109 .local pmc size_pmc 110 size_pmc = getattribute self, 'size' 111 size_pmc = size 112 .end
I mentioned earlier that assigning
count to a
FizzBuzz;Array ultimately called the
set_integer_native vtable method. Because I decided not to
create a full array with all of the elements precalculated, I needed to
intercept this call and do something different.
:vtable attribute tells Parrot that this subroutine
should override the parent’s vtable method of the same name. The
:method attribute tells Parrot that this subroutine expects
the invocant in a special register according to Parrot’s calling
conventions. It also makes that invocant available through the body of the
subroutine in the variable named
All vtable methods are methods, so, yes,
:method. It currently doesn’t.
Lines 109 and 110 retrieve the
size attribute PMC into a
variable. Line 111 assigns the
size passed into this
subroutine to the PMC. Think of the PMC as a container for this integer
It might be tempting to try to assign a primitive integer to the attribute, but that won’t work. As I said before, attributes must be PMCs. You must box a primitive value in a PMC to assign to an attribute slot.
114 .sub 'get_integer' :vtable :method 115 .local pmc size_pmc 116 size_pmc = getattribute self, 'size' 117 118 .local int size 119 size = size_pmc 120 .return( size ) 121 .end
set_* methods imply a corresponding
get_integer vtable method looks at the
size attribute and returns its value. Parrot will call this
for code like:
.local int num_elements num_elements = fb_array
That assumes that
fb_array is a
object, of course.
123 .sub 'elements' :vtable :method 124 .local pmc size_pmc 125 size_pmc = getattribute self, 'size' 126 127 .local int size 128 size = size_pmc 129 .return( size ) 130 .end
Array-like PMCs have another vtable method called
There is currently no easy way in Parrot, to my knowledge, to use the same
Parrot subroutine for two different vtable methods. There will be.
Finally, the real work comes from accessing an element of the array.
132 .sub 'get_string_keyed' :vtable :method 133 .param int key 134 inc key
The vtable method called is either
get_string_keyed_int, depending on some Parrot esoterica. It
takes an integer as the key.
Because Parrot arrays start with an index of
0, line 134
increments the key to make the math easier.
136 .local pmc size_pmc 137 .local int size 138 size_pmc = getattribute self, 'size' 139 size = size_pmc 140 141 unless key > size goto calculate_string 142 .return()
Fixed arrays have fixed sizes in Parrot. I decided to return nothing if
someone tries to access an element beyond the appropriate size of a
Another option is throwing an exception, but I wanted to keep the code simple for this example.
144 calculate_string: 145 .local string result 146 result = '' 147 148 .local int remainder 149 150 check_fizz: 151 remainder = key % 3 152 if remainder goto check_buzz 153 result .= 'Fizz' 154 155 check_buzz: 156 remainder = key % 5 157 if remainder goto return_result 158 result .= 'Buzz' 159 160 return_result: 161 .return( result ) 162 .end
The rest of the code looks very much like the
implementation, except that it doesn’t loop and push the results onto an
array. This code calculates the result for the given index and returns it
directly. It could be more complex by adding caching, but that would
complicate the code and it’s unnecessary.
164 .sub 'get_string_keyed_int' :vtable :method 194 .end
Due to not being able to share implementation of vtable methods defined
as PIR subroutines,
get_string_keyed_int uses the worst
possible method of code sharing–copy and paste–to handle the other way of
accessing an array value by index. It works though.
There are plenty of other ways to solve this problem in Parrot. A fun one is to create separate iterators and access them all simultaneously. Perhaps I’ll do that–or perhaps you will. Despite being an assembly language for a virtual machine still under active development, PIR is reasonably straightforward and very powerful.