Bystroushaak's blog / English section / Programming / Series about Self / Environment and the programming language Self (part one; environment)

Environment and the programming language Self (part one; environment)

Note:

There is also Czech version of this article: Prostředí a programovací jazyk Selfu (díl první; prostředí)


I bring you a message about a language that has been at the birth of many others, but almost no one knows it. A rumor of a graphical environment offering options like no other, but almost no one using it. I also bring information about a virtual machine supporting reflection almost to infinity, reaching almost half of the operating power of C in numerical calculations in its time, yet today forgotten.

Today, I'll tell you about the Self. Different people said different things about Self:

Self is (like) Smalltalk, just more.
Self is the sea of objects through which flow flashes of messages.
The self is so advanced idea of the future that despite being twenty-five-year-old, it is still more than just inspirational. Visionary is the right word for it.
I liked Self. “Good OOP” is still waiting for a much better notion to replace the idea of a “Class”

– Alan Kay, https://news.ycombinator.com/item?id=11941330

The only other language of promise is Self, and that is unfunded and locked in non-development though so incredibly influential.

— Interview with Alan Kay

Software archeology in practice. A rich treasure nobody knows about and nobody uses. Hundreds of thousands of lines of forgotten code, ideas, concepts.

Self is many things, so we will look at it from many different points of views.

From a technical point of view

Self is a programming language, bytecode interpreter and system of memory "images", which are executed by an interpreter.

From practical point of view, it is a binary with a virtual machine and separate a memory image file in which objects forming the environment are stored. The situation is somewhat similar to common scripting languages, but instead of the script, you run the memory image in the state that the script last ended.

The memory image contains the entire development environment and its own graphical interface with Xlib bindings.

There are also compilers for the programming language, the entire standard library, and so on.

Programming language

The Self programming language is a prototype-based, object-oriented Smalltalk-like language.

Prototype-based means that it does not use classes to create objects. New objects are created either by copying or by creating a new object from the source code at the syntactic level.

Smalltalk-like means that everything revolves around sending messages to objects. Apart from a few basic syntactic sugars, you will find nothing more than messages sent back and forth.

As a language, Self is very simple to learn. Virtually all of the features of this programming language fit on a single A4 page with a few labels and explanations.

That will be all for a brief overview. Further details will be given in the following chapters.

Interpreter

You can download the Interpreter and the basic image from the official website http://www.selflanguage.org/. There are binary distributions available for GNU / Linux and Mac OS X. There are also source codes released under OpenSource license, that you can theoretically compile on any Unix system.

It will probably not be so easy, because of the bindings to the graphics server and the JIT compilers, that need to be tweaked to a particular processor family.

After downloading and unpacking the archive, waiting for you are the two main files among others. The main ones are:

The first file is the executable binary interpreter, the second file is the memory image in which the preprepared graphical interface environment is stored.

You can start the interpreter with -h parameter to show help:

$ ./Self -h
./Self: usage: ./Self [-f filename] [-h] [-s snapshot] ...
Options:
  -f filenameReads filename (Self source) immediately after startup
  -hPrints this message
  -pDon't do `snapshotAction postRead' after reading snapshot
  -s snapshotReads initial world from snapshot
  -wSuppress warnings about optimized code being discarded
For debugging use only:
  -FDiscards saved code from snapshot
  -l logfilewrite spy log to logfile
  -rDisable real timer
  -tDisable all timers
  -cUse real timer instead of CPU timer (for OS X)
  -oOversample the timers (Run them 10x faster to flush out bugs)
  -aTest the Assembler (added for Intel)
Other command line switches may be interpreted by the Self world

32-bit system

If instead of the help you see something like this

./Self: error while loading shared libraries: libX11.so.6: cannot open shared object file: No such file or directory

then you are using a 64-bit system, that does not have 32-bit support installed. You can install the necessary support on Debian based systems with following command:

sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libx11-6:i386 libxext6:i386 libtinfo5:i386

Back to the Help

Only two switches are in fact interesting; -f, to load a .self file (which you probably will not use) and -s, which loads the stored memory image. The rest are mostly technical details suitable only for very advanced users.

If you run the Self binary alone, REPL (interactive mode) appears in front of you, where you can type commands:

$ ./Self 
Self Virtual Machine Version 2017.1/13, Tue 16 May 17 00:45:42 Linux i386 (4.5.0-205-gd942ba2-dirty)
Copyright 1989-2016 AUTHORS (type _Credits for credits)

for I386:  LogVMMessages = true
for I386:  PrintScriptName  = true
for I386:  Inline = true
for I386:  SICDeferUncommonBranches = false (not implemented)
for I386:  SICReplaceOnStack = false (not implemented)
for I386:  SaveOutgoingArgumentsOfPatchedFrames = true
VM#

