It's Just Syntax

Previous Home Next

I feel a little guilty about all of the Lisp code in the last entry. I talked a lot about the benefits of object-oriented programming but I showed you hardly a scrap of code from a language specifically designed to support object-oriented programming such as Java or C++. I know it's just syntax but I also know from experience that struggling with unfamiliar syntax can be frustrating - hence my reluctance to code in Java or C++ simply because I'm less familiar with the syntax. Trading parentheses for curly brackets and semicolons and different formatting and commenting conventions and different names for often-used functionality is more than a little disorienting and some times important concepts can get lost in translation. I have so say in this case that the PLT Scheme class.ss library did a very good job of capturing the most important features of object-oriented programming by mapping object-oriented-programming concepts directly onto appropriate Scheme syntax.

Syntactic sugar refers to features added to a language that make it more palatable for humans but that don't affect the ability of the language to specify computations (such features neither increase nor decrease the expressiveness of the language). Syntactic sugar is meant to encourage programmers to write better code by hiding features that are seldom useful and might distract someone trying to make sense of the code or features that are difficult to use and can lead to bugs. Contrast syntactic sugar with syntactic salt which makes it more difficult to write good code and syntactic saccharin (also called syntactic syrup) which introduces gratuitous syntax that serves no useful purpose. Some programming language mavens believe that syntactic sugar can itself be distracting or that the need for it in a programming language provides evidence that the language was poorly designed ("Syntactic sugar causes cancer of the semicolon" from Alan Perlis's Epigrams in Programming). A programmer addicted to syntactic sugar is less likely to understand or use the features that the sugar sweetens by masking.

I mention syntactic sugar in preparation for my defense of introducing object-oriented concepts using Scheme (I have an annoying tendency to become defensive in anticipation of controversy even when the prospects for controversy are remote). The PLT Scheme implementation of classes does abstract away some important features of Java and C++, specifically the requirement of declaring the types for all variables, constants and return values of functions. But these features are not pertinent to object-oriented programming per se and individual preferences regarding parentheses versus curly brackets are similarly beside the point. Therefore it's my feeling that any sugaring in the notation introduced in class.ss is of the good sort. However, I'm also sensitive to the criticism that syntactic sugar constitutes more syntax and too much even of a good thing can rot your stomach.

I've spent all this time justifying my approach and I'm still feeling guilty and so I feel compelled to show you some "real" object-oriented programming syntax. I spent an hour this morning translating the classes that I designed using the class.ss library into Java classes. I was pleased with how easily the translation went and how directly the abstractions in class.ss mapped onto standard Java abstractions. Showing off the code will require that I use some tools from the Sun Java Development Kit (JDK) but we've never shied from introducing new tools and inscrutable (and all too briefly explained) notation in the past so I don't know why we should start now. Also we'll be using a somewhat different style of developing and executing programs than we're used to in interacting with a Lisp interpreter.

To implement the necessary classes and demonstrate their use, I created three files: one file for each of the Date and JournalDate classes and one file for a class called TestDate to demonstrate that the code actually works. TestDate doesn't have any associated instances and exists only so that I can call its main procedure to build some instances of the Date and JournalDate classes and apply methods to these instances to demonstrate that the classes work as advertised.

% ls
Date.java    JournalDate.java    TestDate.java

Here's what the code for the DateInterface interface and Date class look like. Again we've kept it simple for illustration purposes; the Java code implements the same behaviors as the Scheme code. In Java Object is the base class. I've added some navigation so you can jump back and forth between the Scheme and Java implementations. I use the Unix cat program to print the Date.java file to my terminal from the shell. I won't explain the Java syntax in any detail except to note that the DateInterface describes the interface that the Date class implements and the Date class defines four methods, year, month, day and before, in addition to explicitly defining the Date instantiator.

% cat Date.java
interface DateInterface {
    public int year ();
    public int month ();
    public int day ();
    public boolean before ( Date that );

}
Scheme Version
class Date extends Object implements DateInterface { protected int year, month, day; public int year () { return year; } public int month () { return month; } public int day () { return day; } public boolean before (Date that) { if ( year > that.year ) return false ; else if ( year < that.year ) return true ; else if ( month > that.month ) return false ; else if ( month < that.month ) return true ; else return ( day > that.day ) ; } public Date (int y, int m, int d) { year = y; month = m; day = d; } }
Scheme Version

