Checking for Errors Before Run Time

330 views
Skip to first unread message

Chris Perkins

unread,
Nov 20, 2001, 3:12:28 PM11/20/01
to
As I've been learning LISP over the last 6 months or so, I've been
blown away by its power and grace. But there is one thing that has
been bothering me, but it may just be my C++/Java approach.

Programmers wanting to make their code solid often use Design By
Contract to assert input and output contracts on functions. I see
LISP has this, and that's great.

But, Java and C++, by their nature, can perform some basic contract
enforcement at compile time, rather than waiting for runtime.
Specifically, the compiler will bleat for violations of access
(public/private), argument count, and argument type.

LISP compilers seem to throw warnings for argument count, but that's
it.

I would venture that most C++/Java programmers *like* type safety and
see it as a real advantage - they are warned of stupid mistakes at
compile time, rather than having to vette them out at runtime. To my
mind, C++/Java programmers gain the side effect of a simple
preconditional contract on their arguments by using types. And, bonus
for them, that contract is verified at compile time, rather than at
runtime.

Does LISP have any way of doing this? I'm not proposing abusing type
specifications to achieve this, but is there anyway to have simple pre
and post conditional contracts verified outside of runtime?

I would love a system to be able to specify pre & post conditional
contracts, class invariants, etc. and have them all checked by simply
issuing a command at the prompt. While I'm fantasizing, in an ideal
system, contracts that are 100% verifiable would be taken out of the
code (why slow it down?), and the rest would be converted to assert
clauses to continue runtime monitoring.

Chris
Media Lab, Inc. / As Is Software, Inc.

Thom Goodsell

unread,
Nov 20, 2001, 3:53:47 PM11/20/01
to
The current thread with the subject "Using type declarations in safety
checks" is discussing exactly this topic. I'd post a reference, but I
can't figure out how to get message IDs out of Google Groups.

Thom

--
Thom Goodsell tgoo...@cra.com
Scientist (617) 491-3474 x574
Charles River Analytics http://www.cra.com/

cbbr...@acm.org

unread,
Nov 20, 2001, 3:57:05 PM11/20/01
to

Most implementations seem not to do _vast_ amounts of "contract
verification," with CMUCL being the notable exception.

Supposing you write a function that begins:

