📜 ⬆️ ⬇️

Unknown Smalltalk



Dear Habr readers. First of all, I want to explain what the review of the Smalltalk language does in the corporate blog FLProg. The fact is that both the FLProg program itself and the program’s website are written in this wonderful language. Its capabilities and tremendous development speed on it allow me alone to maintain and constantly increase the functionality of both the site and the program. If you're wondering how I do it, I ask for cat.

First, a little background. Nine years ago, I worked at an industrial company as a circuit engineer. He drew schemes, and at his leisure he wrote small programs on dolphies to facilitate a harsh engineering life. The programs gradually began to diverge in the collective, the management noticed this and an application programming department was created. To help me, I was hired by a professional programmer, who recently completed a project. So he introduced me to the Smalltalk language in which his previous project was implemented. Honestly, the first reaction from this language was negative. He broke all my ideas about programming. Breaking lasted about three months, after which I fell in love with Smalltalk and still prefer to work only on it, although during this time I had to learn a few more others.
Since the narrator is not very good of me, I will widely use materials from the Russian Wikipedia dedicated to this language and arrange these materials as quotations.
History of the language:

Smalltalk was created by a group of researchers led by Alan Kayem at the XEROX Palo Alto Research Center. The first implementation, known as Smalltalk-71, was created several months later as a result of the argument that a programming language based on the message idea suggested by the Simula should be implemented on a “code page”. A later version, really used for research work, is now known as Smalltalk-72. Its syntax and model of execution differed greatly from modern Smalltalk, so much so that it should be considered as another language.
After significant revisions that fixed several sides of the execution semantics to increase efficiency, a version known as Smalltalk-76 was created. In this version, inheritance has been added, the syntax is closer to Smalltalk-80, and the development environment includes most of the tools familiar to Smalltalk-esters.
The first years of the life of a language are described in Kay's remarkable essay The Early History of Smalltalk ( HTML ).
In Smalltalk-80, metaclasses were added, which made the phrase “all objects” true by associating properties and behavior with individual classes (for example, supporting various ways of creating instances). Smalltalk-80 was the first version available outside PARC, first as the Smalltalk-80 Version 1 distributed to a small number of companies and universities for “peer review”. Later (in 1983), a publicly available implementation, known as Smalltalk-80 Version 2, became available as an image (a platform-independent file containing objects) and a virtual machine specification.
There are now two Smalltalk implementations that are direct descendants of Smalltalk-80. This is squeak and visualworks. How Smalltalk-80 looked like can be seen in the screenshot. The Smalltalk-80 version 2 image is launched on Hobbes, the ST-80 virtual machine implemented on VisualWorks.
Smalltalk has had a great influence on the development of many other languages, such as: Objective-C, Actor, Java and Ruby. Many of the ideas of the 1980s and 1990s on writing programs (Class-Responsibility-Collaboration card) have appeared in the Smalltalk community, such as design patterns (as applied to software), extreme programming and refactoring. The founder of the WikiWiki concept, Ward Cunningham, is a member of the Smalltalk community.

')
To date, the latest version of the language - 8.0, released in September 2014. Specifically, I work on the implementation of VisualWorks and the story will be devoted to him.

Smalltalk is an object language, so it will be appropriate to recall the basic principles of the PLO (as they were formulated by Alan Kay):
An object is the basic unit of an object-oriented system.
Objects may have a state.
Sending a message is the only way to exchange information between objects.
In addition, the Smalltalk object model is built on classes, which means:
Each object belongs to a class.
The functionality of an object is determined by its class (set of its methods).
Classes are organized into a hierarchy.
Classes inherit functionality from ancestor (or ancestors).
Here, in fact, that's all. Although you can further emphasize some principles and clarify others:
Everything in Smalltalk is an object. Those. everything Everything. There is nothing that is not an object.
In Smalltalk, there are four types of actions — sending a message, assigning it, returning a value from a method, or invoking a primitive virtual machine.

A little from myself. All variables in objects are pointers. There is no concept of dereferencing a pointer, variables are always references to an object. Secondly, Smalltalk is a dynamically typed language. That is, in any variable you can put a link to the instance of an object of any class. Accordingly, there is no concept of casting. Thirdly, the language is a very advanced garbage collector, so almost never have to use the methods of destruction of the object. In the case when there is not a single link to the instance instance, it is quickly destroyed by the collector and the memory is freed. Of course, this is a very simplified description of the garbage collector, but memory leaks in Smalltalk are very difficult (I have never succeeded).

