21 October 2010

Patterns and Practices: Scope and Type Inference Through Syntactic Sugar

Code Complete

Once again I'm referring to Code Complete. Code Complete taught me a lot of things and coding style is one of those that I hold important to this day. Let me preface this by stating that Code Complete was built around C++ and later C# coding, still I believe that utilizing coding style that is indicative of scope and usage makes programs more maintainable. I also believe that more maintainable code can more easily be proven to work and be proven to be correct. Many programming languages, especially dynamically typed programming languages, which are typically scripting languages, use syntax to identify scope and possibly type. Here are some examples:

From C++
#include <iostream>
#include <string>
using namespace std;

class MyObject
{
private:
 string name;
public:
 MyObject(const string & name);
 string getName();
};

// The :: token indicates the relationship of this function definition.
MyObject::MyObject(const string & name)
{
 this->name = name; // this indicates the relationship of the left name versus the right name.
}

string MyObject::getName()
{
 return this->name;
}

int main()
{
 MyObject object("Object 1");

 cout << "First object's name: " << object.getName() << endl;

 return 0;
}
From Ruby
class MyObject
 attr_reader :name # The : prefix indicates that name is a symbol.
 
 def initialize(name)
  @name = name # The @ prefix indicates the relationship of the left name versus the right name.
 end
end

object = MyObject.new("Object 1")

puts "First object's name: " + object.name
From Python
# Tabs indicate containers in Python - there are no curly braces or end statements.
class MyObject:
    def __init__(self, name):
        self._name = name # self and _ indicates the relationship of the _name to the class.
        
    def getName(self):
        return self._name
        
object = MyObject('Object 1')

print "First object's name: ", object.getName()
From Perl
package MyObject;

sub new {
 my $class = shift; # The $ prefix indicates that the variable is a scalar.
 my $self = {
  _name => shift
 };
 
 bless $self, $class;
 
 return $self;
}

sub getName {
 my($self) = @_; # The @ prefix indicates an array.
 
 return $self->{_name}; # The { and } dereference hash values by key.
}

package main;

$object = new MyObject("Object 1");

print "First object's name: " . $object->getName();
1;
Anyway hopefully you get the point that many languages hint in some way how to use certain keywords. C++, a heavily typed language, requires you to signify who a method belongs to. The main or global context is inferred, but a class context requires ::. In Ruby a single colon, :, indicates a symbol, and you can reference that symbol in a class via @symbolName. Python requires tabs to indicate contained code or code in a container, such as a function or a class. And finally in Perl (where everything is a string) there are several indicators or what kind a variable is or how to use it, for example $ = scalar, % = hash, @ = array. All of these things are essentially syntactic sugar.

...and Scope Inference

In Code Complete there are several hints to infer scope in a program. Some of what I am about to show you were developed somewhat more by a team I worked on recently.

SyntaxConditions
PascalCasing
  • Namespaces
  • Class names
  • Method names*
  • Properties and public fields
IInterfaceName
  • All interfaces
TGenericType
  • All generic types
  • All template types
_camelCasing
  • Private class-scoped fields
__camelCasing
  • Private class-scoped static fields
camelCasing
  • Method arguments
  • Method-body-scoped variables
  • Method names*
* this may vary depending upon language
Using these scope hints it is very simple to see what the purpose and scope of each object is. For example if I see a variable named _name then I instantly know that it is privately owned by a class, or in the case of the Python example I know that I should not change it manually (Python doesn't have a private class scope).