(defun db-put (db key datum
&key (start 0) end db-start db-end
(transaction *transaction*) (flags 0))
(declare (type db db) (string key datum)
(type (or transaction null) *transaction*))

CMUCL does some validation, when you run COMPILE-FILE, to see if
arguments db, key, datum, and *transaction* are used, internally, in a
manner conforming with those declarations.

Supposing I set up a _call_ that doesn't conform, as with:

(db-put "db" "key" "datum")

The compiler gripes back at me thusly:

In: DB-PUT "db"
(DB-PUT "db" "key" "datum")
Warning: This is not a (VALUES &OPTIONAL DB &REST T):
"db"

In many cases, further type inference is done by CMUCL. For instance,
it is very likely going to infer that the FLAGS parameter is a NUMBER,
based both on the default, and on the sorts of functions that get
applied to FLAGS within the function.

That's one direction whereby some validation takes place.

Another would be via CLOS. If you use DEFCLASS to define types, and
DEFMETHOD to declare methods to apply to those types, then type
checking gets done quite automatically any time code is written and
compiled. Invalid applications of methods often can be detected at
compile time, which should provide a fair bit of what you're after.

All that being said, it's often more useful to write code in a really
generic manner, not caring about types, and then tighten things down
later _if it proves necessary_.

That's probably as much as you're going to get. If you want
Eiffel-style DBC, then perhaps what you want to use is in fact Eiffel.
If you want ML-style static type checking, then you may want to use
ML. Expecting Lisp to conform to identical design criteria can't be
expected to be reasonable.
--
(reverse (concatenate 'string "moc.enworbbc@" "enworbbc"))
http://www.cbbrowne.com/info/linux.html
Rules of the Evil Overlord #231. "Mythical guardians will be
instructed to ask visitors name, purpose of visit, and whether they
have an appointment instead of ancient riddles.
<http://www.eviloverlord.com/>

Bradford W. Miller

unread,
Nov 20, 2001, 4:42:48 PM11/20/01
to
Not exactly on point, but see Mitsubishi Electric Research Labs TR 91-04
"Some Useful Lisp Algorithms: Part 1" by Richard C. Waters, where he gives
an implementation for automatic regression testing of programs (post
compile), and a way to determine how good your test coverage is by analyzing
your program source.

The most immediate problem with doing things exactly as you suggest is just
that other than CMU Common Lisp, nobody I'm aware of has implemented good
type checking for lisp programs. I think CMU's dates back to spice lisp, so
presumably you can get the code, and nothing prevents you from writing your
own version of defun to wire it in. (There are one or more PD code walkers).

An alternative is just to write your lisp functions to correctly handle
types that don't match their expected arguments. Robust code is better than
contracted code, for most purposes. Ah, the metaphor!


On 11/20/01 2:12 PM, in article ¿y´RTICLE], "Chris Perkins"

Erik Naggum

unread,
Nov 20, 2001, 5:49:59 PM11/20/01
to
* Chris Perkins

| But, Java and C++, by their nature, can perform some basic contract
| enforcement at compile time, rather than waiting for runtime.
| Specifically, the compiler will bleat for violations of access
| (public/private), argument count, and argument type.

They also have a prohibitively expensive compilation process compared to
Common Lisp. This is _why_ it is important in those languages to make
sure that runtime is a less expensive debugging environment. Comparisons
of language tend to forget their contexts and evolution completely, and
take one of these for granted while the other is treated like a stranger
in a strange land. This is why you should strive to forget where you
came from and try to figure out how your new language came to be and why
what it does is natural in its environment.

| I would venture that most C++/Java programmers *like* type safety and see
| it as a real advantage - they are warned of stupid mistakes at compile
| time, rather than having to vette them out at runtime.

That is because so many things are mistakes that no human being in his
right mind can be expected to figure out are mistakes. Languages that
are so hard only compilers (that are so hard to write that no human being
in his right mind can do it) can figure out whether a program is correct,
should simply not be used by human beings. I happen to think Java is
pretty good this way while C++ is absolutely insane.

| To my mind, C++/Java programmers gain the side effect of a simple
| preconditional contract on their arguments by using types. And, bonus
| for them, that contract is verified at compile time, rather than at
| runtime.

A less elaborate contract can actually be remembered and understood.

| Does LISP have any way of doing this? I'm not proposing abusing type
| specifications to achieve this, but is there anyway to have simple pre
| and post conditional contracts verified outside of runtime?

I think you should re-examine the reasons you are obsessing against
run-time. Run-time may hurt in C++ because debugging is so hard, but
learning from pain is not a very good way to learn the right thing.
(The only thing that appears to work is to make it painful _not_ to
think, because it is appears to be painful to many people to think.)
Because you break to the debugger in Common Lisp and you can debug much
more accurately when you do not compile your Common Lisp code, so the
compiler is actually even less important than it might appear to be.

| I would love a system to be able to specify pre & post conditional
| contracts, class invariants, etc. and have them all checked by simply
| issuing a command at the prompt. While I'm fantasizing, in an ideal
| system, contracts that are 100% verifiable would be taken out of the code
| (why slow it down?), and the rest would be converted to assert clauses to
| continue runtime monitoring.

One of the things you learn from writing serious Common Lisp programs is
that you never take out the "checks and balances" part, because it does
not slow the program down appreciably (use a profiler to find out where
your performance is less than optimal -- it is not where you think it is,
and certainly not in execution safety, which turns into crashes and long
debug cycles when you remove them, reduce the safety setting, and ask for
higher speed optimization, and all errors were not taken out of the code)
and because even if you test your own code, you make it harder for others
(including yourself) to use it, whether in that "reuse" fashion, or when
modifying the program sometime later on.

Coming from the C++ world, it can take a while to get used to programs
that do not crash and burn. Likewise, returning from Common Lisp to C++
is _amazingly_ painful.

///
--
Norway is now run by a priest from the fundamentalist Christian People's
Party, the fifth largest party representing one eighth of the electorate.
--
Carrying a Swiss Army pocket knife in Oslo, Norway, is a criminal offense.

Thomas F. Burdick

unread,
Nov 20, 2001, 8:29:31 PM11/20/01
to
Erik Naggum <er...@naggum.net> writes:

> One of the things you learn from writing serious Common Lisp programs is
> that you never take out the "checks and balances" part, because it does
> not slow the program down appreciably (use a profiler to find out where
> your performance is less than optimal -- it is not where you think it is,

This is a lesson that dates from the early 1970's, AFAICT. I'm
completely amazed at how many programmers need to be constantly
reminded of this.

> and certainly not in execution safety, which turns into crashes and long
> debug cycles when you remove them, reduce the safety setting, and ask for
> higher speed optimization, and all errors were not taken out of the code)

Well, unless it is in the execution safety. But then it would only be
in the inner loops. Which, if you find your code doing something
stupid, you carefully arrange for the code around the loop to ensure
the safety of the inner loop, comment this prominently, and locally
turn speed all the way up and safety all the way down. There's really
no need to do this anywhere else, though.

--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

cp

unread,
Nov 20, 2001, 9:12:32 PM11/20/01
to
> They also have a prohibitively expensive compilation process compared to
> Common Lisp. This is _why_ it is important in those languages to make
> sure that runtime is a less expensive debugging environment.
Comparisons
> of language tend to forget their contexts and evolution completely, and
> take one of these for granted while the other is treated like a stranger
> in a strange land. This is why you should strive to forget where you
> came from and try to figure out how your new language came to be and why
> what it does is natural in its environment.

I'm not necessarily advocating type specifications in Lisp. I'm simply
trying to write better and more solid code, which is why I have come to Lisp
in the first place. I don't necessarily care to introduce type
specifications to Lisp, but I would be interested in upstream (not runtime)
verification of simple and complex contracts.

The sooner I can discover a typo or an error, the better. I believe this is
true for any language.

> Coming from the C++ world, it can take a while to get used to programs
> that do not crash and burn.

While it is true that I don't have to restart my machine when I miscode in
Lisp, I still "crash and burn" - I incorrectly use a form - I pass arguments
in the wrong order, etc. Little things that haunt every programmer - even
Lispers. And, I assert, little things that *could* be detected by my
language or tool, instead of me, my debugger, or my users.


But, as has been suggested to me, I will read up on CLOS, I will check
Richard Waters' article on regression testing, and I'll muck about a bit.


On an aside, I've always felt that Design Patterns, DBC, and UML are, at an
idealogical level, fundamentally tied together. They are, in a sense,
programmers struggling to find a "form" or "description" of both the shape
of their code and the code itself. Nowadays, when I think about that
struggle I think to myself "Hmmmmm...that sounds like the type of problem
Lisp would be well suited to solve"


Chris Perkins

unread,
Nov 20, 2001, 9:34:00 PM11/20/01
to
I sent that last message before I was done when I was trying to fix my ID.
cp is me, Chris Perkins.


> Nowadays, when I think about that
> struggle I think to myself "Hmmmmm...that sounds like the type of problem
> Lisp would be well suited to solve"

Let me clarify: Lisp seems like it could solve that problem by someone
actively pursuing it and writing a solution. Merely using Lisp does not
solve the problem (though it is a step in the right direction).

Chris Perkins

Kenny Tilton

unread,
Nov 20, 2001, 9:54:06 PM11/20/01
to

cp wrote:
> While it is true that I don't have to restart my machine when I miscode in
> Lisp, I still "crash and burn" -

No, you just crash, not necessarily burn. It's more like that simulator
in the TV ad where the guy driving the beer truck goes off a cliff
because he is eyeballing a simulated blonde bombshell. The instructor
gives you hell, rewinds the sim to before the babe comes into view, you
keep yer eyes on the road for the most part.

I have spent hours working on a new grid widget without ever closing the
main app window. I just hit the button that leads to the widgets
creation, back out and start again to see the effect of any changes. If
in a rare case I am just changing the paint function, all I need do is
cover uncover the widget.

Even if I crash (the subject at hand), I do not burn. I poke around
sometimes for a few minutes or even an hour, make all the changes I
want, recompile--then look back at the backtrace to see how far back to
restart to pick up the change.

Sometimes I cannot because I use Semaphors a lot and these are
structures that arrange for a slot to be efficiently envalued by a
formula--if I die in a formula, fixing the formula in the source does
not change the lambda function that died, so I just "burn" the window
and re-run. without linking.

I once ported Semaphors to C++ (and Java) and I indeed experienced the
advantages of having the compiler dopeslap me around, but smarter folks
than me say I cannot have it both ways--well, Dylan is a stab at that, I
guess. And if I have to choose, well...

as you say, we are all trying to figure out the best way to program
these things. i see a parallel between Lisp and the mountaineering
technique of Reinhold Messner, who subsituted speed for stuff (gear,
food, oxygen) to conquer big peaks. Instead of seige tactics in which
teams of climbers went up and down ferrying supplies between higher and
higher camps, and he is partner just went for it. This meant climbing
unroped on stuff that would have me pissing in my pants. Messner's
thinking was that usually it's the weather that kills climbers, and
seige tactics ineluctably put one on the mountain longer.

So basically Messner used skill and an insane degree of conditioning to
maximize speed and minimize exposure to the crucial hazard, weather. And
that approach is incompatible with seige climbing.

kenny
clinisys

Erik Naggum

unread,
Nov 20, 2001, 10:49:04 PM11/20/01
to
* Chris Perkins

| I'm not necessarily advocating type specifications in Lisp.

I do not follow you. Type specifications are already available to you in
Common Lisp. Why use an inferior Lisp without them?

Or do you mean that you want static type checking? That you cannot get
very easily.

Or do you mean that you do not want to add type declarations in the true
sense of a declaration -- you _declare_ its type? Why not? If you have
knowledge you withhold from the compiler, that can only be your loss.

| The sooner I can discover a typo or an error, the better. I believe this
| is true for any language.

I disagree, probably to your surprise. The earlier an error is detected,
the _firmer_ the determination that it is an error is, and the simpler
the world must be in which statements are made. For instance, we have
the option in Common Lisp of redefining a function between the definition
the compiler knew about at compile-time of a caller and the actual time
it was called. This would require a total re-compile in languages that
consider such things an error with no option to negotiate. In the long
history of programming languages, indeed human history, there are people
who insist that they know what is true and good, and who seek to limit
other people's opportunity to find out what other things are true and
good. These generally call anything they disagree with "errors" and make
people angry at their compilers or computers. Then there are people who
only think they know what is wrong, and while they have their own ideas
about what is true and good, they only seek to limit other people's
opportunity to do wrong and harmful things. These generally do not think
things are errors unless they are _clearly_ wrong and harmful. If not
clearly, they may issue a warning or a style-warning. (E.g., omitting
the value of the final branch of a cond or case expression when the value
returned is stored in a place that is declared not to accept nil as a
possible value, might be a style warning because the compiler cannot know
that you do not know better.)

| While it is true that I don't have to restart my machine when I miscode in
| Lisp, I still "crash and burn" - I incorrectly use a form - I pass arguments
| in the wrong order, etc.

Then you have a _really_ bad Common Lisp environment.

| Little things that haunt every programmer - even Lispers.

No, not really. You see, a Common Lisp programmer who is uncertain about
the arguments to a function he is about to call, asks the system for the
lambda list. If he changes the lambda list in any way, he calls upon the
system to let him edit all the calling points of that function. If he
uses a smart editor, like Emacs, many of these operations can be fully
automated, and this is again possible because (almost) all Common Lisp
expressions are easy to scan both forwards and backwards in the editor,
so you can move them around with simple editor commands.

| And, I assert, little things that *could* be detected by my language or
| tool, instead of me, my debugger, or my users.

I assert that writing better code to begin with, working with a language
that is actually small enough that it does not impose a cognitive load on
its users. Common Lisp programmers make fewer syntactic bloopers because
there is much less syntax, much better support for what syntax there is
in their editors (although the other languages are getting some of the
benefits of Lisp's superior syntax in Emacs). The tradeoff between how
much the programmer, the editor, and the compiler does is very different
between Java and Common Lisp.

If you think that whichever language you learned first has every implicit
or tacit assumption right, you are wrong. The language you learned first
was an accident. Learning a new langauge can be done two ways: Either
drop everything you have gotten used to and open your mind to the new
language, or study carefully how you react to things that differ and make
those assumptions explicit. Anything else will fail. (Mixing works. :)

Coby Beck

unread,
Nov 20, 2001, 11:01:35 PM11/20/01
to

"cp" <cper...@medialab.com> wrote in message
news:k5EK7.902$jt4.2...@news.uswest.net...

> The sooner I can discover a typo or an error, the better. I believe this is
> true for any language.
>

I think the reason this is not as big an issue as you may feel is due to the
interactive and incremental way development is best done in lisp. You do not
need to write 6 screens full of code before it is ready to hand to the compiler
to uncover all of your typos. I always test my functions as I write them and
definately individually test them when they are "finished". The great thing
about lisp development is that ability. You need to write method foo that will
take an object of one of your classes and do something magical, create an
object, bind it to something, even the same variable named in foo's lambda list
and step by step make sure every line does what you expect. By the time that
process is finished, the only errors left are the special cases you forgot and
logical nuances. These are not the kind of things compilers will tell you
about anyway.

In a certain sense this *is* discovering the typo and "d'oh" errors at runtime,
but the (big) difference is that runtime is anytime.

Coby
--
(remove #\space "coby . beck @ opentechgroup . com")


Craig Brozefsky

unread,
Nov 20, 2001, 11:29:46 PM11/20/01
to
"cp" <cper...@medialab.com> writes:

> I'm not necessarily advocating type specifications in Lisp.

They are already there in Common Lisp.

> The sooner I can discover a typo or an error, the better. I believe this is
> true for any language.

Might I suggest the following then:

1. Learn to control the verbosity of your compiler and it's
strictness. The compiler can tell you quite a bit of information
before you hit "runtime." In cmucl, (setf *compile-verbose* t) will
be helpful.

2. Use declaimations and/or declarations to set your compiler policy
appropriatly. This will get quite a few typos. I put:
(declaim (optimization (debug 3) (safety 3)))
in my init file. Under cmucl I also:
(setf *compile-print* nil)
(declaim (optimize (inhibit-warning 3)))
which reduced my console spam while compiling to the important
warnings and notices.

> Lisp, I still "crash and burn" - I incorrectly use a form - I pass
> arguments in the wrong order, etc. Little things that haunt every
> programmer - even Lispers. And, I assert, little things that
> *could* be detected by my language or tool, instead of me, my
> debugger, or my users.

See above. What usually slips thru at this point may have possibly
been caught by static type checking, but static type checking is not
worth the trouble in CL, as Erik explained in another post.

> But, as has been suggested to me, I will read up on CLOS, I will check
> Richard Waters' article on regression testing, and I'll muck about a bit.

CLOS will not help you much here, it's an object system, tho I still
encourage you to learn about it. What will help you here is the
Common Lisp Hyperspec and your CL implementations manual. Check out
the sections on compiler policy and the use of type declarations in
the CLHS, and your manuals section on the compiler and debugger.

> "Hmmmmm...that sounds like the type of problem Lisp would be well
> suited to solve"

Yah, the solution is called macros and readtable 8)


--
Craig Brozefsky <cr...@red-bean.com>
http://www.red-bean.com/~craig
All around the world hearts pound with the rythym. Fear not of
men because men must die. - Mos Def

Kaz Kylheku

unread,
Nov 20, 2001, 11:37:59 PM11/20/01
to
In article <k5EK7.902$jt4.2...@news.uswest.net>, cp wrote:
>> They also have a prohibitively expensive compilation process compared to
>> Common Lisp. This is _why_ it is important in those languages to make
>> sure that runtime is a less expensive debugging environment.
>Comparisons
>> of language tend to forget their contexts and evolution completely, and
>> take one of these for granted while the other is treated like a stranger
>> in a strange land. This is why you should strive to forget where you
>> came from and try to figure out how your new language came to be and why
>> what it does is natural in its environment.
>
>I'm not necessarily advocating type specifications in Lisp. I'm simply
>trying to write better and more solid code, which is why I have come to Lisp
>in the first place. I don't necessarily care to introduce type
>specifications to Lisp, but I would be interested in upstream (not runtime)
>verification of simple and complex contracts.
>
>The sooner I can discover a typo or an error, the better. I believe this is
>true for any language.

I think that any benefits must be weighed against disadvantages. Is it
wortwhile to save time finding a typo, if you have to pay for it in lost
productivity at every turn? Is it wortwhile if it means that there are
some programs you cannot write? Some programming languages force such
a tradeoff on their users by requiring them to make declarations which
allow checks to be easily implemented.

I think that static checking is perhaps a must only in safety critical
software. Such software should be kept small and uncomplicated, because
too much is at stake, so the lost productivity isn't an issue.

>> Coming from the C++ world, it can take a while to get used to programs
>> that do not crash and burn.
>
>While it is true that I don't have to restart my machine when I miscode in
>Lisp, I still "crash and burn" - I incorrectly use a form - I pass arguments
>in the wrong order, etc.

But note that these situations are identified at a high level. Mistakes
in a C++ program require a mapping from some machine language level back
to the source language. Frequently, the mapping is difficult or
impossible. A mistake that occured thousands of cycles earlier in the
execution in an unrelated part of the program manifests itself in a
mysterious failure elsewhere, perhaps in a subprogram that is itself
correct.

You can't compare that to a high level diagnosis which tells you
exactly what the problem is as it happens. (There can still be some
level separation; e.g. a problem occurs deep in some code generated by
a macro, without an easily apparent macro-level mapping back to the user
of the macro).

C++ also doesn't let you programmatically choose the recovery, and
certainly interactive recovery isn't part of a running C++ program;
only when that program is running in a debugger.

Things like division by zero or dereferencing a null pointer are simply
undefined behavior; they don't generate standard exceptions that can be
caught. Programmers rely on platform-specific, nonportable mechanisms,
like POSIX signals, or structured exception language extensions like
those of Win32 or Digital UNIX or what have you.

> Little things that haunt every programmer - even
>Lispers. And, I assert, little things that *could* be detected by my
>language or tool, instead of me, my debugger, or my users.

Software shops waste tens of thousands of dollars on tools like Purify,
yet crank out C++ that leaks and crashes. Money is wasted on the tools,
time and money on their application.

>But, as has been suggested to me, I will read up on CLOS, I will check
>Richard Waters' article on regression testing, and I'll muck about a bit.
>
>
>On an aside, I've always felt that Design Patterns, DBC, and UML are, at an
>idealogical level, fundamentally tied together.

Many of the the design patterns described in the Design Patterns book
are largely just C++ workaround patterns. It's shocking that the authors
don't appear to realize that; if they do, they sure don't acknowledge it;
their introduction claims that these are genuine patterns of object
oriented design.

For example, the Adapter and Visitor patterns are meaningless in the context
of an object system like CLOS, because you can create new generic
functions with methods that specialize to existing classes, and because
you have multiple dispatch. So from the perspetive of the CLOS user, these
are, respectively, a recipe for overcoming the idiosynchrasies of a
type system, and for clumsily simulating double dispatch.

Flyweights are just interning; happens all the time in Lisp when you
use (interned) symbols.

Here is a good one: the State pattern. Basically, you have an empty
object, which holds a pointer to another object. It redirects its calls
to that object. It switches to other objects to represent state changes.

This is nothing more than a simulation of an object's *type* changing at
run time! The ``context'' object appears to change type because its entire
implementation is in the state object which is swapped for another one
which has a different behavior.

In CLOS you can do that by directly by telling an object to change
class. So you don't need a surrogate object to hold a pointer; you just
have the state object and change it. Design Pattern, my ass! Say it
with me: Workaround Recipe!

The State recipe is basically just reimplementing a virtual dispatch
table in software, because the language doesn't give you the access
to the real virtual table that would let you allow you to switch the
virtual functions to make the object appear to change type.

For fun, I wrote a little C library in which a dynamic structure can,
at run time, change its type among AVL, red-black, splay and ordinary
binary trees as well as a sorted linear list. You can build a red-black
tree, and then say ``please become an AVL tree''. Classes would only
have gotten in the way of this, because I needed a way to switch the
virtual table of a live object to a new set of methods.

Lastly, UML is basically a whole lot of graphical crud thrown together to try
to capture every nuance of C++. It favors a narrow view of object
orientation in which methods are properties of classes, exemplified by
descendants of the Simula family. I think that the big names behind
UML have a vested interest in selling you their design process at big
bucks per seat. Just say no!

By the way, I pay my bills by developing in C++. Dirty, multithreaded,
C++ with dynamic real-world inputs: communication protocol middleware.
So I'm not some academic looking down on the trenches from an ivory
tower. I use those workaround recipes, and from time to time I even have
to produce or understand UM-Hell.

Hope you have as much fun reading this little rant as I had writing it. ;)

Kenny Tilton

unread,
Nov 21, 2001, 12:06:13 AM11/21/01
to

cp wrote:
> I would be interested in upstream (not runtime)
> verification of simple and complex contracts.

I just thought of another parallel, one going back twenty years.

It was a long, detailed, very serious argument I read in a tech journal
against writing code which did not compile on the first shot.

I am sure no one understands what I just wrote, because it is so
inconceivable. I repeat. The guy was saying that it was inexcusable to
submit code to the compiler which would not compile successfully. His
point was that it was lame to rely on the compiler to find stuff, one
should desk check one's code thoroughly enough that one is sure the code
will compile. Failures should leave one kicking oneself.

I do not recall why Mr CompileClean felt that way. Probably time wasted
was one. back then 2500 lines of COBOL could take 30min to compile on
PDP-11/70. But I recall also something more, that he thought programmers
should be looking at what they wrote in your spirit of "the sooner the
better".

I do not need to tell you that type checking upstream or down does not
guarantee correct code. So if one is not looking at code closely enough
to determine if the compiler will barf, clearly one is not looking
closely enough to detect bugs. And I think that was a part of what MrCC
was down on.

Which reminds me of another story from that same high visibility RSTS/E
COBOL project. My manager saw me hunched over a listing and asked if
there was some problem. I said no, I was just desk-checking the code.
Relieved, he laughed and said we do not do that here. I was new. I said
what do you do, just run it and see? He said, no, we move it into
production, and started laughing.

Now there's a Lisper for you.

kenny
clinisys

Chris Perkins

unread,
Nov 21, 2001, 12:44:10 AM11/21/01
to

>
> Hope you have as much fun reading this little rant as I had writing it. ;)

I liked your rant quite a bit. As a C++ programmer I "liked" the Design
Patterns meaning that I understood the need for them, but I always felt they
were at heart just a kludge. Really, just a kludge on top of a kludge.
This is part of the reason I am learning Lisp now.

Chris


Chris Perkins

unread,
Nov 21, 2001, 2:10:23 AM11/21/01
to

> I do not follow you. [...deleted...] Or do you mean that you want

static type checking? That you cannot get
> very easily.

Sorry about that, the message went out before I got to re-read and edit it.
Static type checking would have been most analagous. However, I am in no
means advocating static type checking. I would not cut even a single hair
off Lisps dynamic language head.

I don't want to limit what can or can't be done in the Lisp. I don't want
the compiler to throw errors. I only want something that will help me
identify errors without having to discover them at runtime. Maybe something
like (check-function-for-obvious-errors 'function) Think less about type
errors and more about the situations you use assert clauses for right now.


> I disagree, probably to your surprise. The earlier an error is
detected,
> the _firmer_ the determination that it is an error is, and the simpler
> the world must be in which statements are made.

True, but our code does make simple statements from time to time. And it
would be nice if the simpler bugs could be vetted out. And it would be even
nicer if not so simple bugs could be discovered.....


> I assert that writing better code to begin with, working with a language
> that is actually small enough that it does not impose a cognitive load
on
> its users.

Yes, this is the most salient point against adding artificial constructs
(like DBC) to shore up our code. The more code, the harder it is to keep
all the details in ones head, and coding is a detail oriented job. So, as
programmers we try to fight this with elegance and simplicity, and when
those aren't enough we modularize.


When working on some recent large Java/C++ projects I used DBC extensively
and to great effect. Postconditions, preconditions, invariants, etc. were
all keeping the code ship shape. It was especially useful when the
following year the product was developed into its 2.0 version. There were
a lot of conditional checks, and many were fairly trivial. But every now
and then we'd make a change to something and despite great care to handle
all the consequences we'd set off a DBC assertion in testing. And, hey,
that's great - without that DBC check that little error might have gone
undetected or propogated itself into other problems. But, often once the
problem was examined I would realize that it was one of the trivial
assertions that caught it, and I'd think to myself "That assertion clause
wasn't complicated - I could write something to vette that out
systematically". But, of course, in Java or (worse) C++ one really couldn't
easily write something like that. But, in Lisp, well that's a different
story...

Anyway, I know Java and C++ are terribly brittle, and maybe as I work more
in Lisp I'll just perceive DBC, assert clauses, and the like as artificial
kludges for addressing the shortcomings of static languages. Maybe.... or
maybe not. I still use assert clauses in my Lisp code (though, thankfully,
not nearly as many) and a few seem like they could be systematically
verified.

Chris Perkins

Alain Picard

unread,
Nov 21, 2001, 5:28:40 AM11/21/01
to
k...@ashi.footprints.net (Kaz Kylheku) writes:

>
> Many of the the design patterns described in the Design Patterns book
> are largely just C++ workaround patterns. It's shocking that the authors
> don't appear to realize that; if they do, they sure don't acknowledge it;
> their introduction claims that these are genuine patterns of object
> oriented design.

I can't agree with you more; heck, I've tried to convince my
co-workers of it for years, BUT, to be fair, at least _one_ of the
authors _does_ realize it (I think it's Ralph Johnson, he's actually
a smalltalker). One of the patterns at least says that it's not
useful in smalltalk. [Book's at the office, so I can't check up
on which right now]. But I figure the other 3 authors (and the publishers)
made sure this point didn't come across too clearly...

As you say, next thing you know, people would stop buying Rose and Purify
and actually use programming environments that work... shudder. :-)

The amazing thing is, back when I was a C++ programmer, I thought that
was SUCH a great book. And I guess it was, in a way: it made it possible
to use C++ and get something done. In the long run, of course, that may
have been a disservice...

--
It would be difficult to construe Larry Wall, in article
this as a feature. <1995May29....@netlabs.com>

Thomas F. Burdick

unread,
Nov 21, 2001, 6:04:57 AM11/21/01
to
jlo...@hushmail.com writes:

> On Wed, 21 Nov 2001 02:54:06 GMT, Kenny Tilton <kti...@nyc.rr.com> wrote:
>
>
> >Sometimes I cannot because I use Semaphors a lot and these are
> >structures that arrange for a slot to be efficiently envalued by a
> >formula--if I die in a formula, fixing the formula in the source does
> >not change the lambda function that died, so I just "burn" the window
> >and re-run. without linking.
>

> What are these Semaphors? I guess it's not the IPC thing you're talking about,
> no? :)

