Politics and the Semantics of Programming Languages


C is the classic procedural language. It’s also known as a 2nd generation language, since it compiles to binary (1st generation). Literalists might call assembler a 2nd generation language, but since the major difference is merely the base notation, for clarity it’s best considered a 1st generation tool.

Smalltalk is often thought of as a 3rd generation language, and indeed some implementations do compile the Smalltalk code to C, then to binary, in much the same way as Java is converted to C and run in a virtual machine written in C. However the first Smalltalk versions were written in assembler, and as a result, from a literal perspective Smalltalk is, like C, a 2nd generation language.

So what’s the difference, sans literalism, between languages ‘considered’ 2nd and 3rd generation? This question becomes more cogent when you realize that a large number of ‘3rd generation’ languages were specifically written to look and feel like they used a similar syntax to C.

Below are a few examples, including actual C code, Smalltalk code, Objective C code and Java code. In each, the point is to create some sort of graphical window.

C (as it happens, this is old sample code to create a window in C on OS/2 version 2.x)

#define INCL_DOS /* Select part of header */
#define INCL_WIN /* Select part of header */
#define INCL_GPI /* Select part of header */
#define INCL_DEV
#include <os2.h> /* PM header file */
#include <stdio.h> /* PM header file */
#include <string.h> /* PM header file */
#include <stdlib.h> /* PM header file */

#define ID_WINDOW 255
#define MAXTXTLEN 255
/************************************************************************/
/* Function prototypes */
/************************************************************************/
MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 );
void DrawText(HWND hwnd,HPS hps,char *pszText);