Smalltalk architecture

Any Smalltalk system (development environment, separate executable program, etc.) consists of two parts - a virtual machine and a system image.

Virtual machine

The virtual machine contains the basic functionality: a bytecode handler (in the form of a JIT compiler or interpreter), a memory management system (with garbage collector) and primitives. (Primitives are functionality that, for whatever reason, turned out to be more convenient or advantageous to implement not in Smalltalk, but in a virtual machine. Usually, this is the functionality of the lowest level, such as adding numbers or drawing a point on the screen.)

System image

A system image (image) is a file that stores all the objects of the Smalltalk system between work sessions. These objects include executable programs, created objects, classes, etc.
When the Smalltalk system is running, all actions, of course, are performed in the computer's memory. When you exit the environment, you have the choice to either keep the current state of the system image or not. If you save the image of the system, then the next time you start the entire environment will be restored as accurately as possible - up to the position of the windows and cursor positions. This happens because the states of all objects are saved (and then restored).

The system image is the main container of information in Smalltalk - i.e. Smalltalk source text files are not accepted. In principle, they can be created, but it is much more convenient to work with the image of the system.


Currently, there are virtual machines under Windows x86 (works fine under Windows x64), Windows x64, Linux 32, Linux 64, Solaris, Mac Oc. To switch to another platform, it is enough to enclose the necessary virtual machine to the system image. In the code, it is sometimes necessary to provide different behaviors for specific API calls, but most of these issues have already been resolved in the base classes. For example, working with the file system does not require any changes at all when switching to any platform. I needed to refine the code when porting to Linux only in the field of work with the Com port, and it took no more than a couple of hours.

It was all theory, and now to practice.
The big advantage of Smalltalk is that there is no need to set the environment on the machine. It is possible to create a folder on a flash drive, put three files there and the workplace is always with you. You can work on any machine, even on someone else's, even without administrator rights, and after removing the flash drive, no trace of work remains.

The main working environment of Smalltalk:

Class browser


Workspace


Class Browser stores all program code representing a set of project classes and base classes of the language. It is the main work. It should be noted that all classes are “living”, that is, at any time you can call any class, create its instance, and make the necessary changes. For all this serves Workspace. You can write and execute any code in its working field.

There are many ways of programming, but for myself I chose the “Programming through debug” method. I did not invent it, but I spied on a meeting of programmers on Smalltalk, which took place in St. Petersburg about eight years ago. Unfortunately, I do not remember the speaker. As far as I know other languages, in no other way will this method be possible. The fact is that Smalltalk allows you to stop the program at any time, make a correction to the code and continue with the breakpoint. It is difficult to explain, easier to show.


To store the history of the project, it is desirable to have a database for the version control system. In Smalltalk, it is implemented on the basis of a database, and can work on almost all known database engines. I have PostgreSQL installed on the server, and I can connect to it from anywhere in the presence of the Internet. The version storage system supports storing code histories from the very beginning, creating code branches, different branches, the ability to roll back to any version. In addition, it is possible to view the history of changes of any method in the system, and download the required version of a particular method.
But the presence of such a database is not mandatory. In addition to the system for storing code in the repository, there is also a ChangeList. It automatically saves all changes to the code since the start of work in the image. With it, you can restore all changes, for example in case of a system crash (this sometimes happens when experiments are too rough), turn off the computer, for example, when you turn off the power. In this case, it is possible to restore only the necessary methods, excluding, for example, erroneous ones. As in the case with the version storage system, you can view all the changes of a specific method, and, if necessary, restore any version.

And finally, the most delicious features of Smalltalk are DEBUG and REFACTORING. And I did not just write them in capital letters.
Let's start in order.
A debugger built into Smalltalk in case of an error in the code stops the program from running at an error point, allows you to view the stack of methods with viewing the contents of all variables, make a change in any of the previous methods, change the contents of variables, and start the program from any one of them further. But this is also easier to show than to explain.


As I said in the video, this is only a small part of the possibilities for solving errors, implemented in the language. A full description of these features, perhaps pull on a small book.
Refactoring. Key features:
Change the name of any class, method with automatic tracking of all calls and mentions. In this case, the choice of changeable methods is given.
Changing the name of a variable, with automatic tracking of the use of this variable within the class. Here it is necessary to clarify. All variables in Smalltalk are private. That is, they are available only within the class in which they are created. External access only through accessors (getters and setters). Accordingly, the methods that can use a variable are present only within the same class.
Add or remove method parameters with automatic modification of all calls to this method.
The ability to view all method calls, as well as view all references to the class.
Well, and many other features that deserve separate consideration. Just want to show it in the work.