No, it's his wacky[*] terminology for "constrained slot" :-)

[*] I really don't see the logic in the name. "semaphore" litterally
means "sign bearer". Or it can be the railroad thing, or the flag
thing. Maybe it's a physical metaphor for the railroad semaphore? Or
maybe there's another meaning of semaphore I don't know about?
Actually, I called it wacky, hoping that Kenny will explain the name :-)

Kenny Tilton

unread,
Nov 21, 2001, 10:22:13 AM11/21/01
to

"Thomas F. Burdick" wrote:
>
> jlo...@hushmail.com writes:
>
> > On Wed, 21 Nov 2001 02:54:06 GMT, Kenny Tilton <kti...@nyc.rr.com> wrote:
> >
> >
> > >Sometimes I cannot because I use Semaphors a lot and these are
> > >structures that arrange for a slot to be efficiently envalued by a
> > >formula--
> >

> > What are these Semaphors? I guess it's not the IPC thing you're talking about,
> > no? :)

No, but see below.

>
> No, it's his wacky[*] terminology for "constrained slot" :-)
>
> [*] I really don't see the logic in the name. "semaphore" litterally
> means "sign bearer".

Right, the "bearer" part conveys the dataflow, and the "sema" says
"meaning" to me, so I get "meaning bearer", tho "sign bearer" is what
the dictionaries say.

