A declarative model of Smalltalk (was Re: [DOCS] SUnit tests)

Colin Putney cputney at whistler.com
Sat Feb 22 23:38:00 UTC 2003


On Saturday, February 22, 2003, at 12:21  PM, Nevin Pratt wrote:

> Over the years I have read Allen's papers (and read his posts) 
> concerning a declarative Smalltalk, and I've tried to weigh in and 
> form my own opinion.  Over all of those years, Allen has not convinced 
> me of the value of the declarative approach, but then again, I have 
> not been convinced he is wrong either.  I am simply undecided.

Oddly enough, I have only just recently been introduced to Allen's 
work, but I'm quite excited about the possibilities it presents. The 
work Avi and I did on Monticello convinced me that a declarative 
representation of Smalltalk programs is essential if we are to reliably 
and automatically construct images with known properties in a modular 
fashion.

> However, I *do* take issue to the implied assertion that the current 
> imperative approach used by the major Smalltalk's  necessitates any 
> less (or even any more) reproducable "programs" than the declarative 
> approach.  But let me briefly introduce some definitions of the 
> components of a declarative "program" before I attempt to defend the 
> belief:
>
> 1. A "word" is a sequence of non-white space tokens within the 
> declaration of the "program" (and "white space" has the classic 
> definition we are all used to).
>
> 2. A "vocabulary" is a unique set of words.
>
> 3. A "language" is a vocabulary coupled with a unique meaning of each 
> word of that vocabulary.
>
> 4. Any program declaration is necessarily written in a "language", as 
> defined above.
>
> Since above I said a vocabulary is a *unique* set of words, this means 
> that adding or removing a word to or from the vocabulary creates a new 
> language, per the above definitions.
>
> Since above I said a language is a vocabulary coupled with a *unique* 
> meaning of each word, this means that changing the meaning of a given 
> word creates a new language, per the above definitions.

I find this definition of language unsatisfactory, for two reasons. For 
one, it ignores the notion of grammar, which is a key part of language. 
Also, the requirement for a unique meaning for each word directly one 
of the central notions of Smalltalk, which is that different objects 
respond to different messages differently.

The point (snipped for brevity) that any program necessarily extends 
the capabilities of the base system is well taken, however. In fact, 
it's the main reason that a declarative model for Smalltalk programs is 
so useful.

The difference between declarative and imperative representations of 
Smalltalk boils down to one of meaning. An imperatively defined program 
consists of a series of messages sent to named objects. It is 
understood that if those messages are sent in an appropriate context, 
they will have the side effect of adding the functionality provided by 
the program to the system.

The advantage of the imperative representation is that it provides a 
level of abstraction that can be useful. Since there are only message 
sends, you can take advantage of polymorphism in the environment where 
the program is constructed. A radically different language 
implementation, say one that did not use classes to create objects, 
could provide an environment where that sequence of message sends would 
still have appropriate side effects.

The problem is the imperative approach is that it's so abstract. 
There's no *meaning* attached to the message sends in a fileOut. 
Because of that, it's impossible to reason meaningfully about the 
program. An imperative representation is essentially a program that 
constructs a program. The only way to find out what it does is to run 
it and look for changes in the state of the system.

A declarative representation, OTOH, does have a meaning. As Allen 
mentioned, it's the meaning that's important, not the actual syntax of 
the representation. This means you can reason about the program without 
loading it into the system. This is important precisely because the 
program is an extension of the base system.

As an example consider a program that adds a class to the system. This 
class is a subclass of Object, a class that's already part of the 
system. The imperative model represents this by sending  #subclass: to 
the object named 'Object'. If Object doesn't exist, you get a MNU 
error. An well-designed system will have facilities to catch these 
errors and react appropriately. Nevertheless, if the error occurs in 
the middle of the execution, the side effects of the execution up to 
that point will persist. This leads to an inconsistent system.

The declarative model will assert the existence of a class which 
extends Object. It's up to the system to create whatever structures are 
necessary to bring that about. If Object doesn't exist, the system does 
not provide the functionality the program depends on, and so it can't 
be loaded. It's possible to detect this *before* attempting to load the 
program, handle the error appropriately, and leave the system unchanged.

This case of defining a subclass of a non-existent class is just one 
example of the larger problem of the program dependencies. Because each 
program extends the system, it must rely on certain functionality and 
semantics being present in the base system. A declarative 
representation of the program makes the those dependencies explicit, 
while an imperative makes them implicit.

Cheers,

Colin



Colin Putney
Whistler.com



More information about the Squeak-dev mailing list