FizzBuzz!

Last week I saw an interesting video by Tom Scott about FizzBuzz and it made me have a think about programming.

The “Fizz-Buzz test” is an interview question designed to help filter out job candidates who can’t actually program. The problem is simply to write a program that prints the numbers from 1 to 100, except for multiples of three print “Fizz” instead of the number and for multiples of five print “Buzz”. For numbers which are multiples of both three and five print “FizzBuzz”.

Tom’s video discussed why it’s a good problem to weed out people who just can’t program at all, and he demonstrates one solution in Javascript:

for (var i = 1; i <= 100; i++) {
     var output = "";

     if( i % 3 ) { output += "Fizz"; }
     if( i % 5 ) { output += "Buzz"; }

     if( output == "") { output = i; }

     console.log(output) ;
}

As you can imagine there are any number of ways of achieving the same thing, but the point is that if you have no experience of programming you won’t even know where to start.

There are alternative approaches – Tom’s solution uses the output variable to avoid an extra check for divisibility by both 3 and 5, but some solutions use division by 15 to perform that check. You can argue about the relative performance of using an intermediate variable versus an additional mathematical operation, but that’s not really the point.

I think it’s an interesting way to illustrate a point about code style and canonicity. Let me explain…

I used to be a programmer. I use the past tense because it’s not really my main day job any more and most of the programming I do now is small scale scripting. I read more code than I write, usually trying to figure how something works. I like to think I can get a pretty good idea of what’s going on even in a language I haven’t really used – but that depends on the code style.

The more that the programmer has adopted the canonical conventions for the language in question, the harder the code is to read for someone who isn’t used to that language. Let me illustrate using Perl, which is renowned for there being more than one way to do it…

Here’s FizzBuzz pretty much transliterated from the Javascript version above:

for($i = 1; $i <= 100; $i++) {
     $output = "";
     if($i % 3 == 0) { $output .= "Fizz" };
     if($i % 5 == 0) { $output .= 'Buzz'};

     if($output eq "") { $output = $i }
     
     print $output, "\n";
}

Pretty much identical. The only real Perl-ism is the use of “eq” instead of “==” as the method of string comparison to check whether the output is blank. Any programmer reading that code should immediately understand what it does even if they don’t know Perl.

Here’s another version that’s maybe a bit closer to the way it would be done by a regular Perl programmer:

for(1..100) {
     my $output;
     $output = "Fizz" unless($_ % 3);
     $output .= "Buzz" unless($_ % 5);
     
     print $output || $_, "\n";
}

OK, so for this version you need to know that Perl creates a default variable called “$_” which is often used when a variable is not explicitly defined. In this case, it’s the index of the loop, which is created using the range notation 1..100.

The “my” statement declares the output variable local to the loop so it gets reinitialised each time.

The unless statement is a reverse of if, so the output will be built up unless there is a non-zero modulus value.

The print statement is also a common usage in Perl – if $output is true (i.e. not blank) it will be printed, or (“||” meaning or) the index number will be printed.

OK, so it’s probably still fairly clear. You may need a bit of Perl knowledge, especially to get where the “$_” comes from, but it’s not that hard to follow.

How about this one:

print 'Fizz'x!($_ % 3).'Buzz'x!($_ % 5) || $_, "\n" for 1..100;

The clue to that one is knowing what the “x” does. It returns the first value repeated the number of times specified by the second value.

So $_ % 3 is going to be 0 for exact multiples of three. Zero means false so if we negate that with the exclamation mark, we get a value of 1 for multiples of three, and we say “Fizz” once. Conversely, any other value for $_ % 3 will evaluate as true which is then converted to false (or zero) by the negation so we say “Fizz” zero times.

Repeat for Buzz, do the “or” to print the number if the whole lot is blank, stick the loop on the end and you have a one liner.

I’d say that even a reasonably regular Perl programmer would have to pause at that one and unpick it. It’s a pretty extreme example.

These are small scale examples, but they raise interesting questions for bigger projects. How many of the language specific tricks and features should you use? What’s the canonical way of doing something in the language and what’s best for maintainability? How do you get the balance between code an experienced programmer in that specific language will understand and code that can be understood by competent programmers who aren’t as familiar with that particular syntax? What happens when someone joins the project who has a specific liking for a certain feature unique to that language that you haven’t previously been using and maybe isn’t widely understood?

And this problem is made worse by there being too many programming languages…

It’s not uncommon to have to switch between several languages on a project – perhaps Javascript in the frontend, Python for the backend, maybe PHP… when you’re constantly switching between languages it’s probably better to stick to straightforward language constructs.

Language specific features should probably be added with caution and it’s never a good idea to be clever for the sake of it.

In other words, the second version of the Perl code probably strikes the right balance, but that’s, as always, a matter of opinion.

Let’s face it, there are enough gotchas in different languages without deliberately seeking them out…

Python, for example, has the range function that does the same thing as the Perl “for” construct I used above. So you’d think that Perl’s

for(1..100)

Would translate to Python’s:

for i in range(1, 100)

Right? Er, no. Perl’s version is a shortcut for a loop of the form:

for($i = 1; $i <= 100; $i++)

Python’s version would translate in Perl to:

for($i = 1; $i < 100; $i++)

Note that it’s “less than” rather than “less than or equal to”, so to run our FizzBuzz from 1 to 100, we’d need:

for i in range(1, 101):
     output = ''
     if i % 3 == 0: output = "Fizz"
     if i % 5 == 0: output = output + "Buzz"
     print output or i

The same one-liner trick also works in Python but the syntax is a bit different:

for i in range(1,101): print("Fizz"*(i%3==0) + "Buzz"*(i%5==0) or i)

In short, I think it’s always better to keep it simple. It doesn’t matter if the code is perhaps a little more verbose than it could be or not quite in the canonical style for the language you’re using. The most important thing is readability, which in turn leads to maintainability…

… And I say this as someone responsible for a moderately large Perl project who finds that sometimes he can come back to parts of the code a few years after writing it and not have the first clue how it works…

in Random Musings

Related Posts

Add a Comment

Your email address will not be published. All comments will be reviewed.