While Semaphor may be wacky, "constrained" is wrong. A constraint to me
/partially/ specifies a value in terms of other values. So I might have
(< x y) as a constraint on the values x can assume. The constraint does
not determine the value of x, it keeps x from becoming GE y at runtime.

Semaphors are CLOS slots that act like cells in a spreadsheet. A
formula /fully/ determines the value for the slot. If that is a
constraint it is a constraint with extreme prejudice.

Our first implementation used a lambda whose sole argument was the
instance owning the slot, but this had two problems. One, it was slow.
Two, where a slot value effected the screen appearance, lazy evaluation
is no good; a change to the value requires a screen update. Garneters
must manually call update-window or somesuch. Similarly, if x depends on
y and y changes, maybe y does not effect the screen but maybe x does and
x would return a new value if recalculated. So we arranged for eager
evaluation, with lots of optimizations to make that efficient.

[on IPC: we used win32 COPYDATA to splice semaphoric dataflow between
processes.]

The eager evaluation then means that a change to a single semaphoric
slot causes a cascade of dependent slot changes and (via a GF callback
specialized on the instance, new value and old value) to any necessary
manifestation outside the semaphoric web, such as a screen redraw.

I felt the metaphor of "bearing" was apt for the process of propagating
state. And in my metaphysics the meaning of anything is the sum of its
causes. Eager evaluation is cause-and-effect. Semantics is about
meaning. meaning+propagation = semantics+bearer = Semaphor. Misspelled
because I dig the word "metaphor" and so I can trademark it. :)

kenny
clinisys

Erik Naggum

unread,
Nov 21, 2001, 1:38:23 PM11/21/01
to
* Erik Naggum

> I disagree, probably to your surprise. The earlier an error is detected,
> the _firmer_ the determination that it is an error is, and the simpler
> the world must be in which statements are made.

* Chris Perkins


| True, but our code does make simple statements from time to time.

I was referring to the statement "this is an error".

| And it would be nice if the simpler bugs could be vetted out.

As you grow more accustomed to programming in a better language, you will
notice that you make far fewer "simple bugs". I am serious about this.

| Anyway, I know Java and C++ are terribly brittle, and maybe as I work
| more in Lisp I'll just perceive DBC, assert clauses, and the like as
| artificial kludges for addressing the shortcomings of static languages.

The overspecificity of these languages produces the need for tools to
combat their cognitive load. Having to specify so much detail so early
it just plain wrong, so you need tools that can help you keep things
together when you have to make changes as you learn what you should have
known by the time you specified these things. The nature of the problem
you are solving becomes known to you only as you try to solve it.

I believe C++ instills fear in programmers, fear that the interaction of
some details causes unpredictable results. Its unmanageable complexity
has spawned more fear-preventing tools than any other language, but the
solution _should_ have been to create and use a language that does not
overload the whole goddamn human brain with irrelevant details. Striking
that balance between language complexity and the convenience of using it
is amazingly hard, but I think Common Lisp is closer to this lofty ideal
than any other I have used. That the syntax is so predictable and so
easy to navigate using the proper editor, causes many more benefits than
people realize early on. I think the best advice right now is that you
should relax all those "needs" you have because you come from a C++/Java
environment.

Kenny Tilton

unread,
Nov 21, 2001, 1:46:33 PM11/21/01
to

jlo...@hushmail.com wrote:
>
> Seems interesting, but I'm not sure if I follow you. Could you post a concrete
> example of its use and usefulness? O:)

Well, if you know Garnet you need read no further, Semaphors are like
the constraints/demons tho with important differences such as eager vs.
lazy evaluation.

If you do not know Garnet, here is a simple example (with important
details missing):

(defmodel CTSelectable (Control)
()
(:default-initargs
:selected (sm? (find self (^selection (selector self)))) ;;
explained below
:controlAction #'(lambda (self os-event) (setf (selection (selector
self)) (list self)))))

(defmodel CTButton (CTSelectable Image)())

(def-sm-echo (forecolor) (self newvalue oldvalue) <invalidate self to
force redraw>)

(make-instance 'CTButton :forecolor (sm? (if (^selected self) red
blue)))))

---------------------------------------------------------------

"self" I throw in out of nowhere ala Smalltalk and C++ this. It is the
instance that owns the slot.

(selector self) returns (trust me) some cooperating supervisory instance
which keeps track of the selection defined by several buttons.

the ^macros arrange for behind-the-scenes dependency maintenance in
support of eager re-evaluation. now that I grok specials the ^macros are
superfluous, but I am still implementing that in an experimental branch
of development.

when the controlAction gets invoked (by a mechanism not shown) the
selection semaphor of the selector gets a new value. the dataflow engine
(DF) then causes the selected state to go non-nil. then DF makes the
forecolor of the instance in question change from blue to red. the echo
function associated with forecolor then triggers the screen redraw.

---------------------------------

usefulness? the grail. the silver bullet. better programmer
productivity:

- eliminates an entire class bug, viz, internal inconsistency arising
from oversights in state propagation. and it eliminates all the coding
required to propagate state throughout the application model.

- more self-documenting since it gathers the semantics of any slot in
one rule

- allows OO to deliver on the promise of re-use, since instances can be
assigned their own rules (even closing over different lexically-bound
values), in turn allowing us to get more varied behavior out of fewer
classes than is possible when slot parameters cannot be functional or
can be functional but must have the same rule for each instance of a
slot.

- eliminates the exponential growth of complexity as applications
increase in functionality. example from another domain: if one models in
detail the cashflow of a small business with a spreadsheet one ends up
with a quite complex model in which no cell formula ever taps more than
a few values. the spreadsheet author only has to worry about one formula
at a time, not the whole system all at once. the complexity emerges from
so many simple formulas. same with semaphors.

- it's great fun (as I think Garnetites can confirm)


kenny
clinisys

Lieven Marchand

unread,
Nov 21, 2001, 1:53:14 PM11/21/01
to
Kenny Tilton <kti...@nyc.rr.com> writes:

> I do not recall why Mr CompileClean felt that way. Probably time wasted
> was one. back then 2500 lines of COBOL could take 30min to compile on
> PDP-11/70. But I recall also something more, that he thought programmers
> should be looking at what they wrote in your spirit of "the sooner the
> better".

At that time in mainframe shops, you handed in your punch cards, they
were run and your listing was returned to you and your next shot at
the machine could be in another four hours. Don't assume an
interactive environment that is continuously available. In that
context desk checking was very valuable.

--
Lieven Marchand <m...@wyrd.be>
She says, "Honey, you're a Bastard of great proportion."
He says, "Darling, I plead guilty to that sin."
Cowboy Junkies -- A few simple words

Lieven Marchand

unread,
Nov 21, 2001, 2:00:39 PM11/21/01
to
Erik Naggum <er...@naggum.net> writes:

> I disagree, probably to your surprise. The earlier an error is detected,
> the _firmer_ the determination that it is an error is, and the simpler
> the world must be in which statements are made. For instance, we have
> the option in Common Lisp of redefining a function between the definition
> the compiler knew about at compile-time of a caller and the actual time
> it was called. This would require a total re-compile in languages that
> consider such things an error with no option to negotiate. In the long
> history of programming languages, indeed human history, there are people
> who insist that they know what is true and good, and who seek to limit
> other people's opportunity to find out what other things are true and
> good. These generally call anything they disagree with "errors" and make
> people angry at their compilers or computers. Then there are people who
> only think they know what is wrong, and while they have their own ideas
> about what is true and good, they only seek to limit other people's
> opportunity to do wrong and harmful things. These generally do not think
> things are errors unless they are _clearly_ wrong and harmful. If not
> clearly, they may issue a warning or a style-warning. (E.g., omitting
> the value of the final branch of a cond or case expression when the value
> returned is stored in a place that is declared not to accept nil as a
> possible value, might be a style warning because the compiler cannot know
> that you do not know better.)

I've always liked the Poplog terminology. They call errors mishaps and
have the same philosophy as CL about them. Off course, poplog is also
a highly dynamic language that grew up in AI research, so the
similarity is not surprising.

Thomas F. Burdick

unread,
Nov 21, 2001, 3:45:35 PM11/21/01
to
Kenny Tilton <kti...@nyc.rr.com> writes:

> While Semaphor may be wacky, "constrained" is wrong. A constraint to me
> /partially/ specifies a value in terms of other values. So I might have
> (< x y) as a constraint on the values x can assume. The constraint does
> not determine the value of x, it keeps x from becoming GE y at runtime.

(with-disclaiming
I really know jack about constraints, so I usually just refer to KR,
and KR slots. Which avoids any discussion about the nature of those
slots (so long as people know what KR is -- but if they don't, I
hand them the manual).)

[...]


> I felt the metaphor of "bearing" was apt for the process of propagating
> state. And in my metaphysics the meaning of anything is the sum of its
> causes. Eager evaluation is cause-and-effect. Semantics is about
> meaning. meaning+propagation = semantics+bearer = Semaphor. Misspelled
> because I dig the word "metaphor" and so I can trademark it. :)

Okay, this makes sense to me now. The "sema" in semaphore *really*
means sign to me because of, y'know, that whole thing where semaphores
are mechanical things that have actual signs. Oops, I didn't notice
you were dropping the -e -- that's a great excuse to redefine the
meaning of a word, you re-derived it from the greek (and according to
English conventions, even, not French).

