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.
Post by Allen Wirfs-Brock
Post by Jeff Read
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
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.)
Post by Jeff Read
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.
Post by Jeff Read
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.
Post by Jeff Read
Jeffrey T. Read
"I fight not for me but the blind babe Justice!" --Galford