A declarative model of Smalltalk (was Re: [DOCS] SUnit tests)
nevin at smalltalkpro.com
Sat Feb 22 20:21:51 UTC 2003
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.
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
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.
Given the above definitions, then, one of the first things we discover
is that the act of programming is the same thing as the act of "language
designing". You are extending an existing language in a domain-specific
direction (i.e., introducing new words to the vocabulary, whether they
are functions, prodedures, methods, or whatever), and in so doing, you
are creating a new language as a side-effect, for the simple reason that
your "new" language has a greater (and sometimes lessor) set of words
than what you started with, and you may have even altered the "meanings"
of some of the existing words in the process. Either of these acts
result in a new "language" (using the definition of "language" from
above), even though you may be starting from a given base language when
you do it. Your existing "base" language might be the native
instruction set understood by the CPU you are programming on, or on some
Virtual Machine, or any other form of a "language", but you will always
be building on a base language of some sort.
Now, as we know, many languages differentiate intrinsic words within the
vocabulary of the language from the programmer-defined words. But many
languages (such as Smalltalk) do not differentiate them.
Given the above definitions, a Smalltalk "program" (or any other program
in any language) consists of *every* word of the vocabulary of the
"program", coupled with the meaning of every word. And because
Smalltalk does not differentiate *who* introduced the word into the
vocabulary (intrinisic or programmer defined), it is irrelevent whether
"Programmer A" introduced the word to the vocabulary, or "Programmer B".
Likewise, it is irrelevent whether "Company A" introduced it, or
"Company B". Thus, a complete "program" necessarily has to either (1)
include *every* word of the vocabulary of the program, and the
definitions of those words, or (2) assume that such a program is merely
an extension of an existing language (or program). Actually, two
paragraphs above I argued that you will always be building on a base
language, which would mean that #1 isn't even possible, and that your
only option is to assume that such a program is merely an extension of
an existing language (or program). But I won't actually make that
Now, if such a "program" includes every word of the vocabulary of the
program (assuming that it is even possible to do this, and I suggested
above that this option isn't even possible), together with the
definitions of those words, I personally don't see any advantages (or
disadvantages) of comparing this with an image-based approach, since
everything has to be included anyway.
And, if it is just an extension of an existing language, then it
necessarily has the same "initial state sensitivity" that the imperative
approach has, because it is expecting to extend a known, existing (i.e.,
"static" and unchanging) base language. If the base language that it is
extending is different from that which it was designed to extend, you
have exactly the same state-related problems that you see with the
imperative approach. And, in the imperative approach, if you start from
a known base "language", then a known sequence of expressions applied to
that base *will* reliably reproduce the "program", just as the
declarative approach will.
When merely "extending" an existing base language, both approaches
require that you know where you are starting from, consequently neither
approach results in any theoretical advantage towards program
reproducability. That's my opinion.
I could say more, but suffice it to say that I remain unconvinced that
any declarative approach has any theoretically advantage (or
disadvantage) over the classic Smalltalk imperitave approach.
Allen Wirfs-Brock wrote:
> At 04:00 AM 2/22/2003 -0500, Jeff Read wrote:
>> When the compiler and parser are tightly integrated with the runtime
>> of the language, instructing the language to add program parts to its
>> currently running program often becomes the norm, rather than
>> crafting everything declaratively in an editor and then running it
>> through a compiler.
> I think you half get and half miss the point. Using a declarative
> approach to Smalltalk in no way implies using an editor to create
> source files. As I previously mentioned, Smalltalk browsers generally
> present a declarative model of Smalltalk programs to the programmer
> who creates and views class and method definitions/declarations (a
> class definition is (partially) presented as a message expression but
> to most users that's just syntax which is treated as a
> declaration). The issue is more related to what happens when the user
> clicks "accept". In a classic Smalltalk-80 system the browser uses
> the declaration to imperatively side-effect the running system and
> then essentially forgets the declaration. In a declarative Smalltalk
> environment the browser records the declaration as a primary
> archival artifact and then (perhaps optionally) side-effects the
> running system.
> The two most widely used "team" Smalltalk development environments
> during the "golden age" of commercial Smalltalk were Digitalk's
> VSE(Team/V) and OTI's Envy. While OTI was less overt about it, both
> systems were essentially declarative in nature. Yet both presented
> a complete, browser-based, interactive, incremental, reflective,
> "Smalltalk-style" development experience.
> The issue is really all about reproducibility of programs. If I create
> a program I need to be able to hand it to you with the expectation
> that you will receive the exact same program. I need to be able to
> take that program and run it with a future version of the runtime
> system and know that it will still get the exact same results. I need
> to combine independently development "modules" into a common program
> and know that each module remains as originally defined. I need to
> retrieve an old, archived version of a program and reconstruct it in
> its exact original form. To reliably do these things you need a
> declarative definition of the program or a module rather than a
> sequence of state sensitive imperative operations. BTW, it is the
> initial state sensitivity that is the real killer. That's why
> "file-outs" often don't work when they are "filed-in" and that's why
> you have to worry about the load order of change sets.
> (I also take issue with the implied assertion that the
> Smalltalk/Squeak compiler is tightly integrated with the runtime
> system. Removing the compiler is quite simple. Most commercial
> Smalltalk products have included the capability (or even the
> requirement) to deploy applications without including the compiler.
> Similarly, it is quite possible to build a runtime compiler for Java
> that is capable of taking a source code class declaration and
> dynamically loading it into a running application.)
>> Smalltalk appears to borrow a lot from LISP in this regard, at least
>> in terms of philosophy if not implementation. In Scheme, for
>> instance, the keyword define means "Add this symbol to your currently
>> running global environment, and bind it to the following value..."
>> LISPers tend to see this as an advantage.
> Not when they want to create a maintainable, reproducible, deployable
> application. In that situation they create archival source code
> definitions that can reproducibly create the runable application.
>> The difference, if I surmise correctly, is that every Scheme knows
>> what define means; the base semantics for the keyword are
>> standardized -- whereas each Smalltalk has a different protocol for
>> creation of classes and adding methods to the
>> The Smalltalk situation is rather unfortunate, but I see not what
>> having a separate declarative syntax for Smalltalk affords us; with a
>> standardized imperative protocol for creation of classes, methods,
>> and variables, the declarative syntax comes for free.
> It's not just an issue of protocol standardization. It's more an
> issue of initial state dependencies and polymorphism. Syntactically
> you can use Smalltalk message syntax if you want. However, if you
> want reproducibility, their semantic interpretation can't be dependent
> upon the happenstance state of the running system. As you say, it
> isn't the syntax that is important. However, a standard semantics is
> essential. ANSI Smalltalk doesn't even bother to define a concrete
> syntax for class declarations. It just says that no matter what you
> use for a concrete syntax, here is what it means.
> Allen Wirfs-Brock
>> Jeffrey T. Read
>> "I fight not for me but the blind babe Justice!" --Galford
More information about the Squeak-dev