Kenny Tilton

unread,
Nov 21, 2001, 4:11:12 PM11/21/01
to

"Thomas F. Burdick" wrote:
>
> Okay, this makes sense to me now. The "sema" in semaphore *really*
> means sign to me because of, y'know, that whole thing where semaphores
> are mechanical things that have actual signs.

right. when i was analyzing the name i was reminded also that that was
(is?) how ships communicated when near each other, with someone waving
about paddles (semaphores).

> Oops, I didn't notice
> you were dropping the -e -- that's a great excuse to redefine the
> meaning of a word,

<heh-heh> this is marketing, we don't need an excuse to redefine words.

constraints make me think of handcuffs, leg irons, strait jackets, duct
tape... kinky, but not my thing, and entirely the wrong connotation for
an empowering productivity hack.

kenny
clinisys

Pierre R. Mai

unread,
Nov 21, 2001, 3:47:48 PM11/21/01
to
Craig Brozefsky <cr...@red-bean.com> writes:

> 2. Use declaimations and/or declarations to set your compiler policy
> appropriatly. This will get quite a few typos. I put:
> (declaim (optimization (debug 3) (safety 3)))
> in my init file. Under cmucl I also:
> (setf *compile-print* nil)
> (declaim (optimize (inhibit-warning 3)))
> which reduced my console spam while compiling to the important
> warnings and notices.

Note that the next release of CMU CL will reduce spurious console spam
quite a bit on its own, too, thereby bringing it closer to the goal of
"every issued warning counts":

- Spurious warnings about undefined types/classes or functions for
classes/GFs defined in the same file as methods depending on those
have been eliminated.
- Code that is automatically generated by PCL (CMU CL's CLOS
implementation) will not emit compilation noise anymore. This was
especially annoying since this kind of code generation and
compilation often happens at run-time.

Regs, Pierre.

--
Pierre R. Mai <pm...@acm.org> http://www.pmsf.de/pmai/
The most likely way for the world to be destroyed, most experts agree,
is by accident. That's where we come in; we're computer professionals.
We cause accidents. -- Nathaniel Borenstein

Kent M Pitman

unread,
Nov 21, 2001, 4:42:28 PM11/21/01
to
Lieven Marchand <m...@wyrd.be> writes:

> Erik Naggum <er...@naggum.net> writes:
>
> > I disagree, probably to your surprise. The earlier an error is detected,
> > the _firmer_ the determination that it is an error is, and the simpler
> > the world must be in which statements are made. For instance, we have
> > the option in Common Lisp of redefining a function between the definition
> > the compiler knew about at compile-time of a caller and the actual time
> > it was called. This would require a total re-compile in languages that
> > consider such things an error with no option to negotiate.

I agree. I would spin it this way: The earlier an error is detected,
the more opportunity there should be to fix it. We have a choice
between a world like Gattaca describes in which people's DNA is
determined and the rest of their life follows as a consequence, or the
world the human genome people idealistically think they are working
toward where early diagnosis of something gives you the opportunity to
work toward a fix. Static languages seem to take the gattaca posture,
in part because the whole notion of staticness is to disempower people
to make choices in more places than one. In a static language does
early detection imply "last chance" because not only do static
languages attempt to do early detection, but later on, the sitatuion
is going to remain unchanged. There is no opportunity for users or
code to intervene to head off the inevitable. Like the unlucky
protagonist at center stage of a Shakespearean tragedy, knowledge of
the statically detected tragic flaw yields no hope, and if code is not
stopped, it will merely proceed to one inevitable fate. Hardly any
wonder the compiler gives up and leaves at intermission. But in a
dynamic language, the direness of the warning and the certainness are
in many cases orthogonally varying, and the possible futures are quite
a bit more varied.

> > In the long
> > history of programming languages, indeed human history, there are people
> > who insist that they know what is true and good, and who seek to limit
> > other people's opportunity to find out what other things are true and
> > good. These generally call anything they disagree with "errors" and make
> > people angry at their compilers or computers. Then there are people who
> > only think they know what is wrong, and while they have their own ideas
> > about what is true and good, they only seek to limit other people's
> > opportunity to do wrong and harmful things. These generally do not think
> > things are errors unless they are _clearly_ wrong and harmful. If not
> > clearly, they may issue a warning or a style-warning. (E.g., omitting
> > the value of the final branch of a cond or case expression when the value
> > returned is stored in a place that is declared not to accept nil as a
> > possible value, might be a style warning because the compiler cannot know
> > that you do not know better.)
>
> I've always liked the Poplog terminology. They call errors mishaps and
> have the same philosophy as CL about them. Off course, poplog is also
> a highly dynamic language that grew up in AI research, so the
> similarity is not surprising.

I think the term mishap is a misnomer, or would be for us.

I don't know if there are othe terms you like there, but I'm prepared to
defend the CL terminology if there are others you think are better. :-)
I just went and double-checked the terms and am happy that they all very
closely parallel their conventional English meanings.

The fully elaborated terminology for CL acknowledges that condition
objects represent situations. Situations are actual real-world
phenomena. Error situations are situations situations where something
is amiss. mishap is defined as "an unforunate accident" or "bad luck"
(says Merriam-Webster at webster.com). This seems to me quite a
subset of the possible situations, failing to acknowledge issues that
happen by well-meaning or ill-meaning intent, for example. I also
personally think it connotes an event of actual specific consequences.

Bob Bane

unread,
Nov 21, 2001, 5:01:52 PM11/21/01
to
Kaz Kylheku wrote:
>
> Many of the the design patterns described in the Design Patterns book
> are largely just C++ workaround patterns. It's shocking that the authors
> don't appear to realize that; if they do, they sure don't acknowledge it;
> their introduction claims that these are genuine patterns of object
> oriented design.
>
Has anyone stomped through the Design Patterns book and classified the
patterns in detail, preferrably on the web somewhere? I've seen the
"patterns are C++ workarounds" claim in many places (I saw it first by
Norvig), but never in a form I could easily shove up the nose of a C++
bigot.
--
Remove obvious stuff to e-mail me.
Bob Bane

Matthieu Villeneuve

unread,
Nov 21, 2001, 7:18:27 PM11/21/01
to

Peter Norvig's slideshow "Design Patterns in Dynamic Programming" is
very interesting:
http://www.norvig.com/design-patterns/ppframe.htm

One of the slides summarizes the study:
"16 of 23 patterns are either invisible or simpler, due to:
- First-class types (6): Abstract-Factory, Flyweight, Factory-Method,
State, Proxy, Chain-Of-Responsibility
- First-class functions (4): Command, Strategy, Template-Method,
Visitor
- Macros (2): Interpreter, Iterator
- Method Combination (2): Mediator, Observer
- Multimethods (1): Builder
- Modules (1): Facade"


--Matthieu

Rahul Jain

unread,
Nov 21, 2001, 7:23:38 PM11/21/01
to
Bob Bane <ba...@removeme.gst.com> writes:

> Has anyone stomped through the Design Patterns book and classified the
> patterns in detail, preferrably on the web somewhere? I've seen the
> "patterns are C++ workarounds" claim in many places (I saw it first by
> Norvig), but never in a form I could easily shove up the nose of a C++
> bigot.

Norvig himself has analyzed the issue and has a presentation available
discussing design patters in languages like Lisp, Smalltalk, and
Dylan:

http://www.norvig.com/design-patterns/

--
-> -/- - Rahul Jain - -\- <-
-> -\- http://linux.rice.edu/~rahul -=- mailto:rahul...@usa.net -/- <-
-> -/- "I never could get the hang of Thursdays." - HHGTTG by DNA -\- <-
|--|--------|--------------|----|-------------|------|---------|-----|-|
Version 11.423.999.220020101.23.50110101.042
(c)1996-2000, All rights reserved. Disclaimer available upon request.

Richard P. Gabriel

unread,
Nov 21, 2001, 8:58:14 PM11/21/01
to
I've been working with the patterns community for a long time. The so-called
Gang of Four (Gamma et al) design patterns are notoriously misleading about
the ideas behind patterns. A better way to think of what a pattern is in
software is to think about the kinds of advice an experience usability or UI
person would give to people working on a project in order to make the
interface really nice and usable.

Patterns are not about abstraction.

-rpg-

Fernando Rodríguez

unread,
Nov 22, 2001, 6:00:11 AM11/22/01
to
On Wed, 21 Nov 2001 18:46:33 GMT, Kenny Tilton <kti...@nyc.rr.com> wrote:

>
>
>jlo...@hushmail.com wrote:
>>
>> Seems interesting, but I'm not sure if I follow you. Could you post a concrete
>> example of its use and usefulness? O:)
>
>Well, if you know Garnet you need read no further, Semaphors are like
>the constraints/demons tho with important differences such as eager vs.
>lazy evaluation.

I checked the Garnet[1] site and the project seems to be abandoned. Is there
any other Lisp GUI toolkit that includes this sort of thing? O:-)

[snip]

>usefulness? the grail. the silver bullet. better programmer
>productivity:
>
>- eliminates an entire class bug, viz, internal inconsistency arising
>from oversights in state propagation. and it eliminates all the coding
>required to propagate state throughout the application model.

OK, I'm interested. :-)

Yesterday I spent the whole day debugging this sort of thing (although not in
a Lisp app), and they are the most annoying bugs I've seen. The app's GUI has
many states that modify the state of a huge number of widgets, so enforcing
consistency is very time, patience, good mood and coffee consuming... ;-)

Where can I learn more about these techniques? O:-)

TIA

[1] They abandoned it to start a C++ toolkit called Amulet. That would be
fine, since the application I'm dealing with right now is in C++, but Amulet
has also been abandoned. What the heck?... ;-P

--
Fernando Rodríguez
frr at wanadoo dot es
--

Thomas F. Burdick

unread,
Nov 22, 2001, 6:30:13 AM11/22/01
to
Fernando Rodríguez <spa...@must.die> writes:

> [1] They abandoned it to start a C++ toolkit called Amulet. That would be
> fine, since the application I'm dealing with right now is in C++, but Amulet
> has also been abandoned. What the heck?... ;-P

