Few people have ever heard about the Smalltalk programming language, even less people know how to program in Smalltalk, and even less actually program in Smalltalk in these days. Nevertheless I think it is a beautiful language, and it played an important historical role.
First of all, for the unaware, here I write a brief history and description of Smalltalk.
Smalltalk is chronologically the second object-oriented programming language, following Simula, and the first interactive and interpreted object-oriented programming language, as Simula was an only-natively-compiled language, with no integrated development environment. In addition, Smalltalk was, together with Lisp, the first programming language having a graphical integrated development environment. It was developed iteratively in a research laboratory in the ’70, until the specification of 1980, whose implementation that was marketed in 1983. It influenced particularly Objective-C and Ruby.
As far as I know, all implementations of Smalltalk compile Smalltalk source code to bytecode (Java copied Smalltalk, and not vice versa). And most implementations of Smalltalk just interpret that bytecode, although there is at least one native code just-in-time compiler.
The most distinctive feature of Smalltalk implementations (actually featured also in Lisp environments and in other research environments) is that there is no distinction among the development environment, the standard tools and libraries, the vendor supplied tools and libraries, the third-parties supplied tools and libraries, the locally developed tools and libraries, the applications developed for the customer of the developer. In a Smalltalk environment, there is just one huge application, whose state can be saved in a single file named “image”. That application is the graphical IDE, with all its drivers, tools and libraries. Building an application means build another tool is the toolset. Delivering the application is delivering all the development environment with the new tools. This is not the way software is commercially developed.
Actually some corrections have been applied to support software developers. First of all, it is possible to deliver only Smalltalk bytecode without delivering the source code. This is a partial solution to close the source code, as Smalltalk bytecode is rather easily de-compiled. Second, some tools have been produced to clean the environment removing all the libraries not actually used by the specified application. Therefore, if our customer do not need to use the debugger, the code of the debugger is removed from the image when the release package is built. This is not a really satisfactory solution either, as the package preparation is lengthy, and the resulting image is typically large as it contains still a lot of classes, the Smalltalk compiler, and the Smalltalk virtual machine. This was too much for the personal computers of 20 years ago, even if for today computers it is no more a problem.
The Smalltalk environments contains a virtual machine that interfaces the Smalltalk with the platform. The first Smalltalk implementations were based on the bare metal, without an operating system. Then, some Smalltalk implementations came that were based on the kernel of the operating system and on the graphical hardware, but weren’t based on a graphical user interface. At last, some Smalltalk implementations came that were based on a graphical user interface. Implementations based on the bare metal were very efficient, but didn’t allow any software not written in Smalltalk. The implementations based only on the kernel of the operating system were somewhat less efficient, and allowed software not written in Smalltalk, but had the same user interface look-and-feel on any system; sometimes such behavior was desired, but more and more users prefer a user interface compatible with the conventions of the environment. This delay in conforming the user interface of the application with that of the environment contributing to the low popularity of Smalltalk among software developers.
Now, I present the most fascinating aspects of Smalltalk.
First of all the method call syntax is beautiful. There are three possible syntactical forms to call a method:
If the method is a know infix operator, like “+”, “<=”, and others, the syntax is infix; for example “a + b” calls the method “+” of the class of the object “a” and passes to such method the argument “b”.
If the method has no arguments like “not” (logical negation) or “cos” (trigonometrical cosine), it is just postponed; for example “a not” is the negation of “a” and “35.6 cos” is the cosine of 35.6.
If the method requires one or more arguments, they are put after the name of the function and a semicolon, with another name and another semicolon for every argument; for example “a shiftBy: 3” calls the method “shiftBy:” on the object “a”, passing to it the argument “3”, and “a find: b from: 1 to: 3 ifNotFound: [c show]” calls the method “find:from:to:ifNotFound:” on the object “a”, passing the four arguments “b”, “1”, “3”, and “[c show]”, where “c show” is a code snippet, or lambda function.
If Lisp code has too many parentheses, so that its name is jokingly interpreted as “Lots of Irritating Superfluous Parentheses”, Smalltalk code uses very few parentheses, only to force precedence, making a more readable code.
Smalltalk is a dynamically typed language, meaning that its variables do not have a type. Only the objects that they reference at run-time have a type. But differing from many other dynamically typed languages, in Smalltalk it is necessary to declare variables, in a very simple way.
The following line:
| msg count sum |
that is to be put at the beginning of a method, declare the three variables “msg”, “count”, and “sum”, setting there value to “nil” (meaning “null” in other languages). Then, in that method, “msg” may refer to a string, “total” to an integer number, and “sum” to a floating-point number. The need to declare variables is a good aspect, because it prevents that typos go unnoticed.
Smalltalk is extremely flexible, much beyond necessity, and that is not good for clarity. Even control structures, like “if” and “while” are methods with standard syntax, and they may even be reimplemented by the programmer. To improve performance, their default behavior is implemented in machine language. I consider that uniformity quite absurd and useless.