A recent discussion on interviewing programmers (in hopes of finding clueful ones) brought up the FizzBuzz challenge. Can you write a program to print the numbers from one to one hundred, printing also “Fizz” for multiples of three, “Buzz” for multiples of five, and “FizzBuzz” for multiples of three and five?

This ought to take no more than a few minutes for a developer with any proficiency in a language. I decided it would be fun to write it in Parrot’s PIR. There’s the straightforward procedural way, the array overloading way, an object-oriented way, the coroutine approach, and the generator technique.

I chose the first two, but I also decided to work entirely with test-driven development, even though this is normally the realm of a SpikeSolution–I thought that might be more interesting for everyone.

To make TDD work well, I created a test file, t/examples/fizzbuzz.t. It’s a pure-PIR test script that uses the Parrot version of Test::More and produces Test::Harness compatible TAP.

The program starts out simply:

     1  #!parrot
     2  
     3  .include 'hllmacros.pir'
     4  
     5  .const string TESTS = 18

The .include directive works like #include in C; it inserts the contents of another source file into the current compilation unit. hllmacros.pir contains some useful macros. PIR is powerful, but it’s still an assembly language at heart. We’ve developed a few shortcuts for making PIR easier to write.

Line 5 declares a constant–the number of tests to run. PIR has typed variables (actually four distinct types of registers), so all named variable declarations need a type declaration.

     7  .sub 'main' :main
     8      load_bytecode 'Test/More.pir'
     9      load_bytecode 'examples/pir/fizzbuzz.pir'
    10  
    11      .local pmc import_sub
    12      .IMPORT( 'Test::More', 'plan', import_sub )
    13      .IMPORT( 'Test::More', 'is',   import_sub )
    14      .IMPORT( 'Test::More', 'diag', import_sub )
    15  
    16      plan( TESTS )
    17  
    18      test_function( 'procedural'  )
    19      test_function( 'keyed_array' )
    20  .end

Lines 7 and 20 bracket the main entry point to this test file–a subroutine named main. The name is immaterial to everything but programmers; only the :main attribute tells Parrot that, when invoking this file directly, this is the entry point.

Lines 8 and 9 load two PIR libraries. One is the pure-PIR testing system and the other is the file of FizzBuzz subroutines to test. Yes, load_bytecode is an inopportune name.

Line 11 contains another variable declaration. It only exists to make the .IMPORT() macro work correctly. This time, the variable is a local variable–that is, it persists only through this compilation unit (the subroutine). It holds a PMC–a Parrot Magic Cookie, Parrot’s single non-primitive type.

Lines 12 through 14 import three testing functions from Test::More. Though they come from a separate namespace, they’re available within this test file as if I had declared them locally. (Now you see why I used .IMPORT.)

Line 16 starts the testing by telling the test library that I plan to run TESTS number of tests.

Lines 18 and 19 call a the remaining function in this file with the name of the various FizzBuzz functions in examples/pir/fizzbuzz.pir.

    22  .sub 'test_function'

Note the lack of :main or any other attribute on line 22.

    23      .param string func_name

Line 23 demonstrates how to access subroutine arguments in PIR. The .param declaration is like .local in its scope, but beyond merely associating a name to a particular type of register within this compilation unit, it also accesses the appropriate value passed into the subroutine.

    25      .local pmc test_sub
    26      test_sub = find_global [ 'FizzBuzz' ], func_name

With the function name passed in as an argument, this function needs to be able to access the function in my example PIR file. The find_global opcode takes a namespace key and a string and returns the PMC stored in that namespace under that name. If I have the name correct, test_sub will contain a Subroutine PMC that I can invoke.

Parrot has first-class functions; this is more than just a function pointer.

    27      diag( func_name )

Line 27 calls a Test::More function to show the name of the function being tested. It won’t interfere with the TAP output in any way. It’s just nice when running the tests directly for diagnostic purposes.

    29      .local pmc results
    30      results = test_sub( 10 )
    31  
    32      .local int count
    33      count   = results

Lines 29 and 32 declare two variables which I used throughout the remainder of this function. results contains an Array PMC returned from the subroutine being tested. I use count to hold the number of elements in the results PMC. (If it’s not clear, the count = results line ends up calling the get_integer() vtable method on the PMC. That returns the number of elements for an Array-like PMC. How does Parrot know to call that method? count is an integer, and the assignment operation with an integer variable as an lvalue on a PMC rvalue turns into the get_integer() call.)

All of my FizzBuzz subroutines currently use the same interface. They take an integer for the number of elements to create and return an Array PMC containing the strings for each element. This makes them all easier to test.

    34      is( count, 10, 'test function should return the correct number of results' )

