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
|