Since Self as an interpreter commonly operates at the image level, and I haven't loaded any, I am now in the interpreter where, apart from a few built-in primitives, there is essentially nothing. No standard library, almost no objects to send messages to. Self in this state doesn't even know how to add up two numbers, because it doesn't really know what numbers mean.

Basic help is available by sending a message (details below) help:

VM# help
'
To begin using Self, you must read in the world of Self objects.
To read in the world, type:

'worldBuilder.self' _RunScript

When this process is complete, you will be at the Self prompt.
At the Self prompt, you can start the user interface by typing:

desktop open


' <0>: ( | parent* = <1>. | byte array: {10, 9, 84, 111, 32, 98, 101, 103, 105, 110, 32, 117, 115, 105, 110, 103, 32, 83, 101, 108, ... (258 more elements) } )
VM#

However, the help (in the form of a returned string) is not very useful, the only thing that will show us is how to load the world from .self scripts by sending a message _RunScript to the string with the path to the script.

This is useful when we want to produce a new, "clean" image from serialized source codes. This is achieved by the gradual creation of thousands of objects forming a standard library by using several built-in primitives. It can also be seen as building a system from several axioms.

Image

The morphic.snap file contains already assembled "world" made of linked objects, which together make a standard library and other useful applications. It also includes its own user interface, which is implemented completely in the Self, with several backends per graphics server (Xlib for Unix / Linux, Quartz for OS X).

However, Self does not force you to use this image. You can have an image where there is no graphical interface, where the numbers are not loaded, or where only the webserver is needed. Although it is possible to run a large number of applications in one image, I use several separate images myself for practical reasons.

Overview of the basics of the environment

Before going into the description of the language, I would like to first explain the basics of the user interface and the Self development environment.

When you start Self for the first time, you'll see a white screen, some sort of desktop. I can imagine that for many it may be a shock. When I first turned it on, I closed it again after about thirty seconds of confused looks and mouse clicks.

The terse empty white space just doesn't encourage you to explore what you've come across.

First Shock: Mouse Oriented Environment

The thing that is hard to accept from today's point of view is that, just as the graphical interface of the Plan9 operating system, the Self arose at a time of great enthusiasm for the new periphery: the mouse. The creators promised great intuitive controls, so they decided to make the whole environment manageable primarily by the mouse.

Believe me, if you think you know what to expect from classic graphical applications, you have no idea. In Self, the mouse is not only the primary control element, you literally don't ever have to touch the keyboard, except to write the code. And even programming can to a certain extent be done by the mouse.

If you click on the desktop, both the left and right buttons do nothing and the middle calls up the menu.

From this menu, you can (of course using the mouse), select the basic tools and you can also save the memory image, or stop the interpreter.

Second Shock: Programming Language

I was wondering how to explain this for a long time. The entire graphical interface IS the programming language. The programming language is controllable from a graphical interface, and things that happen in the programming language are often displayed graphically.

The rectangle at the top right with a sign saying shell is like a terminal to write commands in. At the same time, it is also a graphic representation of the programming language object, the so-called outliner.

The arrow in the left corner allows you to view individual slots - elements in an object.

As you can see, there are db*, shortcuts*, and the help slots in this object. The first two are the so-called parent slots, that is, slots referring to the objects to which the messages not found in current object are delegated.

A message with the name of the slot can be sent to object and it returns its content. The message can also be sent graphically, and it returns the content graphically (as shown below).

The three dots next to the object name allow you to view the object's documentation comment.

This is the docstring assigned upon the object's creation.

Furthermore, we see a series of buttons in the right corner that appear a little strange since I don't have the expected fonts installed. The button labeled /\ displays parent slots. When I click on it, parent slot is put "in hand" at the cursor position and I can put it on the desktop with the next click.

That it is actually a parent slot of this object can be shown by clicking on the boxes on the right of the parent slots:

The important button is E, which is displayed for all outliners. This will display the input field, which you can use to send messages to the object.

Here you can see the help message sent by clicking below on Get it, or by pressing CTRL+Enter. This tells the Shell to give me an outliner for the string object. I could also press Do it, which would cause the message to be executed and the return value thrown away.

Te returned outliner can, of course, be further explored:

You can send messages to the returned object, reference it from other objects, and so on.

It is worth noting that the whole environment behaves like a gigantic 2D surface, where it is possible to scroll and jump using WIN+arrow.

Third Shock: User Interface Paradigm

The user interface may seem ugly and strange from today's perspective. It is, however, necessary to add in that it was created in the last century and that virtually no one has ever touched it since.

However, this does not mean, that there is nothing to offer. On the contrary, it is a consistent system based on well-thought-out principles, which include (among others):

Concreteness

If an outliner is displayed on the screen for a particular object, other objects also use it.

A nice example is if you view an outliner for nil:

In the example, you can nicely see how two slots point to one particular object. The outliner for a particular object should not be on the screen more than once.

Uniformity

Once you understand the basics of Morphic (the framework in which the interface is made), everything else can be intuitively derived.

