Monday, November 19, 2007

Syntax Versus Solution

But which came first, the Word or the Thought behind the Word?
--Lorien, Babylon 5 "Whatever Happened to Mr. Garibaldi"

Our language frames our thoughts, and this is as true for computer languages as it is for any other written form. Like everything else under the computer science umbrella, programming languages are evolving quickly. If you want to keep up as a programmer, you have to be prepared to evolve too. Today I'm going to show a trivial example of the sort of things that we run across, when moving from one language to another. For this exercise, I'll start off with a simple C++ program, and move it to Ruby.

Statically typed, compiled, and designed for efficient computer cycle usage, the C family of languages (C, C++, Objective-C, etc.) is the only game in town for whole classes of applications from tiny devices to huge online games to operating systems. A simple program written in C++ looks like this:

#include <iostream>
#include <cstdlib> //For random number generator.
#include <ctime> //To seed the random generator.

int d100(){
  return ( (rand() % 100) + 1 );

void main(void){
  int roll = d100();

  char * type;
  if ((roll >= 1) && (roll <=5)){
    type = "stormy";
  else if ((roll >= 6) && (roll <= 20)){
    type = "rainy";
  }//else if
  else if ((roll >= 21) && (roll <= 40)){
    type = "cloudy";
  }//else if
  else if ((roll >= 41) && (roll <= 60)){
    type = "mostly cloudy";
  }//else if
  else if ((roll >= 61) && (roll <= 95)){
    type = "fair";
  }//else if
  else if ((roll >= 96) && (roll <= 98)){
    type = "windy";
  }//else if
  else if (roll == 99){
    type = "snowy";
  }//else if
    type = "raining toads";

  cout << "The weather today will be: " << type << endl;

Ruby's dynamic typing and interpreted code belongs to a very different paradigm than C++, but it is a testament to the pervasiveness of C that when changing the program to use the Ruby language, you can use almost the same syntax:

def d100()
  return (rand(100) + 1)

roll = d100()

type = nil

if ((roll >= 1) && (roll <= 5))
  type = "stormy"
elsif ((roll >= 6) && (roll <= 20))
  type = "rainy"
elsif ((roll >= 21) && (roll <= 40))
  type = "cloudy"
elsif ((roll >= 41) && (roll <= 60))
  type = "mostly cloudy"
elsif ((roll >= 61) && (roll <= 95))
  type = "fair"
elsif ((roll >= 96) && (roll <= 98))
  type = "windy"
elsif (roll == 99)
  type = "snowy"
  type = "raining toads"

puts("The weather today will be: " << type)

Whee, we have a program in two languages that works identically and looks pretty much the same too. What exactly have we gained here? Nothing, yet. Just as you can abuse a written language to produce grammatically acceptable gibberish (bureaucratized corporate memos come to mind), so too can a computer language be used less than efficiently. And this program isn't going to be considered good Ruby style by any regular user of the language. To get things done in a more Ruby-ish way, we use the language's more flexible case statement, built in range support, and statement evaluation behavior to knock the whole thing down to a single expression:

puts("The weather today will be: " << 
  case (rand(100) + 1)
    when 1..5 then "stormy"
    when 6..20 then "rainy"
    when 21..40 then "cloudy"
    when 41..60 then "mostly cloudy"
    when 61..95 then "fair"
    when 96..98 then "windy"
    when 99 then "snowy"
    else "raining toads"

And that is definitely not something I would want to try with C++.* Such a trivial example doesn't give anyone great insight into the languages in question. However, if you look at where we started and where we ended, you can begin to see how working regularly with either language could make you tend toward slightly different ways of solving the same problem. Luckily, programming languages are vastly easier to learn than human languages, but just learning the syntax of a language often isn't enough. As programmers, we should strive to be as aware of the mental trade-offs needed to make the best use of the different languages as we are of the technical trade-offs.

*In the tradition of lecturers everywhere, I note that it is entirely possible to write this program as a single expression in C++. Actually doing it, I leave as an exercise for the reader. (Feel free to post your solution in the comments!)

1 comment:

Jeff said...

call brianpritchard(hows_the_weather);