HAB hab; /* PM anchor block handle */
typedef struct _SIMPLETEXT {
CHAR Text[MAXTXTLEN+1];
USHORT CurLength;
} SIMPLETEXT;
typedef SIMPLETEXT * PSIMPLETEXT;
/********************** Start of main procedure ***********************/
void main( )
{
HMQ hmq; /* Message queue handle */
HWND hwndFrame; /* Frame window handle */
HWND hwndClient; /* Frame window handle */
QMSG qmsg; /* Message from message queue */
ULONG flCreate; /* Window creation control flags*/
flCreate = FCF_SYSMENU | FCF_SIZEBORDER | FCF_TITLEBAR | FCF_MINMAX;
hab = WinInitialize( 0 ); /* Initialize PM */
hmq = WinCreateMsgQueue( hab, 0 ); /* Create a message queue */

WinRegisterClass( /* Register window class */
hab, /* Anchor block handle */
“MyWindow”, /* Window class name */
MyWindowProc, /* Address of window procedure */
0L, /* No special class style */
4 /* 1 extra window double word */
);
hwndFrame = WinCreateStdWindow(
HWND_DESKTOP, /* Desktop window is parent */
0L, /* No class style */
&flCreate, /* Frame control flag */
“MyWindow”, /* Client window class name */
“Simple Sample”, /* No window text */
0, /* No special class style */
0, /* Resource is in .EXE file */
ID_WINDOW, /* Frame window identifier */
&hwndClient /* Client window handle */
);
if (hwndFrame!=0) {
WinSetWindowPos( hwndFrame, /* Set the size and position of */
HWND_TOP, /* the window before showing. */
100, 50, 250, 200,
SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_SHOW
);
/************************************************************************/
/* Get and dispatch messages from the application message queue */
/* until WinGetMsg returns FALSE, indicating a WM_QUIT message. */
/************************************************************************/
if (hwndFrame!=(HWND)0) {
while( WinGetMsg( hab, &qmsg, 0, 0, 0 ) )
WinDispatchMsg( hab, &qmsg );
} /* endif */
}

WinDestroyWindow( hwndFrame ); /* Tidy up… */
WinDestroyMsgQueue( hmq ); /* and */
WinTerminate( hab ); /* terminate the application */
}
/********************* Start of window procedure **********************/
HPS hps; /* Presentation Space handle */
MRESULT EXPENTRY MyWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
{
PSIMPLETEXT pSimpleText;
RECTL clientrect; /* Rectangle coordinates */
CHAR ch;
CHAR Buffer[80];
POINTL pt;
HPS hpsPaint;
switch( msg )
{
case WM_CREATE:
pSimpleText =(PSIMPLETEXT)malloc(sizeof(SIMPLETEXT));
pSimpleText->CurLength=0;
pSimpleText->Text[0]=0x00;
WinSetWindowPtr(hwnd,0,pSimpleText);
break;
case WM_DESTROY:
pSimpleText=WinQueryWindowPtr(hwnd,0);
free(pSimpleText);
break;
case WM_PAINT:
hpsPaint=WinBeginPaint( hwnd,0, &clientrect );
pSimpleText =WinQueryWindowPtr(hwnd,0);
if (pSimpleText) {
DrawText(hwnd,hpsPaint,pSimpleText->Text);
} /* endif */
WinEndPaint( hpsPaint ); /* Drawing is complete */
break;
case WM_CHAR:
/******************************************************************/
/* Character input is processed here. */
/* The first two bytes of message parameter 2 contain */
/* the character code. */
/******************************************************************/
if( SHORT2FROMMP( mp2 ) == VK_F3 ) /* If the key pressed is F3,*/
WinPostMsg( hwnd, WM_QUIT, 0L, 0L );/* post a quit message to */
if( SHORT1FROMMP( mp1 ) & KC_CHAR ) { /* If it is a valid character */
pSimpleText =WinQueryWindowPtr(hwnd,0);
if (pSimpleText->CurLength>=MAXTXTLEN) {
pSimpleText->CurLength=0;
} /* endif */
ch=CHAR1FROMMP(mp2);
pSimpleText->Text[pSimpleText->CurLength]=ch;
pSimpleText->CurLength++;
WinInvalidateRegion( hwnd, 0, FALSE ); /* Force redraw */
}
break; /* end the application. */
case WM_SETWINDOWPARAMS:
pSimpleText =WinQueryWindowPtr(hwnd,0);
switch (((PWNDPARAMS)mp1)->fsStatus) {
case WPM_TEXT:
strncpy(pSimpleText->Text,((PWNDPARAMS)mp1)->pszText,MAXTXTLEN-1);
pSimpleText->Text[MAXTXTLEN-1]=0x00;
pSimpleText->CurLength=strlen(pSimpleText->Text);
return (MRESULT) TRUE;
break;
default:
return (MRESULT) FALSE;
} /* endswitch */
break;
case WM_QUERYWINDOWPARAMS:
pSimpleText =WinQueryWindowPtr(hwnd,0);
if (WPM_CCHTEXT & (((PWNDPARAMS)mp1)->fsStatus)) {
if (WPM_TEXT & (((PWNDPARAMS)mp1)->fsStatus)) {
((PWNDPARAMS)mp1)->cchText =
min(pSimpleText->CurLength,((PWNDPARAMS)mp1)->cchText);
} else {
((PWNDPARAMS)mp1)->cchText=pSimpleText->CurLength;
return (MPARAM)TRUE;
}
} /* endif */
if (WPM_TEXT&(((PWNDPARAMS)mp1)->fsStatus)) {
if (((PWNDPARAMS)mp1)->cchText>0) {
memset(((PWNDPARAMS)mp1)->pszText,0x00,((PWNDPARAMS)mp1)->cchText);
strncpy(((PWNDPARAMS)mp1)->pszText,
pSimpleText->Text,
((PWNDPARAMS)mp1)->cchText);
return (MPARAM)TRUE;
}
}
break;
case WM_CLOSE:
/******************************************************************/
/* This is the place to put your termination routines */
/******************************************************************/
WinPostMsg( hwnd, WM_QUIT, 0L, 0L ); /* Cause termination */
break;
default:
/******************************************************************/
/* Everything else comes here. This call MUST exist */
/* in your window procedure. */
/******************************************************************/

return WinDefWindowProc( hwnd, msg, mp1, mp2 );
}
return FALSE;

}
void DrawText(HWND hwnd,HPS hps,char *pszText) {
RECTL rcl; /* update region */
LONG cyCharHeight; /* set character height */
LONG cchText;
LONG cchTotalDrawn;
LONG cchDrawn;
FONTMETRICS metrics;
CHAR Buffer[80];
POINTL pt;
ERRORID Error;

Error=WinGetLastError(hab);
WinQueryWindowRect(hwnd, &rcl); /* get window dimensions */

/* WinFillRect(hps,&rcl,CLR_BACKGROUND);*/
GpiErase(hps);
cchText = (LONG)strlen(pszText); /* get length of string */
Error=WinGetLastError(hab);
GpiQueryFontMetrics( hps, sizeof(metrics), &metrics);
Error=WinGetLastError(hab);
cyCharHeight = metrics.lMaxAscender+metrics.lMaxDescender; /* set character height */

/* until all chars drawn */
for (cchTotalDrawn = 0;
cchTotalDrawn < cchText;
rcl.yTop -= cyCharHeight)
{
if (rcl.yBottom>=rcl.yTop) break;
/* draw the text */
cchDrawn = WinDrawText(hps, /* presentation-space handle */
cchText – cchTotalDrawn, /* length of text to draw */
pszText + cchTotalDrawn, /* address of the text */
&rcl, /* rectangle to draw in */
0L, /* foreground color */
0L, /* background color */
DT_WORDBREAK | DT_TOP | DT_LEFT | DT_TEXTATTRS );
if (cchDrawn) cchTotalDrawn += cchDrawn;
else break; /* text could not be drawn */
}
#ifdef DEBUG
pt.x=10;
pt.y=10;
sprintf(Buffer,”Height =%d, Total=%d, Ltext= %d Top=%d Error %p”,
cyCharHeight,cchTotalDrawn,cchText, rcl.yTop,Error);
GpiCharStringAt( hps, &pt, (LONG)strlen(Buffer), Buffer );
#endif
}