For example, a letter is an object. A line of letters is composed of a string of objects in a layout. The line itself is in the layout that is in the window layout. Everything can be dynamically changed and modified.

Directness

Objects behave as if they were real physical objects existing in reality. For example, it is possible to remove a title from the window and place the copy in an empty space. It is not a nonsensical tweak - like the physical objects, the graphical interface in the Self is explorable and disassemblable. And, like physical objects, it can be used to construct new interfaces.

Because the language is based around the concept of prototypes and memory image, it is possible to continue using composited graphical interfaces and perhaps use it to build an application.

Liveness

Liveness is given by the fact that all objects are redrawn when modified, but also by using all sorts of animations across the entire user interface.

Animations are usually hidden in the background, for example, where the windows are moving, a animation is distorted, and gray blobs are rendered in the path, giving the motion a sense of speed and direction. These techniques were directly inspired by cartoons.

Another example of animation is when you get an error message, such as Syntax error, and just place it on the desktop. After some time, it goes off the screen by itself to avoid getting in the way.

Philosophy

Personally, I find interesting the emphasis on the ability of the user to completely explore and modify the graphical environment. The authors have been relatively successful in offering users the ability to create their own graphical interfaces in a relatively simple way, which is otherwise a thing that is virtually impossible for ordinary people with non-existent knowledge beyond Powerpoint.

If you are interested in the principles, I recommend for further reading:

Tools

Another noteworthy thing are the commonly used tools available in the Self Image and in the project repository.

Outliner

Outliner is that thing which let edit objects. It is basically a table view of individual methods and properties of the object, which, however, allows a few extra things:

Sample of context menu of outliner's slot:

Shell

The shell is just an outliner with pre-set parent slots. If you open a shell using E in a standard object, all messages are executed in the context of the object that the outliner represents. If it is an object without any parent slots, you do not have even the common messages, such as true and false. Shell offers you much more convenience in the form of an extended namespace.

You can call it up it by clicking the mouse wheel anywhere on the desktop and selecting New shell.

Core sampler

The Core sampler is a weirdly looking thing, which can be called up from the context menu (right-click) of almost any morph.

This at first glance a strange gun sight with a gray box allows you to use reflection on the entire morphic interface by displaying layers that make it. Simply move it over the specific element you wish to explore:

From this menu, it is possible to immediately change the properties of the individual layers of morphs, modify their layout, make copies, and so on.

Factory window

You can select the factory window tool from the menu by clicking the mouse wheel on a blank area.

It displays a list of keyboard shortcuts, but also various types of morphs ready for use. Just click and drag them to a blank area to start creating your user interface by folding them on top and into each other.

Radar

It is worth mentioning a screen around the middle left of the factory window. This is a radarView prototype, that you can simply take and drag to the desktop.

After you turn it on, it gives you a radar view of the full screen.

Morph can also be opened from shell:

desktop w addMorph: radarView
desktop w hands first addMorph: radarView

The first command displays the morph at the edge of the screen, the second command puts it at the cursor position into your "hand", so you can put it where you want.

You can also paste the command directly into the terminal from which you run Self:

Transporter

A transporter is a Self's way of recovering source code from objects in memory, that can then be versioned in standard VCS, for example with Git.

It works by annotating specific objects as part of a module that can then be extracted and filled out.

A practical example goes beyond the scope of this episode, but can be seen here: Exporting Self objects to source files using the Transporte

The exported code is somewhat illegible as it is stored as a sequence of transporter directives. Sample: http_client.self.

However, it is necessary to add, that it is serialization format, where editing by a programmer is not intended, the purpose is primarily distribution and versioning. Editing should always take place inside the Self itself by direct manipulation of objects.

Other tools

In addition to these tools, you can also find other tools in the objects/applications directory inside Self repository, including:

and so on. The projects are usually dead and at different stages of work in progress. Some work, others look like they have been dead for a long time.

From the documentation point of view

On one hand, there is a Wikipedia, English one contains a relatively comprehensive introduction including a mini-tutorial of the language:

One of the few coherent sources of documentation is Self papers, an archive of scientific papers that can be found directly in the GitHub repository:

or in a more presentable form on the web:

For newbies, the best source is a Self Handbook:

As an introduction to the graphical interface, this old tutorial I've put online on my site, is one of the few usable documents:

If someone has a desire to read the entire maillist, I have the archive here:

there is quite a lot of information on there, but I would like to warn you that reading can take weeks at least. If you are interested in highlights, you can find them at the Self blog:

along with other articles:

And that's mostly all. Everything else you can find is mostly outdated, not updated and irrelevant in this day and age.

Interesting papers

Among the more interesting papers, you can find:

I can suggest papers not included in the repository:

And this was literally eye-opening:

Next episodes

This will be all for part one. In the next three episodes, we will look at the programming language itself, a standard library, philosophical and metaphysical overlaps and much more.

Part two; Environment and the programming language Self (part two; language).

Become a Patron