Next we have to compile the above code using javac, the Java compiler, which converts the Java source code, e.g., the contents of the Date.java file, into Java bytecodes. Most compilers produce assembly code which is then converted by an assembler into machine code to run on a particular machine. The Java compiler produces bytecodes which constitute the machine code for the Java Virtual Machine (JVM). Java bytecodes run on any machine that has an implementation of the JVM. The JVM is a piece of software that has been ported to run on lots of different machines and that serves to simulate a virtual or software machine. This isn't much different from how the Scheme interpreter, a piece of software that has to be written and compiled to run on a particular machine, executes Scheme code. There are differences between Scheme code and Java bytecodes but not enough to loose any sleep over. I suppose it can be argued that Java bytecodes will run in the JVM faster than (uncompiled) Scheme code will run in the Scheme interpreter but there are so many nuances that it isn't worth worrying too much about. Much ado about nothing as far as I'm concerned. Let's invoke the compiler.

% javac Date.java

I won't bother to do a listing of the directory (ls) but now there is a file called Date.class in the directory along with Date.java. Date.class contains the compiled version of the Date class. Now I'll show you the file implementing the JournalDate.java class. Note that it begins by declaring its dependence on the Date class and then proceeds to extend DateInterface before getting around to describing the JournalDate class. Here as in the Scheme version I invoke the instantiator, called super in Java, for the superclass, Date.

% cat JournalDate.java
import Date;

interface JournalDateInterface extends DateInterface {

    public void iso ( );

}
Scheme Version
class JournalDate extends Date implements JournalDateInterface { protected String yearString, monthString, dayString ; public void iso () { System.out.println( yearString + "-" + monthString + "-" + dayString ); } public JournalDate (String y, String m, String d) { super( Integer.parseInt( y ), Integer.parseInt( m ), Integer.parseInt( d ) ); yearString = y; monthString = m; dayString = d; } }
Scheme Version

Compile the code in JournalDate.java.

% javac JournalDate.java

TestDate.java contains the description of a class, TestDate, whose only purpose for being is to run its main method to exercise the code in Date.java and JournalDate.java. It's not very fancy; it just creates an instance of JournalDate and then invokes the iso method on the instance.

% cat TestDate.java
import JournalDate;

class TestDate {

    public static void main(String[] args) {

        JournalDate today  = new JournalDate ( "2002", "08", "28" );

        today.iso ();

    }

}

It has to be compiled just like all the other classes.

% javac TestDate.java

Now we list the contents of the directory and notice compiled versions for all of the classes and interfaces.

% ls
Date.class                  JournalDate.java
Date.java                   JournalDateInterface.class
DateInterface.class         TestDate.java
JournalDate.class           TestDate.class

In order to run the program that we just compiled we use Java interpreter which called simply java.

% java TestDate
2002-08-28

Not very interesting output but at least it appears that the iso method defined in the JournalDate class works according to our expectations. To give you a little more of an idea of how objects are used in Java code, note that if in defining a procedure I was to declare and instantiate two JournalDate objects as follows:

    JournalDate today = new JournalDate ( "2002", "08", "28" );
    JournalDate yesterday = new JournalDate ( "2002", "08", "27" );

Then, later in same procedure, if I were to write today.before(yesterday) and yesterday.before(today), then these statements would evaluate to false and true, respectively, thereby exercising the (inherited) methods in the superclass Date of the JournalDate class.

So that's about it: inheritance, interfaces, public and private methods; all good stuff from what I hear tell. But remember that a major part of what makes it all work is in your head, the discipline and good sense you bring to designing good code. No amount of fancy syntax, sweet, sour, salty or otherwise, is going to turn you into a good programmer if you don't have discipline and common sense in good measure. Java is a nicely designed language and I wouldn't be surprised if it was now my favorite language had it been the first language that I did any serious programming in. But it wasn't and it isn't and lucky for me my favorite language is alive and well, thankyou very much.

One of my students, Luke, on reading parts of the first installments of this journal remarked that he felt that each entry was like the forward to a textbook but less formal. In a forward, the author tries to convey his or her excitement and enthusiasm for the subject matter of the book, but, in the case of technical material, eventually has to get down to brass tacks and explain the details which can be, if not handled very skillfully, a little tedious. I get to skip blithely from subject to subject leaving the reader to track down the details or chose not to. I like Luke's characterization; it does a good job of capturing some of what I'm up to - the rest, I'm not sure of myself.