Smalltalk

Smalltalk is built around the MVC pattern, so first we have the domain model:

Object subclass: #TalkBox
instanceVariableNames: ”
classVariableNames: ”
poolDictionaries: ”
category: ‘UIApplications-New’!

!TalkBox methodsFor: ‘actions’!
goodbye
“Return a farewell message.”
^’Bye, now.’!
hello
“Return a greeting.”
^’Howdy, y”all!!’! !

Next we have the application model:

ApplicationModel subclass: #TalkInterface
instanceVariableNames: ‘talk message ‘
classVariableNames: ”
poolDictionaries: ”
category: ‘UIApplications-New’

Next we have the application methods:

initialize
“Initialize an interface instance.”
talk := TalkBox new

If you’ve been paying attention, we had an instance variable message that we haven’t created a method for. This is because the method is a generic Smalltalk method that has been inherited from Object, so we don’t have to write it. If we were to write it, it would look like this.

message
^message isNil
ifTrue: [message := String new asValue]
ifFalse: [message]

The last thing we need to write are the application specific methods, i.e. make the window do something:

goodbye
“Action when the Goodbye button is selected.”
message value: talk goodbye

hello
“Action when the Hello button is selected.”
message value: talk hello

That’s it, obviously we seem to have left a lot out, I’ll get back to why that’s the case later.

Objective C:

#import <Cocoa/Cocoa.h>
#import “AppDelegate.h”

int main(int argc, const char * argv[])
{
NSArray *tl;
NSApplication * application = [NSApplication sharedApplication];
[[NSBundle mainBundle] loadNibNamed:@”MainMenu” owner:application topLevelObjects:&tl];

AppDelegate * applicationDelegate = [[AppDelegate alloc] init]; // Instantiate App delegate
[application setDelegate:applicationDelegate]; // Assign delegate to the NSApplication
[application run]; // Call the Apps Run method

return 0; // App Never gets here.
}
-(id)init
{
if(self = [super init]) {
NSRect contentSize = NSMakeRect(500.0, 500.0, 1000.0, 1000.0);
NSUInteger windowStyleMask = NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask;
window = [[NSWindow alloc] initWithContentRect:contentSize styleMask:windowStyleMask backing:NSBackingStoreBuffered defer:YES];
window.backgroundColor = [NSColor whiteColor];
window.title = @”MyBareMetalApp”;

// Create a view
view = [[NSTabView alloc] initWithFrame:CGRectMake(0, 0, 700, 700)];
}
return self;
}

-(void)applicationWillFinishLaunching:(NSNotification *)notification
{
[window setContentView:view]; // Hook the view up to the window
}

-(void)applicationDidFinishLaunching:(NSNotification *)notification
{
[window makeKeyAndOrderFront:self]; // Show the window
}

Java Swing

 
package start;

/*
* HelloWorldSwing.java requires no other files.
*/
import javax.swing.*;