Well, Garnet isn't completely abandoned -- it is public domain, so
just because CMU threw it to the wolves, doesn't mean that the wolves
aren't takeing care of it. But, we aren't exactly continuing
development, either. That's too bad about Amulet. I know they
struggled for a long time to port it to C++ (time that could have been
spent amaking Garnet quite amazing), but it really sucks that that
ended out killing the project. I liked it a lot more being able to
imagine that there was a mutant Garnet out there somewhere :-(

Tim Bradshaw

unread,
Nov 22, 2001, 7:04:19 AM11/22/01
to
Bob Bane <ba...@removeme.gst.com> wrote in message news:<3BFC2450...@removeme.gst.com>...

> Has anyone stomped through the Design Patterns book and classified the
> patterns in detail, preferrably on the web somewhere? I've seen the
> "patterns are C++ workarounds" claim in many places (I saw it first by
> Norvig), but never in a form I could easily shove up the nose of a C++
> bigot.

I did this but not on the web, and I gave up before the end, sorry!

But I came to the conclusion, after talking to various people for a
bit, that patterns are *not* just C++ workarounds, but that there is
actually something more there. However I think that it is the case
that the GoF book patterns almost all are C++ workarounds, but perhaps
that says more about the book than patterns as such. Unfortunately
the patterns community seems to be riddled with the sort of cultism
that is so common in computing (it seems to have happened to XP too,
which is sad), and I'm kind of averse to that (the robes and diet of
cardboard fish get to me after a while, as does the ending up buried
in a pit with all the other cult members when the world fails to end
on time) so I kind of lost interest. But I think there may be
something there if you look beyond the GoF book.

--tim

Kenny Tilton

unread,
Nov 22, 2001, 12:32:56 PM11/22/01
to

"Fernando Rodríguez" wrote:
>
> On Wed, 21 Nov 2001 18:46:33 GMT, Kenny Tilton <kti...@nyc.rr.com> wrote:
>
> >
> >
> >jlo...@hushmail.com wrote:
> >>
> >> Seems interesting, but I'm not sure if I follow you. Could you post a concrete
> >> example of its use and usefulness? O:)
> >
> >Well, if you know Garnet you need read no further, Semaphors are like
> >the constraints/demons tho with important differences such as eager vs.
> >lazy evaluation.
>
> I checked the Garnet[1] site and the project seems to be abandoned. Is there
> any other Lisp GUI toolkit that includes this sort of thing? O:-)

COSI is similar. On this page, check out Paper #6 under 1999 papers:

http://www-int.stsci.edu/apsb/doc/papers-and-meetings/papers.html

But under their system constraints are defined for a class. Semaphors
for the same slot can vary from instance to instance. Other diffs as
well. No demons/echos, but changes go thru (setf <slotName>). Semaphors
echo out of (setf slot-value-using-class) so it does not matter what the
writer method is called (which might vary from class to class onthe same
slot) and so it gets kicked off at make-instance time (initforms go thru
(setf SVUC)).


>
> Yesterday I spent the whole day debugging this sort of thing (although not in
> a Lisp app), and they are the most annoying bugs I've seen. The app's GUI has
> many states that modify the state of a huge number of widgets, so enforcing
> consistency is very time, patience, good mood and coffee consuming... ;-)

Semaphors are definitely great fun for complex or large problems like
that.

>
> Where can I learn more about these techniques? O:-)
>

I plan to share the existing ACL/win32 stuff RSN. The DF engine will be
proprietary FASL-only until/if I decide to OpenSource it and will come
with a license for non-commercial use. Commercial use will not be a
problem, I just haven't thought that far.

The GUI source will be, oh, I don't know, GPL to start? That could be
relaxed over time as things develop.

There is a small amount of doc. I will add to that in the context of an
open project to build a GPL optics workbench simulator. (A pet project.)
I will also help anyone with their code myself. That would include
newbie help and also advanced help for when things get hairy. Also
adding extensions to Semaphors where that seems the Right Thing to solve
a problem.

If ACL/Win32 is not your platform I will try to work something out,
either getting the same platform or having someone build FASLs under
NDA. MCL is a little harder because they do not support the MOP, but
that is where Semaphors started (ie, a MOP-less approach is possible). I
am not crazy about making that effort, tho. Maybe if a lot of interest
developed from that quarter.


> TIA
>
> [1] They abandoned it to start a C++ toolkit called Amulet. That would be
> fine, since the application I'm dealing with right now is in C++, but Amulet
> has also been abandoned. What the heck?... ;-P
>

Wow. I see they Open-sourced it, but that page does not show any news or
updates in a year. Dead also?

I have actually ported Semaphors to C++ and Java out of curiosity.
Without macros more plumbing shows, but they seemed to work. Python
looks very doable. If CL users don't dig Semaphors I'll see what the
Pythonites think, looks like they'll eat anything.

kenny
clinisys

Reini Urban

unread,
Nov 22, 2001, 9:34:48 PM11/22/01
to
Tim Bradshaw wrote:
>But I think there may be
>something there if you look beyond the GoF book.

I esp. like the AntiPatterns Book.
At my acadwiki http://xarch.tu-graz.ac.at/acadwiki/AntiPattern I try to
categorized some for the web.

Positive patterns in other languages than lisp are
mostly useless for lispers, even the smalltalk patterns,
but anti patterns are usually common.
--
Reini Urban
http://tv.mur.at/film/

Will Deakin

unread,
Nov 23, 2001, 5:27:12 AM11/23/01
to
Kenny Tilton wrote:

> I do not need to tell you that type checking upstream or down does not
> guarantee correct code. So if one is not looking at code closely enough
> to determine if the compiler will barf, clearly one is not looking
> closely enough to detect bugs. And I think that was a part of what MrCC
> was down on.


This is an excellent point.

In written english did a lot of this when writing a thesis and I
still see this every day in word documents and emails -- when stuff
is spell checked people assume that it is *right*. But all spell --
or type name -- checking tells you is that the spell checking
recognised all the words: a bit of a chocolate fireguard.

Aha, you might say, the next this is grammar checkers. And computer
languages are much more robust in this respect than natural
languages. However, again the guarantees give are also fraught with
danger because they give the unwary a fuzzy glow of success -- or
desparate anger in the case where valid syntax is marked as wrong[1].

:)w

[1] One of my biggest pains was writing about light propagation in
optical crystals where the nouns `field' and `feld'[2] are both valid.
[2] As in `Icelandic feld spar'.

Tim Bradshaw

unread,
Nov 23, 2001, 6:32:49 AM11/23/01
to
"Richard P. Gabriel" <r...@dreamsongs.com> wrote in message news:<B8219BB6.C3D%r...@dreamsongs.com>...

>
> Patterns are not about abstraction.

Yes. I think this is the key point that should be made about them and
which is completely missing in a lot of the literature (well, in the
GoF book).

When I read it, I found myself just getting annoyed and cynical (OK, I
was already cynical), because virtually everything they actually
describe is a stupid half-working workaround for something that is a
problem only because people program in some completely inadequate
language like C++. And this all seemed to be raised up into some
quasi-religions thing.

I think (as a non-patterns person) that it's somehow about rituals.
Rituals are ways of doing something which you just do, rather than
working out all the time from first principles why it's done like
this, and *good* rituals are ways of doing something that turn out to
work well and combine well with other good rituals.

Software development is a mass of rituals, and most of them are bad
ones. I find myself spending a lot of time trying to work out and
explain *why* things are being done, because most of the time you find
that there is just no reason at all - and if you repeatedly ask why
you can maybe stop this thing being done or work out how to do it
better (or, more likely, get sacked for being an inconvenient and
annoying person). These bad rituals are almost the same thing as what
I was calling cults in my other message in this thread.

A good example of this working is working out what backup strategies
should be: everyone has them, and something happens every day, and it
all feels comfortable. But you need to really look hard at what is
being done, and in particular you have to work out what the bad cases
are: if the disk goes on fire can you take a naked machine and recover
it in a hurry? Is anything useful actually getting written to tape
(do you need multiple drives / multipke controllers?). Is it for
disaster recovery or accidental file-deletion recovery, should you use
different processes (rituals) for these rather than the same for both?
What happens if the building burns down: do you need offsite backups
(in one case I dealt with I decided the answer was no: if we had an
event bad enough to take out the machine room and the tape store (4
floors up) then about our last problem was data recovery since the
organisation would not recover from such an event anyway). I bet that
*most* backup strategies have *serious* vulnerabilities to some
reasonably likely event, because no one has ever stopped to think
about what they are doing.

But you can't always do this - for instance you need to be able to
work out, once, what works, and not do it each time, and sometimes
it's really not clear why what works does work. So you describe the
rituals that work as rituals, and call them patterns. Of course,
without the analysis of why you can't distinguish patterns from cults,
and that's a big problem, since I think a lot of patterns turn out to
be cults.

I think that things like `how you go about developing code in Lisp'
are good candidates for patterns - there clearly are a bunch of
rituals that people use, and they are often very successful, but even
if you can work out why they work such a description would be so
enormous that it's better to say `do it this way, it works'.

--tim

Richard P. Gabriel

unread,
Nov 23, 2001, 1:07:12 PM11/23/01
to
in article fbc0f5d1.01112...@posting.google.com, Tim Bradshaw at
tfb+g...@tfeb.org wrote on 11/22/01 4:04:

> Unfortunately
> the patterns community seems to be riddled with the sort of cultism
> that is so common in computing (it seems to have happened to XP too,
> which is sad), and I'm kind of averse to that

There is a fine line to observers between cult and culture. I have been part
of the patterns community since it started, and it has a strong culture
derived from the community's interest in making developing software easier
and using software better for end users. There are a number of people in the
community who believe the works of Christopher Alexander are getting at
something important. I believe this as well - in many ways what the patterns
community is saying about the advantages of patterns and pattern languages
are what we were saying were the advantages of Lisp.

Patterns are about what to build, not how to build it.

People who believe in Alexander use his vocabulary, just as many of you use
the vocabulary of McCarthy, Moon, Steele, and - consider this - me. This
makes them seem a little cultish, as does your use of a culture-specific
language. Think about how some folks in the Lisp community feel denotational
semantics is important or #F is better than NIL. This is cultish. Or is it
cultural?

XP came out of the patterns community and by the same people who started the
patterns movement, so it's not odd that that community would be built based
on a strong cultural basis.

There is really a lot to patterns and the patterns community, though that
community is in decline. If you want to find out about it, try reading
Alexander's "The Oregon Experiment," which I think is the easiest, quickest
way to see the ideas. After that "The Timeless Way of Building." A long
time ago I wrote a bunch of essays explaining the ideas to the OO community
which were collected in a book. If you have a friend who has the book you
can take a look at those essays.

But don't dismiss patterns because of the GoF - much of the patterns
community derides that work as well. Think of the GoF as helping losers lose
less.

-rpg-