The first test is that calling the subroutine being tested and asking for ten elements should produce an Array PMC containing ten elements.

    36      results = test_sub( 100 )
    37      count   = results
    38      is( count, 100, '... based on start and end' )

That didn’t quite meet the FizzBuzz challenge though, so I tried it again with 100 elements. (I also worked in a very small step when developing the previous step; I hardcoded the tested subroutine to return an Array of 10 null elements.)

    40      .local string element
    41      element = results[0]
    42      is( element, '', '... with nothing for the first element' )
    43  
    44      element = results[2]
    45      is( element, 'Fizz', '... with Fizz for the third element' )
    46  
    47      element = results[4]
    48      is( element, 'Buzz', '... and Buzz for the fifth element' )
    49  
    50      element = results[14]
    51      is( element, 'FizzBuzz', '... and FizzBuzz for the fifteenth element' )
    52  
    53      element = results[17]
    54      is( element, 'Fizz', '... and Fizz for the eighteenth element' )
    55  
    56      element = results[19]
    57      is( element, 'Buzz', '... and Buzz for the twentieth element' )
    58  
    59      element = results[29]
    60      is( element, 'FizzBuzz', '... and FizzBuzz for the thirtieth element' )

This is the heart of the test now. With the returned results array, accessing individual elements should give the right answers for the FizzBuzz challenge. You’ve probably noticed, however, that all of the numbers are off by one. This is because Parrot’s array indices start at 0, not 1. I could have padded the array by one element if this were important, but noting it explicitly seemed sufficient.

    61  .end

Finally, this test function needs to end.

That’s the test code. It doesn’t yet meet the FizzBuzz challenge, and that’s not only because I haven’t shown the code for the tested subroutines yet. This doesn’t print anything, unless you consider test output.

Here’s the first part of examples/pir/fizzbuzz.pir:

     1  .namespace [ 'FizzBuzz' ]

The .namespace directive tells Parrot that all subsequent declarations should take place into a separate namespace. That’s unnecessary for simple example code, but it’s a good habit to avoid name clashes. (I wanted to write as real a program as possible.

     3  .sub 'main' :main
     4      .param pmc argv

Like the test file, this code has its own main function as well. What happens when Parrot loads it from the test file? Absolutely nothing. Only the first :main is the main.

However, this means that you can run this program on its own, because in that case this main function will execute. Line 4 gives access to the command-line arguments provided in that case.

     6      .local string sub_name
     7      sub_name = argv[1]
     8  
     9      if sub_name goto load_sub
    10      sub_name = 'procedural'

The first element of argv is the program name. That’s immaterial here. The real arguments start at index 1. I expect this program to take one argument, the name of the testable subroutine to run. If there’s no subroutine provided, default to procedural.

Line 9 might look a little awkward. Yes, goto is the main form of intrafunction control flow in Parrot. Remember that I called it an assembly language.

    12    load_sub:
    13      .local pmc sub_pmc
    14      sub_pmc = find_global sub_name

This code ought to look familiar; it uses the string name of a subroutine to (attempt to) fetch the associated Sub PMC. I say attempt because someone may provide an invalid name. I didn’t add any error handling to check for this condition, but the best approach is to make sure that sub_pmc contains a PMC that implements the Sub role somehow.

Note that this use of find_global is different; I’m calling it here from the same namespace where I’ve declared the testable subroutines, so I don’t need the namespace key that I used in the test file.

    16      .local pmc results
    17      results = sub_pmc( 100 )
    18
    19      .local pmc iter
    20      iter = new .Iterator, results
    21  
    22      .local string elem
    23      .local int count
    24      count = 1

Lines 16 and 17 should look familiar.

Lines 19 and 20 create an iterator. This is another type of PMC, used to iterate through an aggregate.

Lines 22 through 24 declare a couple of variables I want to use in the upcoming loop.

    26    iter_start:
    27      unless iter goto iter_end
    28      elem = shift iter
    29  
    30      print count
    31      print ": "
    32      print elem
    33      print "\n"
    34  
    35      inc count
    36      goto iter_start

Lines 26 through 28 are boilerplate for every use of a Parrot iterator that I’ve ever seen. 26 is the start of loop label, 27 is the end of loop condition, and 28 gets the current element out of the iterator into a PMC variable.

Lines 30 through 33 print the number of the current element and the current element. If it’s blank, it’s blank. Otherwise, it contains Fizz, Buzz, or FizzBuzz.

Line 35 increments the count variable, used for display purposes only (it started at one). Line 36 restarts the loop.

    38    iter_end:
    39      end 
    40  .end

The loop and the function end here.

The rest of the code actually does the important FizzBuzz work. I’ll show that tomorrow. In the meantime, I wonder how many people can build Parrot (or just read the documentation) and write their own version of these functions. procedural is easy, but keyed_array took a few minutes.