public class HelloWorldSwing {
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame(“HelloWorldSwing”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//Add the ubiquitous “Hello World” label.
JLabel label = new JLabel(“Hello World”);
frame.getContentPane().add(label);

//Display the window.
frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application’s GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

This example doesn’t have any application methods, meaning all it’s going to do is create a basic Swing window and display it.

The first thing everyone should have noticed is that the actual C program is extremely long, and a big part of the reason for that is that absolutely everything needs to be specified.
While there are plenty of C libraries that simplify things, in a sense a 3rd gen language is a huge set of libraries and a particular syntax to make them easier to use together, so in comparing the basic usage it would be ‘cheating’ to use something like QT.

The above, at the very least, should explain why most business programs aren’t written in C. Aside from the time spent, the more important reason is that the developer’s focus is on manipulating the machine, not on solving the users’ problems.
The difference between the three ‘object’ languages are, to me, more interesting.
1. While Objective C has the name ‘C’ in it, it looks more like the Smalltalk code, with keywords such as Self and a view component, part of the Model/View/Controller pattern.
(Java Swing is also MVC based, but in a slightly less obvious way). Part of the reason for this is that the target VM for Objective C code is precisely a Smalltalk VM.
2. I noted at the end of the Smalltalk code that, particularly compared with the C code, but even compared with Objective C and Java Swing there is simply less code written, never mind that the code is far less arcane.
Obviously to accomplish the same thing (and since Smalltalk doesn’t need an interim compilel to C, nothing is added by the compiler) similar code must be somewhere.
And of course it is, it’s in the Smalltalk environment itself, which is a virtual machine that contains all the base Smalltalk code plus your code and any libraries you use.
Since Smalltalk specifies a GUI, and even specific class/object browser designs, the code to create such windows is inherently part of the environment.
You can of course send a message to your window object that will changes its appearance, for example, but unless you want something other than the default, you don’t need to.
While that would seem to cause a constant growth of the environment, the Smalltalk developer keeps different VMs for different types of projects, and the runtime optimizer removes any classes not actually used, which in fact makes Smalltalk very efficient.
Smalltalk is in fact efficient enough that it has proven easier to write a complete operating system offering comparable performance to one written in C using Smalltalk than using C++.
This is the case despite the obvious advantage C++ has of being C compatible where C would be more ideal. Yet the original C++ version of Windows NT had to be rewritten in C for performance reasons.
NextStep, OS X and iOS, which are all functionally Smalltalk VMs, have no such issues. The first GUI OS of all, the Xerox Star, was written explicitly in Smalltalk and ran in 256k of RAM, which makes the claim that C is the best language for writing an OS (always the fallback answer to the question “why use C?”) at the very least questionable.  In fact, the usability advantages of iOS over Android and OS X over Windows could easily be attributed to the fact that C programmers are focused on arcane code syntax and not on solving the users’ problems to the same degree as Objective C and Smalltalk developers.

3. The Java code ‘feels’ more like the C code, although it’s much shorter and obviously Java Swing is taking care of a lot of details in the background.
Java has, due to the extensive set of libraries and frameworks available, largely caught up with Smalltalk in terms of developer efficiency. The question remains though why it caught on to a degree that Smalltalk didn’t, since obviously a terser and more natural syntax, if paired with an equivalent infrastructure ecosystem, would make Smalltalk appear more attractive to new programmers than Java.

The popularity of Java over Smalltalk (and the relative popularity of Objective C over Smalltalk, which is doubly odd given that it runs, at the end, in a Smalltalk VM) is solely due to this ‘feel’.  This desired feel is, of course, a feeling of control.
Programmers (particularly the type often disparagingly referred to as ‘code monkeys’ feel closer to the machine when writing Objective C or Java than Smalltalk.
This is, of course, not actually the case. In fact it could be argued that since Objective C compiles to Smalltalk, and Java compiles first to C, that Objective C and Java are further from the actual machine than Smalltalk.

A similar argument is often made in favour of command line interfaces and featureless editors like the variations on VI. VI is great, when you have no other choice. Using VI to write Java code when Netbeans and Eclipse are available, though, is simply myopic and unproductive, given how much tedious rote labour those environments save. 

 
In this context, the frustration experienced by a number of former C programmers learning Java in the ’90’s using VisualAge for Java crossed both these political minefields.  VA Java was written in, you guessed it, Smalltalk.  By default, and in order to allow command line compilation etc., a Java class is a file, a namespace (package) is a directory structure, i.e. com/mybusiness/myprogam/ProgramWindow.java.  VA Java dispensed with that and used the Smalltalk repository convention – a class is a structure in a repository.  You could copy and paste it into a text file, but it won’t ‘work’ except in a Smalltalk VM, so what would be the point?  The irony of course is that exactly the same is true of a Java class, compiling it or running it from the command line simply implies that you’re starting a Java VM on the command line and telling it where to load your class / library / application.  However, since the program code is stored in files on a filesystem, and not in a repository, teamwork requires that it be precisely loaded into a shared repository such as CVS, SVN, GIT etc.  So at the end it was pulled out of a code repository, only to be put back in a code repository.
One would think that a programmer versed in systems architecture and virtualization would be the last person to be ‘taken in’ by a simplistic interface, believing it to be more ‘real’ in some vague sense, but ideology and politics always wins over evidence and knowledge.

 

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s