Paolo Amoroso

unread,
Nov 23, 2001, 2:20:40 PM11/23/01
to
On 23 Nov 2001 03:32:49 -0800, tfb+g...@tfeb.org (Tim Bradshaw) wrote:

[about the GoF patterns book]


> When I read it, I found myself just getting annoyed and cynical (OK, I
> was already cynical), because virtually everything they actually
> describe is a stupid half-working workaround for something that is a
> problem only because people program in some completely inadequate
> language like C++. And this all seemed to be raised up into some

I seem to remember that they candidly admit a few times that languages such
as Lisp, or maybe they explicitly mention CLOS, don't need patterns. I
don't have the book handy, so I can't check.


Paolo
--
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://web.mclink.it/amoroso/ency/README
[http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/]

Paolo Amoroso

unread,
Nov 23, 2001, 2:20:42 PM11/23/01
to
On Wed, 21 Nov 2001 17:58:14 -0800, "Richard P. Gabriel"
<r...@dreamsongs.com> wrote:

> the ideas behind patterns. A better way to think of what a pattern is in
> software is to think about the kinds of advice an experience usability or UI
> person would give to people working on a project in order to make the
> interface really nice and usable.

Do you mention this as a general example, or because the kind of advice
from usability/UI persons, and not other kinds of advice, provides better
insight on software patterns?

Richard P. Gabriel

unread,
Nov 23, 2001, 3:25:56 PM11/23/01
to
in article 7nL+O5eiZiCvDZ...@4ax.com, Paolo Amoroso at
amo...@mclink.it wrote on 11/23/01 11:20:

> On Wed, 21 Nov 2001 17:58:14 -0800, "Richard P. Gabriel"
> <r...@dreamsongs.com> wrote:
>
>> the ideas behind patterns. A better way to think of what a pattern is in

>> software is to think about the kinds of advice an experienced usability or UI


>> person would give to people working on a project in order to make the
>> interface really nice and usable.
>
> Do you mention this as a general example, or because the kind of advice
> from usability/UI persons, and not other kinds of advice, provides better
> insight on software patterns?

Because that sort of advice is most like what the best patterns are like,
and so if you can appreciate that sort of advice, then you can appreciate a
good pattern in another area when you see it.

Here's another true statement about patterns: If there are no such things as
patterns in the Lisp world, then there are no statements a master programmer
can give as advice for junior programmers, and hence there is no difference
at all between an beginning programmer and a master programmer in the Lisp
world.

The GoF patterns are notorious in parts of the patterns world for
misrepresenting the patterns concept because they provide to C++ programming
constructs we have in Lisp. The authors of the book understand that - they
are as smart and knowledgeable as you all think you are - but maintain that
the poor C++ programmer needs these patterns, which is true.

But, patterns by themselves are neither interesting nor generally useful. A
pattern is part of a pattern language, which is a coordinated set of
patterns that tell you how to build a really nice artifact of a particular
category customized to your needs. If you are someone who thinks that a
pattern is just an abstraction or is something that a great abstraction
mechanism can provide for you, then put that thought firmly in your head
right now.

Here are some remarks about a pattern language for spreadsheets. By a
"spreadsheet" I mean any sort of constraint satisfaction system that relies
on geometry to provide intuitive assistance to its users who use and
sometimes program the spreadsheet using, perhaps, a user interface. The
design of the "macro language" is part of the problem of designing and
building the spreadsheet. A spreadsheet pattern language is aimed at doing
two things: It teaches how to create such a system, and it teaches what
makes a good spreadsheet for users and for programmers who have to build and
maintain spreadsheets.

It starts with a tour of what a general spreadsheet is in the form of a
skeleton of the steps you would take to write one. You would use this PL if
you needed to write a spreadsheet program for a particular application or
for a particular set of users with oddball needs. Its patterns would tell
you at every stage of the process what to build (code or design) next. If
you were an expert programmer but had never done a spreadsheet before you
would be able to build a nice one the first time, and at the end you would
understand how to build anything that was like a spreadsheet - perhaps with
the assistance of the pattern language.

The patterns and pattern language are a stylized way of presenting the
information you need, and each pattern includes the reasons why the thing
you build using the pattern makes it nicer for you as designer/coder and for
the person using the spreadsheet.

You *could* substitute for this some mondo set of abstractions and macros
and a framework for generalized spreadsheets along with some documentation
for it, but the pattern language is more general and in the end it teaches
you about the art of creating spreadsheets. And, in languages like C++,
Java, and SmallTalk, you could do the exact same thing, yet many people
prefer to write pattern languages, mostly because of the pedagogical angle.

Again, if you think patterns are only about abstractions, then you must
notice you never comment to yourself that one piece of code is better than
another nor that one design is better than another. Patterns are a literary
form for expressing those judgments along with the reasons why, and a
pattern language is a literary form for showing and teaching people how to
build a nicely designed and implemented system.

-rpg-

Wade Humeniuk

unread,
Nov 23, 2001, 4:20:54 PM11/23/01
to
> Again, if you think patterns are only about abstractions, then you must
> notice you never comment to yourself that one piece of code is better than
> another nor that one design is better than another. Patterns are a
literary
> form for expressing those judgments along with the reasons why, and a
> pattern language is a literary form for showing and teaching people how to
> build a nicely designed and implemented system.

Do you mean something like this simple case? (In Lisp of course)

(declare-pattern grocery-list
:number-of-items (probably < 200)
:functionality
(must (insert-item and (sort-by-location-in-store since easier-to-follow
and
store is sorted by food-catagory)))
:implementation-data-representation
((lisp-list since lisp-list is not to long and insertable and orderable)
(not hash-table since storage-requirements and complexity
exceed functionality)))

Wade


Kaz Kylheku

unread,
Nov 23, 2001, 5:04:21 PM11/23/01
to
In article <0W=+O1VxGoGH6Zng...@4ax.com>, Paolo Amoroso wrote:
>On 23 Nov 2001 03:32:49 -0800, tfb+g...@tfeb.org (Tim Bradshaw) wrote:
>
>[about the GoF patterns book]
>> When I read it, I found myself just getting annoyed and cynical (OK, I
>> was already cynical), because virtually everything they actually
>> describe is a stupid half-working workaround for something that is a
>> problem only because people program in some completely inadequate
>> language like C++. And this all seemed to be raised up into some
>
>I seem to remember that they candidly admit a few times that languages such
>as Lisp, or maybe they explicitly mention CLOS, don't need patterns. I
>don't have the book handy, so I can't check.

Yes they do, albeit weakly. They say in the introduction that in CLOS
there is a ``lesser need'' for design patterns like Visitor, instead
of saying out right that there is in fact no need. No need implies lesser
need, so at least they aren't lying.

But what is damning is that they admit that if the book's
focus was procedural languages like C, Pascal or Ada, then among the
design patterns, they would have to consider "Inheritance", "Polymorphism"
and so on.

That's a clear indication that the patterns are a manual workaround,
and the authors know it: that they are programs to be executed by the
programmer, where automation is lacking in the machine.

I would add that if the book was about assembly language, then "control
structures" and "data structures" would be listed as design patterns.

Richard P. Gabriel

unread,
Nov 23, 2001, 7:24:52 PM11/23/01
to
in article 9tmejt$gf5$1...@news3.cadvision.com, Wade Humeniuk at
hume...@cadvision.com wrote on 11/23/01 13:20:

Yes, this is an excellent example of completely misunderstanding the concept
of patterns. Is that what you meant?

-rpg-

Friedrich Dominicus

unread,
Nov 24, 2001, 1:50:18 AM11/24/01
to
"Richard P. Gabriel" <r...@dreamsongs.com> writes:
>
> Patterns are about what to build, not how to build it.
I dont't think that is fully the case. Having read your book (Patterns
of Software) and having it always within reach. I cite (page 47
(Pattern languages)
The way Alexander motivates pattern languages is with the example of
barns.
....
If each farmer were to desing and build abarn based on this functional
requirements, each barn would be different, probably radically
different.
...

But barns in Swiss valleys do not vary wildly, so each farmer must be
copying something.
...

That does imply for me that not just what to build is important but
even how you do it. Just an example. I would be damn bad idea to put
the hay in the cellar. So you will always try to put it above the
cattle. That is a how for me. It suggest how to build such things.

In fact pattern has a lot of meanings but the nearest hit IMHO is
template. That has another smell hasn't it ;-)

Well the template of the GOF book are introduced using C++. Therefor
one better know how to deal with C++ to understand those
patterns. In Common Lisp there are surely other templates. E.g a very
easy one is
- transform elements of a collection

Well this is so common that we have some patterns for that. We or the
inventors have even gave it a name. How is it done is still open, I
agree, but there are still suggestions on how to do it.
Take one element
Transform it
keep the result somewhere

>
> But don't dismiss patterns because of the GoF - much of the patterns
> community derides that work as well. Think of the GoF as helping losers lose
> less.

I think this is a bit unfair. It's the same as how the authors do not
state explicitly or clearly that this patterns are not of use
universal but for xy. I don't feel as if it's good idea to call the
users of the GoF book as loosers.

Regards
Friedrich

Fernando Rodríguez

unread,
Nov 24, 2001, 5:24:54 AM11/24/01
to
On Thu, 22 Nov 2001 17:32:56 GMT, Kenny Tilton <kti...@nyc.rr.com> wrote:

>> Where can I learn more about these techniques? O:-)
>>
>
>I plan to share the existing ACL/win32 stuff RSN. The DF engine will be

RSN? O:-)

>If ACL/Win32 is not your platform I will try to work something out,
>either getting the same platform or having someone build FASLs under

I'm using LWW. Is it very implementation dependant? Would it work with
Allegro 'free' version?

>> [1] They abandoned it to start a C++ toolkit called Amulet. That would be
>> fine, since the application I'm dealing with right now is in C++, but Amulet
>> has also been abandoned. What the heck?... ;-P
>>
>
>Wow. I see they Open-sourced it, but that page does not show any news or
>updates in a year. Dead also?

It doesn't look very alive, but I'll take a look at it.

>I have actually ported Semaphors to C++ and Java out of curiosity.
>Without macros more plumbing shows, but they seemed to work. Python
>looks very doable. If CL users don't dig Semaphors I'll see what the
>Pythonites think, looks like they'll eat anything.

I also use Python, so that's OK for me. ;-)

Software Scavenger

unread,
Nov 24, 2001, 5:26:51 AM11/24/01
to
"Richard P. Gabriel" <r...@dreamsongs.com> wrote in message news:<B82428D4.171B%r...@dreamsongs.com>...