Here are a few language features that break the programming patterns in the early stages of exploring the language.
Priorities of mathematical operations. They simply do not. Since numbers are the same objects as everything else, then operations are ordinary methods. And performed in the usual sequence. For example.
a: = 1 + 2 * 3/4.
How will this be done in ordinary language? As far as I remember (if wrong, correct) 2 multiplied by 3, then the result will be divided by 4 and 1 will be added.
On the small one, 2 will be added to 1, the result will be multiplied by 3 and divided by 4. You just need to remember this and do not forget to use brackets. In order to perform actions in accordance with the result in ordinary language, it is necessary to write this:
a: = 1+ (2 * 3/4).

Collections Collections are analogous to arrays in other languages. There are many and different ones (Set, OrderedCollection, ByteArray, etc.). By the way, a string is the same collection, and most of the methods related to the collection apply to it. The first feature in the collection may be objects of completely different classes. The second, the most unusual for any programmer, feature of the collection is that the indices start with 1 and not with 0. Accordingly, the first character in the line has an index of 1. And in any collection as well. To this the same need to get used to.
Well, the third - the main thing. No primitives. All are objects. Even Class is an instance of the Metaclass class.
Metaclass is the Metaclass instance. Here is a ring on the top.

Well, a little more about goodies.
Calculations without loss of accuracy. The main problem in many languages ​​is the loss of accuracy when dividing. For example: 1/3 is 0.3333 and 3 in the period. Accordingly, in other languages, the number of decimal places is specified, and accuracy is lost. In Smalltalk, this problem was solved very beautifully. As a result of this division, we get the number of the class Fraction. It contains the numerator (1) and the denominator (3). That is, there will be no division per se, but a fraction. We lose nothing. And all subsequent operations are subject to the rules for working with fractions. When you need to get a decimal number, just say this object asFixedPoint: with the required number of decimal places and get the result. In this case, the number itself remains unchanged, and we can continue to conduct calculations without loss of accuracy. In other languages, I have not seen this.

Serialization of the object structure. I know two packages: BOSS and SIXX.

BOSS - saves any object structure to the file while preserving the uniqueness of the objects. Saves very quickly to a binary file. Keeps very compact. There are downsides. When any change in the declaration of saved objects (adding, deleting variables, changing the name of variables, etc.), the file is not subtracted back. For my tasks did not fit.

SIXX - saves any object structure to the file while preserving the uniqueness of the objects. Saves slower than BOSS, and the file is larger. The file is text, something like XML. Great advantage. In the saved classes, you can safely delete, add variables, it is undesirable only to change their names. If a variable is added, then when it is read from the file, it is initialized by nil. This behavior allowed me to open projects saved in the first versions in the program, although much has changed in the project since then.

Work with databases. I use the GLORP package included in the base package. The package is used to save the database and restore to the database of objects of any complexity. For objects stored in the database, it is necessary to describe once the way to save them, and then all the work with the database will be as follows:

1. Get a session of working with the base:
session: = FLProgRuDescriptorSystem sessionForLogin: FLProgRuDescriptorSystem login.

2.Save or update an object in the database
session save: object.

2. Subtract all objects from the base of a certain class
collection: = session readManyOff: Foo.

3. Subtract the condition:
all where the value of the variable is id = 100
collection: = session readManyOff: Foo where: [: each | each id = 100].

the first is where the variable value is id = 100 and the value isCorrect = true
object: = session readOneOff: foo where: [: each | (each id = 100) & (each isCorrect = true)].
4. Deleting an object from the database
session delete: object

I have not yet touched upon the issues of creating a GUI for an application, testing issues (the SUnit package is built in, probably the most powerful testing tool of the languages ​​I know), the application deployment and the WEB capabilities. But the post and so it turned out great, and if we consider them more, then to the end, no one will finish. If you like the post, I will try to choose the time and tell about the rest in the sequel.

If you are interested in this language, you can read more about it here:
Russian wikipedia dedicated to the language of which I used resources

Group of Russian-speaking users of Smalltalk

I will try to answer all your questions to the comments.

Source: https://habr.com/ru/post/257611/


All Articles