From: Peter Seibel
Subject: Synonym streams
Date: 
Message-ID: <m3r82o6xoj.fsf@javamonkey.com>
I was trying to figure out what synonym streams are for and came up
with the following explanation. I'm hoping someone can tell me if this
is more or less right.

Suppose I want to make an encapsulated stream (say an echo stream)
that will track changes to a well-known stream variable such as
*standard-input*. I can make it like this:

  (make-echo-stream (make-synonym-stream '*standard-input*) my-output-stream)

Now if someone changes or rebinds *standard-output* while I'm still
using the echo stream, it will pick up on the change. Whereas if I
made the echo stream like:

  (make-echo-stream *standard-input* my-output-stream)

it would keep using the stream referenced by *standard-input* at the
time the echo stream was made, even if *standard-input* is later reset
or rebound. A similar situation could arise when making a broadcast
stream.

Is that it? Or is there some other use that I'm totally missing?

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp

From: Kent M Pitman
Subject: Re: Synonym streams
Date: 
Message-ID: <sfwu17krysc.fsf@shell01.TheWorld.com>
Peter Seibel <·····@javamonkey.com> writes:

> I was trying to figure out what synonym streams are for and came up
> with the following explanation. I'm hoping someone can tell me if this
> is more or less right.
> 
> Suppose I want to make an encapsulated stream (say an echo stream)
> that will track changes to a well-known stream variable such as
> *standard-input*. I can make it like this:
> 
>   (make-echo-stream (make-synonym-stream '*standard-input*) my-output-stream)
> 
> Now if someone changes or rebinds *standard-output* while I'm still
> using the echo stream, it will pick up on the change. Whereas if I
> made the echo stream like:
> 
>   (make-echo-stream *standard-input* my-output-stream)
> 
> it would keep using the stream referenced by *standard-input* at the
> time the echo stream was made, even if *standard-input* is later reset
> or rebound. A similar situation could arise when making a broadcast
> stream.
> 
> Is that it? Or is there some other use that I'm totally missing?

No.  I'm not even sure you're allowed to do this (Because of potential
circularities).

It's so you can have interdependent "well-known variables".  In particular,
it allows *standard-input*, *standard-output*, *query-io*, and *debug-io*
to be synonym streams to *terminal-io* without having to rebind anything
other than *terminal-io* to change the "focus of attention" to another
window.  On the Lisp Machine, *terminal-io* (which was very badly named),
meant what might better have been called *current-window*.

Unfortunately, because hte hygiene for maintaining window focus is 
ill-specified in CL in general, being left to implementations, you 
mostly can't use it in this way.  You could, of course, make similar
mechanisms of your own, so that you only had to bind one focus variable
in order to change things.

Note that LispWorks, for example, just makes *terminal-io* go to some
tty-like window that I, for one, never want to talk to.  I think they
decided (alas) that this icky DOS-like window was the "terminal".  The
window more resembles what the Lisp Machine would call the "cold load 
stream", the court of last resort in debugging. The
intended abstraction, I think, by those who created this set of names,
would have been that they would have let that be *terminal-io* until
they had bootstrapped their way into multiprocessing, and then would
have re-bound *terminal-io* per process, leaving *standard-input* and
friends alone (because they'd be synonym streams).  By the time I found
what they'd one (which is not non-conforming, as far as I know, just
not what I and others intended), I'm not sure there was any way to get
them to back out of it.

Nor are they likely to be the only ones who  did this.  I think there
are other implementations that have said that there is always a 
*standard-input* and *standard-output*, like stdin and stdout, but
that sometimes there is no (or no useful) *terminal-io* if windowing
operaitons of some class are not supported.  THis is again, not what I
think would have been intended, but the spec is so vague that there's
no real way to prevent it.

[Historically, Maclisp had TYI ("tty input") and TYO ("tty output")
which were really both *terminal-io* and were very definitely not
anything you'd re-bind, mostly because the mechanisms for it were
terrible and mostly things would break.  Everything relied on these
really holding a console, not just a stream, and being able to do 
console-type IO to it.  People would sometimes try
and then make a mess of things by getting them inconsistent (one
of TYO bound to a stream and one to the terminal), or worse, they'd
get one bound to one part of the screen and one part of another
(which was a neat trick since the operating systems Maclisp ran
under didn't really have "windows" in the modern sense, but 
sometimes still could fake it by giving you lines n-m of the screen
as if it were a sort of window ,so you could write TALK programs
or so that you could reserve a line at the bottom as a status line
that other text didn't write over.)
There was a (status ttycons), a special form on each stream, that
could be changed by (sstatus ttycons ...) that would help you know
what to rebind TYI or TYO to if you undrestood all of this and
really wanted to rebind them to another
value... there was nothing like the CL spec forcing you to not do
things.  The maclisp manual mostly tried to excavate "current practice"
and tell people how not to get hurt in what was really a wild, wild west
kind of environment that changed all the time in the way everyone here
is always complaining that ANSI CL doesn't... every monday (or so) an
email saying what had changed and asking you to please update your
programs.  .. anyway, so TYI and TYO  still had to be a screen stream
if you didn't want  the aforementinoed big mess.
Maclisp's IO system underwent an upheaval at some point just before I
came on the scene, and it continued to support both "old i/o" and 
"new i/o" even after the upgrade. 
Old-IO really had no multiple streams, but had a way
of changing the reader with no args (or with
stream arg NIL) to read from an alternate place under control of
some variables with caret in their names (^R, ^W, etc.) that 
corresponded to the interactive interrupt character you could do 
to affect whether I/O was coming from such a stream.  (The interrupt
character would just set or unset these variables.)  When New-IO came
along, creating real "streams" you could open, pepole preferred
using those, but there was no way to talk about *standard-output*
because it was nowhere in the abstraction.  The right thing would
have been contniued use of old-io's NIL stream but (a) having it
be part of old-io was daunting, and (b) it really did have those
awful enabling variables that were a mess and no one wanted to use.
I mentino all of this not to teach anyone how old-io or new-io worked
in Maclisp, but rather to say that if you think synonym streams are
not very elegant, you have to see where people were historically
digging themselves out from, because they were a MASSIVE improvement
over prior abstractions, even if they don't offer much today.]
From: Peter Seibel
Subject: Re: Synonym streams
Date: 
Message-ID: <m33cf4gp1z.fsf@javamonkey.com>
Kent M Pitman <······@world.std.com> writes:

> Peter Seibel <·····@javamonkey.com> writes:
> 
> > I was trying to figure out what synonym streams are for and came up
> > with the following explanation. I'm hoping someone can tell me if this
> > is more or less right.
> > 
> > Suppose I want to make an encapsulated stream (say an echo stream)
> > that will track changes to a well-known stream variable such as
> > *standard-input*. I can make it like this:
> > 
> >   (make-echo-stream (make-synonym-stream '*standard-input*) my-output-stream)
> > 
> > Now if someone changes or rebinds *standard-output* while I'm still
> > using the echo stream, it will pick up on the change. Whereas if I
> > made the echo stream like:
> > 
> >   (make-echo-stream *standard-input* my-output-stream)
> > 
> > it would keep using the stream referenced by *standard-input* at the
> > time the echo stream was made, even if *standard-input* is later reset
> > or rebound. A similar situation could arise when making a broadcast
> > stream.
> > 
> > Is that it? Or is there some other use that I'm totally missing?
> 
> No.  I'm not even sure you're allowed to do this (Because of potential
> circularities).

Oh well, so much for my latest effort at creative spec interpretation
and reverse engineering. Thanks for setting me straight.

> It's so you can have interdependent "well-known variables". In
> particular, it allows *standard-input*, *standard-output*,
> *query-io*, and *debug-io* to be synonym streams to *terminal-io*
> without having to rebind anything other than *terminal-io* to change
> the "focus of attention" to another window. On the Lisp Machine,
> *terminal-io* (which was very badly named), meant what might better
> have been called *current-window*.

Ah. That makes a ton of sense. I should have figured that out.
Actually, I did go exploring a little ways down that path but in
Allegro 6.2 none of those variables reference synonym streams though
some of them seem to reference the same terminal-simple-stream. But
that fits with what you say late--that this mechanism is perhaps not
widely used any more. Thanks again.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Larry Clapp
Subject: Re: Synonym streams
Date: 
Message-ID: <slrnblvoem.2fm.larry@theclapp.ddts.net>
In article <···············@shell01.TheWorld.com>, Kent M Pitman wrote:
> The maclisp manual mostly tried to excavate "current practice" and
> tell people how not to get hurt in what was really a wild, wild west
> kind of environment that changed all the time in the way everyone
> here is always complaining that ANSI CL doesn't... every monday (or
> so) an email saying what had changed and asking you to please update
> your programs.

This one gave me a chill when fortune first spit it out:

> ===  ALL USERS PLEASE NOTE  ========================
> 
> The garbage collector now works.  In addition a new, experimental
> garbage collection algorithm has been installed.  With
> SI:%DSK-GC-QLX-BITS set to 17, (NOT the default) the old garbage
> collection algorithm remains in force; when virtual storage is
> filled, the machine cold boots itself.  With SI:%DSK-GC-QLX-BITS set
> to 23, the new garbage collector is enabled.  Unlike most garbage
> collectors, the new gc starts its mark phase from the mind of the
> user, rather than from the obarray.  This allows the garbage
> collection of significantly more Qs.  As the garbage collector runs,
> it may ask you something like "Do you remember what SI:RDTBL-TRANS
> does?", and if you can't give a reasonable answer in thirty seconds,
> the symbol becomes a candidate for GCing.  The variable
> SI:%GC-QLX-LUSER-TM governs how long the GC waits before timing out
> the user.

Certainly this one's tongue-in-cheek, but did you ever get similarly
broad changes?  "QUOTE now works."  "LIST is broken."  "We
accidentally bound DEFUN to REBOOT; sorry."

-- 
Larry Clapp / ·····@theclapp.org
Use Lisp from Vim: VILisp: http://vim.sourceforge.net/script.php?script_id=221
From: Kent M Pitman
Subject: Re: Synonym streams
Date: 
Message-ID: <sfw7k4fm5on.fsf@shell01.TheWorld.com>
Larry Clapp <·····@theclapp.org> writes:

[The story you quoted was a LispM story, not a Maclisp story, btw.
 Not that it wasn't just as fun there.  But Maclisp had no packages,
 and it had only a mark/sweep GC since it had only 1.25MB of storage 
 (well, to be precise, 256KW of 36-bit words (sometimes seen as 
 4 9-bit bytes, though it was not a byte-coded machine generally; 
 as strings you got 5 7-bit bytes with 1 bit left over to use for
 "fun" purposes)) with usually 3-6 times that much real memory (so
 the running job and even many stopped jobs were fully paged in),
 and there was no performance issue with mark/sweep as there were in
 later machines that had more virtual memory than real memory...

 Nevertheless, I'll interpret your question as one about Maclisp,
 circa 1979-1980, just before CL, since was what I was talking about.]

> Certainly this one's tongue-in-cheek, but did you ever get similarly
> broad changes?  "QUOTE now works."  "LIST is broken."  "We
> accidentally bound DEFUN to REBOOT; sorry."

Sure.  Especially with new stuff.  My favorite was when we installed
backquote for the first time.  There were several competing versions
and the first one installed always did a full copy.  I excitedly changed
a ton of my calls to CONS, LIST, etc. into backquote forms.  Then a couple
weeks later, there was an announcement saying it was "too expensive" for
it to be copying all the time, and it would only copy structure it had to.
Great for folks just working from templates and not planning to side-effect,
but my calls to CONS, LIST, etc. were there for a reason--to get fresh
structure.  It was a pain to go back and change things.  But at least I
could assume that basically all calls to backquote were suspect, since
the macro had not existed for a long time...

Plus people were always finding bugs and sometimes when JonL White couldn't
fix them, he'd just put in a breakpoint acknowledging the problem and who
had reported it, so you'd be running along and see 
 ;BKPT PSZ LOSES
or some such thing, indicating that there was work remaining to do in
coding something you'd thought was fully working...

It was fun (when it was) mostly because of two things: (1) we didn't
distribute the code, we mostly used it locally and all our users
dialed in, so when we needed a fix, installing it "worldwide" was not
that hard and (2) our livelihood did not depend upon its correctness.
we weren't commercial, we were sponsored research staff.

But after a while I got tired of being told my code had changed meaning
and that it was my responsibility to update it.  My code meant what I 
meant it to mean, even when broken by changes, and that little joke about
how it had changed meaning and to please "update my program" wore thin
after a while...

It was frustrating enough that I cringe just a little when people
romanticize overly about how great it was when things used to change
faster.  ANSI CL may not have changed in a long time, but that was its
whole purpose in life.  Many people, including (D)ARPA -- one of our
big sponsors, had told us that Maclisp was too unstable a platform to
build long-term products upon.  And they were right.
From: Erann Gat
Subject: Re: Synonym streams
Date: 
Message-ID: <gat-1109031352290001@k-137-79-50-101.jpl.nasa.gov>
In article <···············@shell01.TheWorld.com>, Kent M Pitman
<······@world.std.com> wrote:

> It was frustrating enough that I cringe just a little when people
> romanticize overly about how great it was when things used to change
> faster.  ANSI CL may not have changed in a long time, but that was its
> whole purpose in life.  Many people, including (D)ARPA -- one of our
> big sponsors, had told us that Maclisp was too unstable a platform to
> build long-term products upon.  And they were right.

At the risk of opening myself up to a beating when the bruises from the
last one haven't completely healed up yet I would like to say that while I
am sympathetic to Kent's point, I also believe that the opposite extreme -
no change at all - is also harmful.  Change brings problems, no doubt. 
But the solution IMO is not to eliminate change, but to manage it better.

E.
From: John
Subject: Client/Server question
Date: 
Message-ID: <oprvd37iiefhfgdd@news.chello.no>
I have recently developed a text only version of Othello.
(Basically a case study of applying a alpha-Beta pruning search algorithm.)
Now I would like to extend this program to be an othello server.
The client interface will be a Java applet. Communication I suspect will 
use XML-RPC 1.0 .
Does anyone have experience with this?
What tools should I use?
I use Corman Lisp.

John
From: Steven M. Haflich
Subject: Re: Synonym streams
Date: 
Message-ID: <1d89b.2889$Ql4.605@newssvr29.news.prodigy.com>
Peter Seibel wrote:
> I was trying to figure out what synonym streams are for and came up
> with the following explanation. I'm hoping someone can tell me if this
> is more or less right.
> ...
> Is that it? Or is there some other use that I'm totally missing?

Since I know you are writing about Common Lisp, how about this prose:

The idea of the synonym-stream was an attempt to provide a layer of
stream indirection and a mechanism capable of rapid lambda binding
of stream capability depending on, well, lambda binding.  It was and
remains a horrible `kludge' (q.v.) because it make streams, if not
fully second-class objects, something less than first class.  The
important aspects of the identity of a synonym stream are not
discernable by eq, and the important aspects of its behavior are not
discernable by class-of or type-of, and do not even remain constant
within a single function body.

Synonym streams should be deprecated, not because they might not be
useful in overly-clever code, but because their existence stands in
the way of other, more-useful and more-extensible stream paradigms
that are more compatible with the proven coding abstractions in the
language.
From: Peter Seibel
Subject: Re: Synonym streams
Date: 
Message-ID: <m3ekyibpcz.fsf@javamonkey.com>
"Steven M. Haflich" <·················@alum.mit.edu> writes:

> Peter Seibel wrote:
> > I was trying to figure out what synonym streams are for and came up
> > with the following explanation. I'm hoping someone can tell me if this
> > is more or less right.
> > ...
> > Is that it? Or is there some other use that I'm totally missing?
> 
> Since I know you are writing about Common Lisp, how about this prose:
> 
> The idea of the synonym-stream was an attempt to provide a layer of
> stream indirection and a mechanism capable of rapid lambda binding
> of stream capability depending on, well, lambda binding.  It was and
> remains a horrible `kludge' (q.v.) because it make streams, if not
> fully second-class objects, something less than first class.  The
> important aspects of the identity of a synonym stream are not
> discernable by eq, and the important aspects of its behavior are not
> discernable by class-of or type-of, and do not even remain constant
> within a single function body.
> 
> Synonym streams should be deprecated, not because they might not be
> useful in overly-clever code, but because their existence stands in
> the way of other, more-useful and more-extensible stream paradigms
> that are more compatible with the proven coding abstractions in the
> language.

Thanks. With the perspective Mr. Pitman and you have given me on this
issue, I suspect I'll probably just not bring it up unless I happen to
have an appendix that says *something* about every class in the
COMMON-LISP package.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Paolo Amoroso
Subject: Re: Synonym streams
Date: 
Message-ID: <87ad96utbx.fsf@plato.moon.paoloamoroso.it>
Steven M. Haflich writes:

> Synonym streams should be deprecated, not because they might not be
> useful in overly-clever code, but because their existence stands in
> the way of other, more-useful and more-extensible stream paradigms
> that are more compatible with the proven coding abstractions in the
> language.

Which paradigms?


Paolo
-- 
Paolo Amoroso <·······@mclink.it>
From: Steven M. Haflich
Subject: Re: Synonym streams
Date: 
Message-ID: <vEY9b.153$5h5.151@newssvr29.news.prodigy.com>
Paolo Amoroso wrote:
> Steven M. Haflich writes:
> 
>>Synonym streams should be deprecated, not because they might not be
>>useful in overly-clever code, but because their existence stands in
>>the way of other, more-useful and more-extensible stream paradigms
>>that are more compatible with the proven coding abstractions in the
>>language.
> 
> Which paradigms?

Gray Streams, Simple Streams, any number of streamish window systems,
or anything else that might involve gf discrimination on stream type.

Synonym streams present two practical problems.  First, the operational
class of the stream is not apparent via the actual class of the stream.
Second, any function that is part of some higher layer implemented on
streams (e.g. draw-rectangle) must be extended to work with a
synonym-stream.  Plausible safety nets to do this automatically such as
no-applicable-method typically have unacceptable overhead or
indirectness.

I forget whether typical CLIM operators would work on synonym streams,
or whether anyone ever considered the issue...
From: james anderson
Subject: Re: Synonym streams
Date: 
Message-ID: <3F686627.3F51B4DC@setf.de>
is this objection specific to synonym streams? is not make-synonym-stream
typical of the standard cl stream operations in that it is reluctant to
support specialization? in which sense synonym-stream is not in itself an obstacle.

"Steven M. Haflich" wrote:
> 
> Paolo Amoroso wrote:
> > Steven M. Haflich writes:
> >
> >>Synonym streams should be deprecated[. ]their existence stands in
> >>the way of other, more-useful and more-extensible stream paradigms
> >> ...
> >
> > Which paradigms?
> 
> Gray Streams, Simple Streams, any number of streamish window systems,
> or anything else that might involve gf discrimination on stream type.

are there arguments against specializing the synonym stream for specific
delegation tasks?

are there arguments against relying on special variables, as opposed to slot
values, for delegation attributes? wrt the encapsulation ==> robust and
predictable issue, there's not much difference between an uninterned symbol
and a slot value.

> 
> Synonym streams present two practical problems.  First, the operational
> class of the stream is not apparent via the actual class of the stream.

iff one uses exactly the synonym-stream class.

> Second, any function that is part of some higher layer implemented on
> streams (e.g. draw-rectangle) must be extended to work with a
> synonym-stream.  Plausible safety nets to do this automatically such as
> no-applicable-method typically have unacceptable overhead or
> indirectness.

under the same assumptions as above.

> 
> I forget whether typical CLIM operators would work on synonym streams,
> or whether anyone ever considered the issue...
...
From: Kent M Pitman
Subject: Re: Synonym streams
Date: 
Message-ID: <sfwfzivf7zl.fsf@shell01.TheWorld.com>
"Steven M. Haflich" <·················@alum.mit.edu> writes:

> Paolo Amoroso wrote:
> > Steven M. Haflich writes:
> >
> >>Synonym streams should be deprecated, not because they might not be
> >>useful in overly-clever code, but because their existence stands in
> >>the way of other, more-useful and more-extensible stream paradigms
> >>that are more compatible with the proven coding abstractions in the
> >>language.
> > Which paradigms?
> 
> Gray Streams, Simple Streams, any number of streamish window systems,
> or anything else that might involve gf discrimination on stream type.

These aren't really paradigms.  These are implementation strategies.
Synonym streams could be implemented using either of these, though it
would be opaque to the user.  Moreover, the use of these does not impose
any discipline that would cause really anything at all to be dynamically
nor statically inferrable from having used one of these so-called paradigms
other than "a Turing machine is invoked here".
 
> Synonym streams present two practical problems.  First, the operational
> class of the stream is not apparent via the actual class of the stream.

I'm not sure I get your point here.

> Second, any function that is part of some higher layer implemented on
> streams (e.g. draw-rectangle) must be extended to work with a
> synonym-stream.

"might have to be extended".  It seems to me that synonym streams _could_
be a subclass of a gray stream or a simple stream.

> Plausible safety nets to do this automatically such as
> no-applicable-method typically have unacceptable overhead or
> indirectness.
> 
> I forget whether typical CLIM operators would work on synonym streams,
> or whether anyone ever considered the issue...

I'm sure it was originally considered when synonym streams were invented
since the Lisp Machine uses both synonym streams and "new flavors" 
(essentially a syntactic variant of CLOS) pretty extensively in the
implementation of Dynamic Windows (conceptually very similar to CLIM).

CL, as usual, didn't pick up the whole of what the LispM had to offer,
and so suffers from its desire to "be conservative".
From: Steven M. Haflich
Subject: Re: Synonym streams
Date: 
Message-ID: <2Pscb.626$qj2.134624621@newssvr13.news.prodigy.com>
Kent M Pitman wrote:

>>Gray Streams, Simple Streams, any number of streamish window systems,
>>or anything else that might involve gf discrimination on stream type.
> 
> These aren't really paradigms.  These are implementation strategies.

Sorry for being away from this thread so long, but I really cannot agree
with the above statement.  All these things are not implementation
strategies; they are APIs avaialble to client code, even extensible APIs.

If one's focus considering streams is the implementation of the parochial
ANS stream capabilities, everything is merely an implementation strategy
and the details don't matter at all to the user programmer.  But the ANS
avoids most of the obvious real-world real-computing-universe requirements
on streams.  In the age of MACLISP, everything interesting passed through
a tty.  Today, nothing interesting interesting passes through a tty.

>>Synonym streams present two practical problems.  First, the operational
>>class of the stream is not apparent via the actual class of the stream.
> 
> 
> I'm not sure I get your point here.

The point is that the implementor of any module that defines non-CL-package
operators must arrange for these operators to discriminate and delegate for
synonym etc. streams. or else document that they won't work.  The former is
a tedious and costly load on otherwise sane API implementations.

> "might have to be extended".  It seems to me that synonym streams _could_
> be a subclass of a gray stream or a simple stream.

But a synonym strteam would not automatically be a subclass of a
terminal-stream-with-double-spacing or a clim:presenting-stream unless
the implementors of these protocols make it so.

> I'm sure it was originally considered when synonym streams were invented
> since the Lisp Machine uses both synonym streams and "new flavors" 
> (essentially a syntactic variant of CLOS) pretty extensively in the
> implementation of Dynamic Windows (conceptually very similar to CLIM).

There was a time, before they went bankrupt, that Symbolics had lotsa money
and lotsa programmers, and could devise that synonym streams would delegate
transparently for all the defined operators.  But if I'm a little developer
trying to write a window system, say, that back ends on the XUL rendering
language of Mozilla, I might be annoyed that I have to write methods for
every API function I create for each kind of delegating ANSI stream, or else
document that they won't work.

I repeat my opinion that the ANS delegating streams (synonym, contatenating,
broadcast) are a failed experiment incompatible with modern oo programming
and which remain an unfortunate weight upon the language.  I think they
shold be deprecated.
From: james anderson
Subject: Re: Synonym streams
Date: 
Message-ID: <3F732D0E.DDB83976@setf.de>
"Steven M. Haflich" wrote:
> 
> Kent M Pitman wrote:
> 
> >>Gray Streams, Simple Streams, any number of streamish window systems,
> >>or anything else that might involve gf discrimination on stream type.
> >
> > These aren't really paradigms.  These are implementation strategies.
> 
> Sorry for being away from this thread so long,

thank you for returning to it. i did not follow your conclusions the first
time and i welcome the chance to understand the issue.

>    but I really cannot agree
> with the above statement.  All these things are not implementation
> strategies; they are APIs avaialble to client code, even extensible APIs.
> 
> ...
> >>Synonym streams present two practical problems.  First, the operational
> >>class of the stream is not apparent via the actual class of the stream.
> >
> >
> > I'm not sure I get your point here.
> 
> The point is that the implementor of any module that defines non-CL-package
> operators must arrange for these operators to discriminate and delegate for
> synonym etc. streams. or else document that they won't work.  The former is
> a tedious and costly load on otherwise sane API implementations.
> 
> > "might have to be extended".  It seems to me that synonym streams _could_
> > be a subclass of a gray stream or a simple stream.
> 
> But a synonym strteam would not automatically be a subclass of a
> terminal-stream-with-double-spacing or a clim:presenting-stream unless
> the implementors of these protocols make it so.
> 

but no specialization relation is autmatic. if one neglects issues of
finalization and encapsulation which would preclude a subclass, why can not a
synonym stream not treat these as protocol classes to be specialized, or,
alternatively, assuming that the api is intended to be extended, why can't it
specialize some abstract class, for which the abstract functions in the
interface are then written? yes, the implementors of the protocol cannot make
it so, but they can allow the users to.

as i noted in my earlier query, delegation in lisp depends on a binding for
the referent. synonym streams effect this with a special variable.
object-based delegation can support it with a slot binding. it would be
possible to do it with closed-over variables, but i'm not acquainted with
implementation which use that technique. given this requirement, that is, that
the referent is bound somewhere, the only difference i can discern between the
special-binding-based delegation and the slot-based delegation is, well, the
nature of the binding. 

> > I'm sure it was originally considered when synonym streams were invented
> > since the Lisp Machine uses both synonym streams and "new flavors"
> > (essentially a syntactic variant of CLOS) pretty extensively in the
> > implementation of Dynamic Windows (conceptually very similar to CLIM).
> 
> There was a time, before they went bankrupt, that Symbolics had lotsa money
> and lotsa programmers, and could devise that synonym streams would delegate
> transparently for all the defined operators.  But if I'm a little developer
> trying to write a window system, say, that back ends on the XUL rendering
> language of Mozilla, I might be annoyed that I have to write methods for
> every API function I create for each kind of delegating ANSI stream, or else
> document that they won't work.

this is where i don't understand why that is a problem. that
make-synonym-stream does not include a means to specify the class of the
stream is a problem. which problem is common to all elements of the standard
stream interface, not particular to synonym streams.

> 
> I repeat my opinion that the ANS delegating streams (synonym, contatenating,
> broadcast) are a failed experiment incompatible with modern oo programming
> and which remain an unfortunate weight upon the language.  I think they
> shold be deprecated.

what is the argument against specializing them. if it were possible to specify
the concrete class, to the standard creation functions, what problem would remain?

if i take a tiny example. let's say i would like to generate svg. i have these
data objects which need to be serialized. in order to support delegation,
there has to be some provision for it in the api protocol.

in this case, the base generic function and default definitions are all
generated via
macros. like

(defProjectionOp line (l1 l2 &optional properties))
(defProjectionOp line*2 (x1 y1 x2 y2 &optional properties))
(defProjectionOp line*3 (x1 y1 z1 x2 y2 z2 &optional properties))


in order to provide for delegation - or whatever sort - i would think that
there has to be a definition somewhere which looks something like

(defmethod op ((instance delegate) &rest args)
  (apply #'op (delegate-referent instance) args))

are there alternatives? given that, the generation function for delegatable
operations needs an additional clause. some thing like

(push `(:method ((delegate delegate-context) ,@lambda-list)
                (,do-call #',operator-name
                     (delegate-referent delegate) ,@arguments))
      methods)

which is not that complex and provides for any class which specializes
delegate-context and implements delegate-referent. it is not material whether
the class specializes synonym-stream or some other abstract class. assuming
that the projection operations above are so defined, the alternative
delegation forms do not look very different. 

(defClass svg-presenter () ()
  (:documentation
   "the protocol class which specifies the presence of the svg presentation methods"))

(defClass svg-context (aspect-context)
  ((stream
    :initform nil :initarg :stream
    :reader context-stream
    :documentation "bound to an output stream for svg-envoded output."))
  (:documentation
   "a context which implements graphics operations as svg serialization."))


(defclass svg-wrapper-context (delegate-context svg-presenter stream)
  ((context :reader effective-context :initarg :context))
  (:documentation
   "a wrapper which implements svg presentation methods through delegation to
a context which implements graphics operations."))

(defParameter *svg-output* nil)

(defClass svg-synonym-context (delegate-context svg-presenter synonym-stream)
  ()
  (:default-initargs :symbol '*svg-output*)
  (:documentation
   "a synonym context which delegates through a spacial variable binding
rather than a slot binding."))

(defMethod effective-context ((synonym-context svg-synonym-context))
  (symbol-value (synonym-stream-symbol synonym-context)))


[ ignoring the stream operations which the wrapper needs to act as a stream ]


the concrete serialization looks something like this

(defun svg-line*3 (x1 y1 z1 x2 y2 z2 &optional aspects)
  "serialize a line given the 3d location"
  #+og.assert-types (progn (assert-types (x1 y1 z1 x2 y2 z2) number)
                           (assert-type aspects sequence))
  (flet ((emit-line ()
           (xml ({svg}line ({}x1  x1) ({}y1  y1)
                           ({}x1  x2) ({}y1  y2)
                           ({}stroke *svg-stroke-color*)))))
    (declare (dynamic-extent #'emit-line))
    (call-with-aspects #'emit-line aspects)))

(defMethod .og.::line*3 ((context svg-context) x1 y1 z1 x2 y2 z2 &optional aspects)
  "draw a line given two extreme 3d vertices"
  (svg-line*3 x1 y1 z1 x2 y2 z2 aspects))

(defMethod .og.::line*2 ((context svg-context) x1 y1 x2 y2 &optional aspects)
  "draw a line given two extreme 2d vertices"
  (svg-line*3 x1 y1 0.0d0 x2 y2 0.0d0 aspects))

(defMethod .og.::line ((context svg-context) l1 l2 &optional aspects)
  "draw a line given the end locations (2-d or 3-d) in object/world coordinates"
  ;; ignoring that svg is only 2d
  (with-location-coordinates (((x1 y1 z1) l1) ((x2 y2 l2) l2))
    (svg-line*3 x1 y1 z1 x2 y2 l2 aspects)))


the projection interface looks something like this

(defgeneric present (instance context)
  (:method ((instance line) (context svg-presenter))
           (line context (location instance) (end instance)
                       (presentation-properties instance context))))

and the usage looks something like this

(defParameter *svgc* (make-instance 'svg-context :stream *trace-output*))
;(context-stream *svgc*)

(defParameter *svg-wc* (make-instance 'svg-wrapper-context :context *svgc*))
;(effective-context *svg-wc*)
;(context-stream (effective-context *svg-wc*))

(defParameter *svg-sc* (make-instance 'svg-synonym-context :symbol '*svg-output*))

(setq *svg-output* *svg-wc*)


(with-projection-context (*svgc*)
  (let ((line (make-instance 'line
                :location ·@(|3| 0.0 0.0 0.0) 
                :end ·@(|3| 1.0 1.0 1.0))))
    (format *svg-wc* "~%~%<!-- presenting to a svg-wrapper-context: -->~%")
    (present line *svg-wc*)
    (format *svg-sc* "~%~%<!-- presenting to a svg-synonym-context: -->~%")
    (present line *svg-sc*)))


wherein i discern no difference between synonym classes and wrapper classes.
do the problems surrounding a terminal-stream-with-double-spacing a
clim:presenting-stream has a shape which is so different from this?

...