> Yes, this is an excellent example of completely misunderstanding the concept
> of patterns. Is that what you meant?

How is it different than a program design document? You can implement
a pattern on different platforms and/or in different contexts, just
like you can port a program to different platforms and/or contexts.
It seems to me the pattern is just an abstraction of the program
design, including the reasons for making the design decisions. By
getting rid of the baggage of implementation, the design becomes more
easily portable. Is a pattern really just a program design document?

Kenny Tilton

unread,
Nov 24, 2001, 6:51:27 AM11/24/01
to

"Fernando Rodríguez" wrote:
>
> On Thu, 22 Nov 2001 17:32:56 GMT, Kenny Tilton <kti...@nyc.rr.com> wrote:
>
> >> Where can I learn more about these techniques? O:-)
> >>
> >
> >I plan to share the existing ACL/win32 stuff RSN. The DF engine will be
>
> RSN? O:-)

within a month?

> I'm using LWW. Is it very implementation dependant? Would it work with
> Allegro 'free' version?

version 1.0 will use ACL Common Graphics enough places to require ACL.
In the GUI stuff. The DF engine is CL+MOP. A quick apropos on the free
LWW suggests the MOP support there would suffice for that much.

version <next> would resurrect the bit I did where I wrapped CG widgets
(and could prob wrap also arbitrary win32 controls).

version <next> would elim ACL CG and just use win32 calls. Then I guess
a port to LWW would require only FFI access to that. Porting from MCL to
ACL took a solid, intense month, FWIW.

version <Mac>... without MOP support in MCL I either do a MOP-less
version or, well, can CMUCL be run under OSX or some Mac Linux or
something?

yes, it works with the ACL 'free' version.

I plan to follow the path of greatest interest (if any), so the above
rough plan might well be overtaken by events.

kenny
clinisys

Kenny Tilton

unread,
Nov 24, 2001, 7:35:34 AM11/24/01
to

Kenny Tilton wrote:
>
> "Fernando Rodríguez" wrote:
...


> > RSN? O:-)
>
> within a month?

btw, before going public I am taking a crack at fixing a long-standing
problem with the propagation, so this could delay things a week.

the flaw arises when:

1. B uses A in a calculation. Maybe B <= 2 * A

2. C uses A and B. Maybe C <= (+ A B)

First of all, we get an inefficiency because C recalculates twice.

Worse, depending onhow things unfolded at runtime, when A changes C
might get notified first and take on a bogus value until B gets notified
and in turn again notifies C to refresh itself.

So:

(setf A 1)

Evaluate B: 2

Evaluate C: 3

(setf A 2)

C changes to 4 (not good)

B changes to 4

C changes to 6 (correct)

The amazing thing to me is that this has not presented a problem in five
years of heavy use in many different kinds of application. But I think I
see a way to sort it out, so I thought I would fix that up before going
public.

Another issue I should address is rolling back dataflow via
unwind-protect, but I am not even sure that is feasible. Currently
changes to a semaphoric slot are manifested outside the flow via echo
functions as each slot takes on a new value, before propagating the
change to dependents. I could easily back out the slot changes, but the
echos of course would have done their thing. Echoing after the
propagation--well, that's an area for future research, but I do know
there are a number of places where it is a Good Thing the side-effects
of echos happen before propagation, so that might be dicey.

Again, this has not been a problem and Semaphors have been stress-tested
severely over the years, so maybe unwinding is not a concern. But if a
wider audience starts running into problems we can play with this.

kenny
clinisys

Wade Humeniuk

unread,
Nov 24, 2001, 10:07:43 AM11/24/01
to
>
> > Yes, this is an excellent example of completely misunderstanding the
concept
> > of patterns. Is that what you meant?
>
> How is it different than a program design document? You can implement
> a pattern on different platforms and/or in different contexts, just
> like you can port a program to different platforms and/or contexts.
> It seems to me the pattern is just an abstraction of the program
> design, including the reasons for making the design decisions. By
> getting rid of the baggage of implementation, the design becomes more
> easily portable. Is a pattern really just a program design document?

To really be effective the vocabulary used in a design document must be
commonly understood by the people sharing the design document. It always
was bit frustrating to write a design document because I always seemed to
take artistic liscense (so that the design would be attractive to other
developers and thus they would adopt the thinking) of thus how much was a
lie (lie by ommision and simplification). Though in the end with people
working on the software together this vocabulary allowed qiuck discussion of
large sections of the implementation. There seemed to be concepts like
finite state machines, device drivers, interprocess communication that were
developed based on conventions and experience that other people had. The
design document became less important as the work went along as people
realized it was of little use.

Wade


Wade Humeniuk

unread,
Nov 24, 2001, 10:27:43 AM11/24/01
to
> Yes, this is an excellent example of completely misunderstanding the
concept
> of patterns. Is that what you meant?

Mostly I was probing for more information (someone had to ask a question).
I see I should do some reading. Anyways...

Is the fault in the example the attempt to formalize? Or is it that a
grocery list not a pattern (though all grocery lists seem to pretty
similar)? Or something else?

Wade


Kaz Kylheku

unread,
Nov 24, 2001, 12:12:32 PM11/24/01
to
In article <a6789134.01112...@posting.google.com>, Software

Scavenger wrote:
>"Richard P. Gabriel" <r...@dreamsongs.com> wrote in message news:<B82428D4.171B%r...@dreamsongs.com>...
>
>> Yes, this is an excellent example of completely misunderstanding the concept
>> of patterns. Is that what you meant?
>
>How is it different than a program design document? You can implement
>a pattern on different platforms and/or in different contexts, just
>like you can port a program to different platforms and/or contexts.
>It seems to me the pattern is just an abstraction of the program
>design, including the reasons for making the design decisions.

A pattern is a step by step recipe which a programmer follows; so in
effect it is software that is executed by the programmer. In principle,
it could be executed by the machine.

In the Introduction, the authors of _Design Patterns_ admit that if their
target languages were C or Pascal, then ``Inheritance'' and ``Polymorphism''
would be included among the design patterns.

So, extending one step further, if they used even lower level languages,
then perhaps ``Control Structure'' and ``Data Structure'' would also
be patterns; the programmer would follow these patterns to crank out
code with certain properties, without the aid of the machine.

Kenny Tilton

unread,
Nov 24, 2001, 4:53:46 PM11/24/01
to

Kenny Tilton wrote:
>
> btw, before going public I am taking a crack at fixing a long-standing
> problem with the propagation, so this could delay things a week.
>
> the flaw arises when:
>
> 1. B uses A in a calculation. Maybe B <= 2 * A
>
> 2. C uses A and B. Maybe C <= (+ A B)
>

...


> The amazing thing to me is that this has not presented a problem in five
> years of heavy use in many different kinds of application.

Well, turned out to be hard to trigger this problem, partly because
recently I put in a partial quick fix:

before propagating a change in A to /any/ of its dependents, flag
/all/ dependents as requiring re-evaluation.

So even if C gets told to recalculate before B, when it samples B the
internals see it requires reevaluation and comes up with a freash value.

But I /did/ manage to set up double calculation (the first erroneous)
and I /have/ seen it in real-world code, so I'm going in. I had to set
up multiple layers of dependency and order the code just right. The
flag-all trick can only go one dependency deep because optimizations
stop propagation if a given node does not change. Thus I do not know if
dependents of a dependent require recalculation until that dependent
recalculates and is observed actually to change.

btw, lest that sound a little hairy to work with, my objective has
always been that the user should just be able to code rules without
worrying about this stuff, just as a spreadsheet author nowadays (not at
first) only needs to watch out for circularities.

kenny
clinisys

Fernando Rodríguez

unread,
Nov 25, 2001, 4:32:55 AM11/25/01
to
On Thu, 22 Nov 2001 17:32:56 GMT, Kenny Tilton <kti...@nyc.rr.com> wrote:

>> I checked the Garnet[1] site and the project seems to be abandoned. Is there
>> any other Lisp GUI toolkit that includes this sort of thing? O:-)
>
>COSI is similar. On this page, check out Paper #6 under 1999 papers:
>
> http://www-int.stsci.edu/apsb/doc/papers-and-meetings/papers.html
>

I also found this
http://cocasoft.cs.tamu.edu/~lidu/courses/db01f/papers/GUInDatabase-goyal98.pdf

It's about abstracting the GUI as a sort of prolog database (with the state of
widgets defined with facts and rules) and considering the event handlers as
queries that modify this DB.

The idea seems cool, thought I'm not sure if I like the pseudo-prolog / C++
implementation. I don't know how this compares to your Semaphores...

Kenny Tilton

unread,
Nov 25, 2001, 11:34:41 AM11/25/01
to

"Fernando Rodríguez" wrote:
>
>
> I also found this
> http://cocasoft.cs.tamu.edu/~lidu/courses/db01f/papers/GUInDatabase-goyal98.pdf
>

Nice find, thx. I'll add that to the bibliography.

> It's about abstracting the GUI as a sort of prolog database (with the state of
> widgets defined with facts and rules) and considering the event handlers as
> queries that modify this DB.
>
> The idea seems cool, thought I'm not sure if I like the pseudo-prolog / C++
> implementation. I don't know how this compares to your Semaphores...

Very similar in many ways. details probably differ, but the big picture
is the same. One quibble: upon discovering parallels between the GUI
problem and database management they concluded that GUI management /is/
a database management problem. I would have said that GUI and DBMS were
special cases of some higher-order state management problem.

As for the implementation language issue, yes, early on I saw that one
of the biggest wins about Semaphors is that they are Just Lisp. GarnetSo
that makes them more approachable. The constraints crowd tended to
create whole new languages built atop the constraint solver. With
Semaphors you have to get used to the paradigm shift, but that's fun.
And nothing stops anyone from having a slot rule invoke an embedded
prolog system or constraint-solver to calculate a new value. So you get
the best of both i think.

back on the ranch, unexpectedly easy progress fixing that dataflow
problem in which slots transiently take on illogical values, might roll
over for me today if a -- simple solution holds up and i get a few
hours in.

kenny
clinisys

Kenny Tilton

unread,
Nov 25, 2001, 1:50:28 PM11/25/01
to

Kenny Tilton wrote:
> back on the ranch, unexpectedly easy progress fixing that dataflow
> problem in which slots transiently take on illogical values, might roll
> over for me today if a -- simple solution holds up and i get a few
> hours in.

ok, that was easy. i'll get to work now on a distro for ACL/CG/Win32.

kenny
clinisys