From: Rolf Breuning
Subject: block closures
Date: 
Message-ID: <3342C8FF.2395@post.rwth-aachen.de>
From what I have read, Smalltalk inherited his blocks from LISP. So, if
somebody is out there with a knowledge of both Smalltalk and LISP:
- Is there an equivalent to a Smalltalk expression like:
  (a < 0) ifTrue: [a := 0].
- If yes, what would this LISP equivalent look like ?
- What are the differences in the semantics ?

Thanks in advance


**********************************************************************
* Rolf Breuning                             ····@eecs.rwth-aachen.de *
* Bahnhofstr.7                                     using OS/2 Warp 4 *
* D-52064 Aachen                             - standard disclaimer - *
**********************************************************************

From: Ken Tilton
Subject: Re: block closures
Date: 
Message-ID: <3342F148.4A5@bway.net>
Rolf Breuning wrote:
> 
> From what I have read, Smalltalk inherited his blocks from LISP. So, if
> somebody is out there with a knowledge of both Smalltalk and LISP:
> - Is there an equivalent to a Smalltalk expression like:

>   (a < 0) ifTrue: [a := 0].

Yes and no. The above code is a contortion ST is forced into by its
commitment to 'all-objects-all-the-time'. Thru CLOS we could in Lisp do
the same (see below), but would normally write:

   (when (< a 0) (setf a 0))

No need for a closure (ST block). You need the block in ST so you can
send it along for execution to the boolean (a<0) with the message
#iftrue:.

> - If yes, what would this LISP equivalent look like ?

God my Lisp has gotten rusty after five months of VAX Basic! :( Anyway,
roughly:

(defclass boolean ()
  ((value :accessor value :initarg value))))

(defmethod ifTrue ((aBool boolean) justDoIt)
   (when (value aBool) (funcall justDoIt)))

...then...

(ifTrue (make-instance 'boolean :value (< a 0)) #'(lambda() (setf a 0)))

Pretty silly, but again, ST uses a block to achieve the classic "if"
statement out of religious fervor (IMHO), as in its all-objects policy. 

I think many a good idea has failed becuase the inventor got excited and
said, Hey, let's use this for /everything/.

Let the flames begin. <G>

ken
From: Mike Anderson
Subject: Re: block closures
Date: 
Message-ID: <334371D2.2F8@ix.netcom.com>
Ken Tilton wrote:

> Pretty silly, but again, ST uses a block to achieve the classic "if"
> statement out of religious fervor (IMHO), as in its all-objects policy.
> 
> I think many a good idea has failed becuase the inventor got excited and
> said, Hey, let's use this for /everything/.

What do you think is the downside of an 'all-objects policy'?

....Mike
From: Jan Steinman
Subject: Re: block closures
Date: 
Message-ID: <Jan-ya02408000R0304972044040001@news.structured.net>
In article <············@ix.netcom.com>, ····@ix.netcom.com wrote:

> > Pretty silly, but again, ST uses a block to achieve the classic "if"
> > statement out of religious fervor (IMHO), as in its all-objects policy.
> > 
> > I think many a good idea has failed becuase the inventor got excited and
> > said, Hey, let's use this for /everything/.
> 
> What do you think is the downside of an 'all-objects policy'?

It allowed C++ and Java to proliferate by people who can't handle the fact
that everything IS an object.

(Oh yes, I forgot the little ----> :-)

: Jan Steinman <··········@Bytesmiths.com>
: Bytesmiths <http://www.bytesmiths.com>
: Java, the elegant simplicity of C++ and the blazing speed of Smalltalk.
From: Vassili Bykov
Subject: Re: block closures
Date: 
Message-ID: <01bc42a2$b367f100$752d54c7@vbykov.hip.cam.org>
Ken Tilton <····@bway.net> wrote in article <············@bway.net>...
> > - Is there an equivalent to a Smalltalk expression like:
> >   (a < 0) ifTrue: [a := 0].
> 
> Yes and no. The above code is a contortion ST is forced into by its
> commitment to 'all-objects-all-the-time'. 

Many people think this is elegance, not a contortion.  Besides, none of the
real Smalltalk compilers actually treats this as a closure passed to a
boolean.

> God my Lisp has gotten rusty after five months of VAX Basic! :( Anyway,
> roughly:
> 
> (defclass boolean ()
>   ((value :accessor value :initarg value))))
> 
> (defmethod ifTrue ((aBool boolean) justDoIt)
>    (when (value aBool) (funcall justDoIt)))

Now this is a contortion indeed!  If you do want to speak CL, first, you
cannot have a class BOOLEAN in CL because there is a type BOOLEAN already
defined.  Second, there is no need to make instances of  BOOLEAN when you
can simply specialize on NIL and everything else.  Third, you can use two
separate methods for that which is much nicer.  Incidentally, this would be
very close to what Smalltalk is doing (again, in theory--in practice
ifTrue: is rarely actually compiled as a message send):

(defmethod if-true ((aBool (eql nil)) fun)
  nil)

(defmethod if-true (aBool fun)
  (funcall fun))

Not to say you can use a macro to avoid cluttering your code with
#'(lambda)'s:

(defmacro ifTrue (cond &body forms)
  `(if-true ,cond #'(lambda () ,@forms)))

> ...then...
> (ifTrue (make-instance 'boolean :value (< a 0)) #'(lambda() (setf a 0)))

(ifTrue (< a 0) (setf a 0))

> Pretty silly, but again, ST uses a block to achieve the classic "if"
> statement out of religious fervor (IMHO), as in its all-objects policy. 
> I think many a good idea has failed becuase the inventor got excited and
> said, Hey, let's use this for /everything/.

Of course, using objects for everything is not a good idea.  It is a
terrific idea.  Incidentally, it was Alan Kay who said, "terrific ideas
tend to hide behind good ones".  Would you elaborate in what respect
exactly did Smalltalk "fail" with using blocks and messages for control
syntax?

--Vassili
From: Bob Jarvis
Subject: Re: block closures
Date: 
Message-ID: <01bc438b$8bd68c20$2f74b993@jarvisb>
Ken Tilton <····@bway.net> wrote in article <············@bway.net>...
> Rolf Breuning wrote:
> > 
> > From what I have read, Smalltalk inherited his blocks from LISP. So, if
> > somebody is out there with a knowledge of both Smalltalk and LISP:
> > - Is there an equivalent to a Smalltalk expression like:
> 
> >   (a < 0) ifTrue: [a := 0].
> 
> Yes and no. The above code is a contortion ST is forced into by its
> commitment to 'all-objects-all-the-time'. Thru CLOS we could in Lisp do
> the same (see below), but would normally write:
> 
>    (when (< a 0) (setf a 0))
> 
> <snipped for brevity>
> 
> Pretty silly, but again, ST uses a block to achieve the classic "if"
> statement out of religious fervor (IMHO), as in its all-objects policy. 

IMHO using objects for everything is an excellent idea.  It promotes a very orthogonal
view of programming, and provides more benefits than problems.  One of the areas
which some people might view as a problem is that it changes some of the "traditional"
programming structures, e.g. if-then-else becomes condition-ifTrue-ifFalse.  I know this
drove me a little nuts, being from the Algol-Fortran-C school, until I finally "got it".
Sadly, it took me a long time to do this because I allowed myself to become "stuck in
a rut" (in my case the C/C++ rut/trench), and it wasn't until I realized that I had a
huge blind spot (i.e. I only knew one language which might be called "object oriented")
that I finally applied myself to learning Smalltalk.

> I think many a good idea has failed becuase the inventor got excited and
> said, Hey, let's use this for /everything/.

Well, I view this from another perspective.  Smalltalk has the fewest "exceptions" of any
language I've ever seen.  When you're programming durn near everything is a message
send.  The only exceptions I can think of (quickly) are

	variable assignment	:=
	method answer		^
	method variables	| aVariable |
	blocks			[ ... ]
	block variables		[ :aBlockVar | ... ]
	statement end		.
	comments		" ... "

I've probably missed some things, but that's pretty much it.  There's darn little in
Smalltalk that's defined by fiat in the language spec, so there's not much "language" to
learn.  (Contrast this with, as Jan Steinman so eloquently (and tongue-in-cheekedly) puts
it, the "elegant simplicity" of C++, where everything is a language feature, and every feature
adds its own little twist to the language (with most everything being Yet Another Use Of
The Term 'virtual' :-)).  (To defend myself - I'm a relatively longtime (9 year) veteran of C++
so I figger I'm allowed to take a few potshots in my own back yard, so to speak).  Smalltalk
is, in my limited experience, the best example I've seen of building a complete system from
a few well thought out basic concepts.  

> Let the flames begin. <G>

No flames intended.  Everyone's entitled to an opinion.
-- 
Bob Jarvis
Mail addresses hacked to foil automailers!
Remove '_spamless' from reply address
From: Barry Margolin
Subject: Re: block closures
Date: 
Message-ID: <5husi1$4qg@tools.bbnplanet.com>
In article <·············@post.rwth-aachen.de>,
Rolf Breuning  <····@eecs.rwth-aachen.de> wrote:
>From what I have read, Smalltalk inherited his blocks from LISP. So, if
>somebody is out there with a knowledge of both Smalltalk and LISP:
>- Is there an equivalent to a Smalltalk expression like:
>  (a < 0) ifTrue: [a := 0].
>- If yes, what would this LISP equivalent look like ?

I'm not really an expert on Smalltalk, but that expression looks pretty
obvious to me and I think the Lisp equivalent is:

(if (< a 0) (setq a 0))
-- 
Barry Margolin
BBN Corporation, Cambridge, MA
······@bbnplanet.com
(BBN customers, call (800) 632-7638 option 1 for support)
From: Bill Gooch
Subject: Re: block closures
Date: 
Message-ID: <334311B4.483D@flash.net>
Barry Margolin wrote:
> 
> In article <·············@post.rwth-aachen.de>,
> Rolf Breuning  <····@eecs.rwth-aachen.de> wrote:
> >From what I have read, Smalltalk inherited his blocks from LISP. So, if
> >somebody is out there with a knowledge of both Smalltalk and LISP:
> >- Is there an equivalent to a Smalltalk expression like:
> >  (a < 0) ifTrue: [a := 0].
> >- If yes, what would this LISP equivalent look like ?
> 
> I'm not really an expert on Smalltalk, but that expression looks pretty
> obvious to me and I think the Lisp equivalent is:
> 
> (if (< a 0) (setq a 0))

Yes and no.  In practice, it is equivalent. However, the 
block following the ifTrue: is (in principle) a closure 
that gets passed as an argument to the ifTrue: method, 
which is a difference.  Smalltalk compilers often inline
the ifTrue:, though, so even that difference means little. 

~~~~~~~~~~~~~~~~~~~~~~
Bill Gooch			······@flash.net
Texas liaison for the International Programmers Guild
For information on IPG, see http://www.ipgnet.com/ipghome.htm
From: Stefan Matthias Aust
Subject: Re: block closures
Date: 
Message-ID: <334347a9.1971102@news.cls.de>
>From what I have read, Smalltalk inherited his blocks from LISP. So, if
>somebody is out there with a knowledge of both Smalltalk and LISP:
>- Is there an equivalent to a Smalltalk expression like:
>  (a < 0) ifTrue: [a := 0].
>- If yes, what would this LISP equivalent look like ?

(if (< a 0) (setq a 0))

However, neither Smalltalk nor Lisp use real block closures here. Smalltalk
optimizes the ifTrue: method inside the compiler (but has still the same
semantic). Lisp uses a special form "if" which prevents the evaluation of
the "then" argument, if the condition isn't true. A better equivalent would
be (if I remember the definition of CLOS methods right)

(defmethod ifTrue ((condition nil) block)
    (block))

(defmethod ifTrue ((condition T) block)
    nil)

(ifTrue (< a 0) (lambda () (setq a 0))

This has exactly the same semantic.

>- What are the differences in the semantics ?

Lisp's if expression is a special form and doesn't use method sending.
Otherwise, Lisp's lambda expressions (using only lexically bound variables)
have the same semantic as Smalltalk block closures as provided by most
Smalltalk implementations.

bye
From: Bill Gooch
Subject: Re: block closures
Date: 
Message-ID: <33455A62.4C30@iconcomp.com>
Stefan Matthias Aust wrote:
> ....
> Lisp's if expression is a special form and doesn't use method sending.
> Otherwise, Lisp's lambda expressions (using only lexically bound variables)
> have the same semantic as Smalltalk block closures as provided by most
> Smalltalk implementations.

Not exactly.  In particular, an explicit return from a
Smalltalk block is defined as a return from the defining
method of the block, whereas a (return) in a Common Lisp 
closure is a return from the closure itself.  (Common Lisp 
also provides a mechanism to specify a return from specific
enclosing contexts by name, which Smalltalk lacks.)  This 
difference has nothing much to do with the ifTrue:/(if ...) 
example, but it does reflect a limitation of Smalltalk in 
dealing with a block which may be invoked outside of the 
context of the method in which it is defined.  

In this sense, Smalltalk blocks do not behave as first-class 
objects.

-- 
William D. Gooch             ····@iconcomp.com
Icon Computing               http://www.iconcomp.com     
Texas liaison for the International Programmers Guild 
For IPG info, see http://www.ipgnet.com/ipghome.htm
From: Eliot & Linda
Subject: Re: block closures
Date: 
Message-ID: <33456637.4088@pacbell.net>
Bill Gooch wrote:
> 
> Stefan Matthias Aust wrote:
> > ....
> > Lisp's if expression is a special form and doesn't use method sending.
> > Otherwise, Lisp's lambda expressions (using only lexically bound variables)
> > have the same semantic as Smalltalk block closures as provided by most
> > Smalltalk implementations.
> 
> Not exactly.  In particular, an explicit return from a
> Smalltalk block is defined as a return from the defining
> method of the block, whereas a (return) in a Common Lisp
> closure is a return from the closure itself.  (Common Lisp
> also provides a mechanism to specify a return from specific
> enclosing contexts by name, which Smalltalk lacks.)  This
> difference has nothing much to do with the ifTrue:/(if ...)
> example, but it does reflect a limitation of Smalltalk in
> dealing with a block which may be invoked outside of the
> context of the method in which it is defined.
> 
> In this sense, Smalltalk blocks do not behave as first-class
> objects.

Nonsense! ( :) ) Smalltalk blocks _can_ return from a block
as well as return from a block's enclosing method.  How does
the following work otherwise:

	(1 to: 10) select: [:n| n even]

i.e. [:n| n even] is returning to the select method after each
activation.

Smalltalk provides no default syntax for a block to return to
its enclosing method.  But there's lots of mechanism around to
do it.

e.g.

someMethod: someCollection
    | exitSignal result |
    exitSignal := Signal new.
    . . .
    result := exitSignal
                handle: [:ex| ex returnWith: #negative]
                do: [someCollection select:
                        [:elem|
                        elem isInfinite ifTrue: [^#infinte].
                        elem negative ifTrue: [exitSignal raise].
                        elem even].
    . . .

which returns #infinite to the sender of someMethod: when an
infinite element is encountered before a negative one in someCollection,
and assigns #negative to result when a negative value is encountered
before an infinite one in someCollecion, and otherwise assigns the
even elements in someCollection to result.

There are also numerous ways of writing the following style:

BlockClosure methods for evaluating
valueWithExit
  ^self value: [:exitValue| ^exitValue]

someMethod: someCollection
    | exitSignal result |
    exitSignal := Signal new.
    . . .
    result := [:exit| someCollection select:
                        [:elem|
                        elem isInfinite ifTrue: [^#infinte].
                        elem negative ifTrue: [exit value: #negative].
                        elem even]] valueWithExit.
    . . .

which has the same effect as the above.

And in what sense do these behaviours imply that Smalltalk closures
are not first class objects?  First-class refers to the ability to
a) pass closures around as freely as any other objects
b) the ability to define methods on closures as any other objects
Smalltalk provides both of these.

Which begs the question are closures in CLOS objects?  I don't know,
but CLOS, being an impure language (unlike Smalltalk and Dylan), may
not make closures objects.  If so, it is CLOS which lacks first-class
closures and not Smalltalk.
_______________,,,^..^,,,_______________
Eliot Miranda, ObjectEngine technical lead, ParcPlace-Digitalk
From: Eliot & Linda
Subject: Re: block closures
Date: 
Message-ID: <33456BE1.4C14@pacbell.net>
and I forgot to say that the use of raise and return in

> someMethod: someCollection
>     | exitSignal result |
>     exitSignal := Signal new.
>     . . .
>     result := exitSignal
>                 handle: [:ex| ex returnWith: #negative]
>                 do: [someCollection select:
>                         [:elem|
>                         elem isInfinite ifTrue: [^#infinte].
>                         elem negative ifTrue: [exitSignal raise].
>                         elem even].
>     . . .

is exactly analogous to Lisp's catch and throw (which pre-dates CLOS).

and I also forgot to include 

> And in what sense do these behaviours imply that Smalltalk closures
> are not first class objects?  First-class refers to the ability to
> a) pass closures around as freely as any other objects
> b) the ability to define methods on closures as any other objects

c) define new subclasses of closures that define additonal
   state/new methods etc

> Smalltalk provides both of these.

Some Smalltalks (e.g. VW) provide all three, even if c) requires
creating a vanilla closure first.

_______________,,,^..^,,,_______________
Eliot Miranda, ObjectEngine technical lead, ParcPlace-Digitalk
From: Bill Gooch
Subject: Re: block closures
Date: 
Message-ID: <3345806D.6AB1@iconcomp.com>
Eliot & Linda wrote:
> 
> Bill Gooch wrote:
> >
> > Not exactly.  In particular, an explicit return from a
> > Smalltalk block is defined as a return from the defining
> > method of the block, whereas a (return) in a Common Lisp
> > closure is a return from the closure itself.  (Common Lisp
> > also provides a mechanism to specify a return from specific
> > enclosing contexts by name, which Smalltalk lacks.)  This
> > difference has nothing much to do with the ifTrue:/(if ...)
> > example, but it does reflect a limitation of Smalltalk in
> > dealing with a block which may be invoked outside of the
> > context of the method in which it is defined.
> >
> > In this sense, Smalltalk blocks do not behave as first-class
> > objects.
> 
> Nonsense! ( :) ) Smalltalk blocks _can_ return from a block
> as well as return from a block's enclosing method.

Not via an explicit ^ return, as far as I know.  If 
they can, none of your examples demonstrate this - 
they all exhibit blocks which either complete without
doing an explicit return, or return directly from the 
defining method.

>  How does the following work otherwise:
> 
>         (1 to: 10) select: [:n| n even]

This has no explicit return, nor is it an example of
a block which may be invoked outside the context of
the method in which it is defined (aka a block with
indefinite, as opposed to dynamic, extent).
 
> ... Smalltalk provides no default syntax for a block to return to
> its enclosing method.  But there's lots of mechanism around to
> do it.

There is one mechanism that I know of: the block 
completes without executing an explicit return, thus
returning the value of the last statement evaluated.
This is the *only* return mechanism that is valid in 
a block which is executed outside the context of its
defining method, since any explicit return in that 
case results in a runtime exception (due to trying to
return from a method context for a method which is
no longer on the execution stack).

> .... 
> someMethod: someCollection
>     | exitSignal result |
>     exitSignal := Signal new.
>     . . .
>     result := exitSignal
>                 handle: [:ex| ex returnWith: #negative]
>                 do: [someCollection select:
>                         [:elem|
>                         elem isInfinite ifTrue: [^#infinte].
>                         elem negative ifTrue: [exitSignal raise].
>                         elem even].
>     . . .

Again, this example does not show a block which is
executed outside of the context of its defining method,
and the explicit return of #infinte is a return from the 
defining method, and not from the select: block.
 
> There are also numerous ways of writing the following style:
>     . . .
> 
> which has the same effect as the above.


Fine, whatever.  Try the following, which illustrates
my point:

defineBlock
 ^[ :arg | arg == #broken 
               ifTrue: [^#veryBroken]
               ifFalse: [#allRightyThen] ].

testIt
 | block result1 result2 |
 block := self defineBlock.
 result1 := block value: #fine.
 result2 := block value: #broken.
 ^OrderedCollection with: result1 with: result2.

When you invoke #testIt, you'll get a walkback.

> And in what sense do these behaviours imply that Smalltalk closures
> are not first class objects?  First-class refers to the ability to
> a) pass closures around as freely as any other objects
> b) the ability to define methods on closures as any other objects
> Smalltalk provides both of these.

True, although (a) entails the limitation (demonstrated 
in the above example) that blocks which can be invoked 
outside the context of their definition cannot use the
full Smalltalk syntax and behavior.  They are constrained 
because they implicitly depend on the context of their
defining method, which they do not encapsulate.

> Which begs the question are closures in CLOS objects?  I don't know,
> but CLOS, being an impure language (unlike Smalltalk and Dylan), may
> not make closures objects.  If so, it is CLOS which lacks first-class
> closures and not Smalltalk.

CLOS makes no pretense of "purity."  I could be wrong, 
but I don't believe the standard requires that closures 
be first-class CLOS objects.  However, CLOS implementa-
tions can make closures first-class without violating 
the standard, and I believe that at least some implemen-
tations do so.

In any case, CL closures in any implementation of the
standard are far more powerful and flexible than Smalltalk 
blocks.

Are we having fun yet?

-- 
William D. Gooch             ····@iconcomp.com
Icon Computing               http://www.iconcomp.com     
Texas liaison for the International Programmers Guild 
For IPG info, see http://www.ipgnet.com/ipghome.htm
From: Eliot & Linda
Subject: Re: block closures
Date: 
Message-ID: <3345962A.2785@pacbell.net>
Bill Gooch wrote:
> Eliot & Linda wrote:
> > Bill Gooch wrote:
> > >
> > > Not exactly.  In particular, an explicit return from a
> > > Smalltalk block is defined as a return from the defining
> > > method of the block, whereas a (return) in a Common Lisp
> > > closure is a return from the closure itself.  (Common Lisp
> > > also provides a mechanism to specify a return from specific
> > > enclosing contexts by name, which Smalltalk lacks.)  This
> > > difference has nothing much to do with the ifTrue:/(if ...)
> > > example, but it does reflect a limitation of Smalltalk in
> > > dealing with a block which may be invoked outside of the
> > > context of the method in which it is defined.
> > >
> > > In this sense, Smalltalk blocks do not behave as first-class
> > > objects.
> >
> > Nonsense! ( :) ) Smalltalk blocks _can_ return from a block
> > as well as return from a block's enclosing method.
> 
> Not via an explicit ^ return, as far as I know.  If
> they can, none of your examples demonstrate this -
> they all exhibit blocks which either complete without
> doing an explicit return, or return directly from the
> defining method.

^-return is defined to mean "return to the sender of the current method"
whether the point of execution is at the first level within the method,
or nested within the activation of some closure.  This is more
convenient
than have it mean "return to caller" for the majority of cases.  It is
also considered more consistent, since within any method ^-return means
return to the same point.

My examples demonstrated how one can construct a mechanism which does
provide "return to caller" from an arbitrary point within a block
(including nesting).

You're confusing the restriction on the use of ^-return with an
non-existent restriction on being able to return to the caller of a
block.
^-return must be executed within the dynamic extent of the enclosing
method
for there to be a sender of the method to return to.  There is no such
restriction on returning to caller.

Appologies for not including an example that demonstrated a block
being used outside the dynamic extent of its enclosing method.
But you know that its possible; your example below illustrates it:

[snip]
> Fine, whatever.  Try the following, which illustrates
> my point:
> 
> defineBlock
>  ^[ :arg | arg == #broken
>                ifTrue: [^#veryBroken]
>                ifFalse: [#allRightyThen] ].
> 
> testIt
>  | block result1 result2 |
>  block := self defineBlock.
>  result1 := block value: #fine.
>  result2 := block value: #broken.
>  ^OrderedCollection with: result1 with: result2.
> 
> When you invoke #testIt, you'll get a walkback.

Right.  Try doing the same thing in CLOS and you'll also get a
walk-back.
Of course, its harder to writem since CLOS provides no convenient syntax
for ^.  But then Smalltalk provides no convenient syntax for returning
to a caller from an arbitrary point in a block.  But this illustrates
a merely syntactic difference.

There's nothing to stop you doing

defineBlock
   ^[ :arg | arg == #broken
               ifTrue: [#notBroken]
               ifFalse: [#allRightyThen]].

testIt
  | block result1 result2 |
  block := self defineBlock.
  result1 := block value: #fine.
  result2 := block value: #broken.
  ^OrderedCollection with: result1 with: result2.

just as there's nothing to stop you writing

defineBlock
    ^[:arg|
	[:exit|
	arg == #broken ifTrue: [exit value: #notBroken].
	#allRightyThen] valueWithExit]

its syntactically ugly, but it does what your CLOS closure can.


> > And in what sense do these behaviours imply that Smalltalk closures
> > are not first class objects?  First-class refers to the ability to
> > a) pass closures around as freely as any other objects
> > b) the ability to define methods on closures as any other objects
> > Smalltalk provides both of these.
> 
> True, although (a) entails the limitation (demonstrated
> in the above example) that blocks which can be invoked
> outside the context of their definition cannot use the
> full Smalltalk syntax and behavior.  They are constrained
> because they implicitly depend on the context of their
> defining method, which they do not encapsulate.

Wrong.

> > Which begs the question are closures in CLOS objects?  I don't know,
> > but CLOS, being an impure language (unlike Smalltalk and Dylan), may
> > not make closures objects.  If so, it is CLOS which lacks first-class
> > closures and not Smalltalk.
> 
> CLOS makes no pretense of "purity."  I could be wrong,
> but I don't believe the standard requires that closures
> be first-class CLOS objects.  However, CLOS implementa-
> tions can make closures first-class without violating
> the standard, and I believe that at least some implemen-
> tations do so.
> 
> In any case, CL closures in any implementation of the
> standard are far more powerful and flexible than Smalltalk
> blocks.

How?  (they're not.  One can implement Lisp atop Smalltalk directly
mapping Lisp closures to Smalltalk blocks just as one can easily
do the converse.) They have the same semantic power.  CLOS lacks
syntax for Smalltalk-style ^-return.   Smalltalk lacks syntax
for CLOS's explicit return.  But both provide mechanism for
implementing the other.

> Are we having fun yet?

Very much so.

P.S. The original Smalltalk-80 as described by Goldberg and Robson
also had indefinite extent blocks, but these were not full closures,
and were not re-entrant.  This limitation has been absent from all
major commercial implementations for some time.
_______________,,,^..^,,,_______________
Eliot Miranda, ObjectEngine technical lead, ParcPlace-Digitalk
From: Bill Gooch
Subject: Re: block closures
Date: 
Message-ID: <3349C76B.326D@flash.net>
I am replying to this only briefly now, and will try to
respond more fully later, if time permits.

Eliot & Linda wrote:
> 
> ^-return is defined to mean "return to the sender of the current method"

Only by a somewhat odd (IMO) definition of "current."  I
personally find it hard to see how a method which may or 
may not be currently executing at the time of the return 
could be considered "the current method" at that time.

> ....
> You're confusing the restriction on the use of ^-return with an
> non-existent restriction on being able to return to the caller of a
> block....

No, I'm not.  You're ignoring my point, and diverting the 
discussion onto tangential matters.

> Right.  Try doing the same thing in CLOS and you'll also get a
> walk-back.

Wrong.  As I said, an explicit return from a CLOS closure 
is just that: a return from the closure itself.  Works fine,
regardless of extent; no special cases.

> Of course, its harder to writem since CLOS provides no convenient syntax
> for ^.

Wrong.  CL provides both a return from the current context,
via (return), as well as a return from a named enclosing 
context, via the (return-from <name>) syntax.

>  But then Smalltalk provides no convenient syntax for returning
> to a caller from an arbitrary point in a block.

Correct.

>  But this illustrates a merely syntactic difference.

CL functions can return from an explicitly named caller in 
the call chain, whether the return was anticipated or not.  
Smalltalk does not have this capability, as doing non-local 
returns requires explicit return-to points (defined, for
example, by exception handlers).  (Note: I don't consider 
the CL capability important, and I personally avoid using it, 
for reasons which I think are fairly obvious.  It's an old 
Interlisp feature I wish had never crept into Common Lisp.  
Nonetheless, the difference here is more than "syntactic.")

~~~~~~~~~~~~~~~~~~~~~~
Bill Gooch			······@flash.net
Texas liaison for the International Programmers Guild
For information on IPG, see http://www.ipgnet.com/ipghome.htm
From: Jan Steinman
Subject: Re: block closures
Date: 
Message-ID: <Jan-ya02408000R0704972305480001@news.structured.net>
In article <·············@flash.net>, Bill Gooch <······@flash.net> wrote:

> CL functions can return from an explicitly named caller in 
> the call chain, whether the return was anticipated or not.  
> Smalltalk does not have this capability...

Thank goodness! This allows you to use so-called "clean" (optimized) blocks
in situations that would be impossible if they had to carry around the
whole execution context. I assume that to "return from an explicitly named
caller," you've got to keep the entire damn caller chain around until the
block is complete, which is at best is merely wasteful of memory.

An explicit return is always a bad idea in a non-local block. In fact, if
you go along with Knuth's "single entry, single exit" rule of good design,
an explicit return out of a block is always a bad idea!

Okay, Bill. It might be useful to be able to "break" from a block back to
the immediately enclosing context, rather than from the declaring method,
but I don't really miss it. Smalltalk isn't CL.

: Jan Steinman <··········@Bytesmiths.com>
: Bytesmiths <http://www.bytesmiths.com>
: Java, the elegant simplicity of C++ and the blazing speed of Smalltalk.
From: Bill Gooch
Subject: Re: block closures
Date: 
Message-ID: <3349C9A8.7457@flash.net>
Eliot & Linda wrote:
> 
> ....
> P.S. The original Smalltalk-80 as described by Goldberg and Robson
> also had indefinite extent blocks, but these were not full closures,
> and were not re-entrant.  This limitation has been absent from all
> major commercial implementations for some time.

Curious logic: the removal of blocks which work properly 
when applied over indefinite extent somehow corresponds 
to the removal of a limitation?  I'd say removing the 
limitation would mean making *all* blocks fully capable, 
re-entrant closures, regardless of extent.

~~~~~~~~~~~~~~~~~~~~~~
Bill Gooch			······@flash.net
Texas liaison for the International Programmers Guild
For information on IPG, see http://www.ipgnet.com/ipghome.htm
From: Jan Steinman
Subject: Re: block closures
Date: 
Message-ID: <Jan-ya02408000R0704972322270001@news.structured.net>
In article <·············@flash.net>, Bill Gooch <······@flash.net> wrote:

> Eliot & Linda wrote:
> > 
> > ....
> > P.S. The original Smalltalk-80 as described by Goldberg and Robson
> > also had indefinite extent blocks, but these were not full closures,
> > and were not re-entrant.  This limitation has been absent from all
> > major commercial implementations for some time.
> 
> Curious logic: the removal of blocks which work properly 
> when applied over indefinite extent somehow corresponds 
> to the removal of a limitation?

Actually, I believe that an explicit return inside a block causes it to be
a slow "full" block, which follows the old Smalltalk-80 model pretty
closely. It has indefinite extent in the calling stack. Shucks, by crawling
"thisContext," I'll bet you can even get them to return to an arbitrary
context like CL does if you worked at it! :-)

Read your VisualWorks manuals, Bill -- nothing has been removed, but cases
that have a limited requirement for outer scope have been optimized. There
are three kinds of blocks in VW, clean, copying, and full. Full blocks
require outer context, and are several times slower than clean blocks. When
passed around or stored, they carry the entire outer context around, which
makes them memory pigs. (Copying blocks are nearly as time-efficient as
clean blocks, but they carry around "self," which makes them potential
memory pigs when stored or passed around.)

If you want blocks that you consider to "work properly," all you have to do
is reference a method temp inside the block and later after the block --
voila: you've got a slow, memory-hog, Smalltalk-80 style block! (Somehow, I
don't think Smalltalk-80 was what you had in mind as something that used to
"work properly." Feeling argumentative, perhaps? :-)

: Jan Steinman <··········@Bytesmiths.com>
: Bytesmiths <http://www.bytesmiths.com>
: Java, the elegant simplicity of C++ and the blazing speed of Smalltalk.
From: Vassili Bykov
Subject: Re: block closures
Date: 
Message-ID: <01bc442b$0d1e3fe0$752d54c7@vbykov.hip.cam.org>
Bill Gooch <······@flash.net> wrote in article <·············@flash.net>...
> Eliot & Linda wrote:
> > 
> > ....
> > P.S. The original Smalltalk-80 as described by Goldberg and Robson
> > also had indefinite extent blocks, but these were not full closures,
> > and were not re-entrant.  This limitation has been absent from all
> > major commercial implementations for some time.
> 
> Curious logic: the removal of blocks which work properly 
> when applied over indefinite extent somehow corresponds 
> to the removal of a limitation?  

Smalltalk blocks do and did have indefinite extent in the sense they can be
invoked at any moment of time after creation, regardless of whether the
exclosing method has been returned from or not.  However, in older versions
of Smalltalk-80 and Smalltalk/V blocks did not close over their lexical
scope bindings.  For example, a more or less equivalent of CL code

  (mapcar #'(lambda (i) #'(lambda () i)) '(1 2 3 4 5))

in a modern Smalltalk would be:

  #(1 2 3 4 5) collect: [:i | [i]]

which produces an Array of closures such that the first evaluates to 1, the
second--to 2, etc.  The same in older Smalltalk-80 (or in Smalltalk Express
nowadays) will not work because there blocks are not closures.  This is the
limitation Eliot says was lifted.

> I'd say removing the limitation would mean making *all* blocks fully
> capable, re-entrant closures, regardless of extent.

Thay are--or what do you mean by "fully capable"?  Block closures in modern
Smalltalks are not less capable than closures in CL: they close over
visible variable bindings and are re-entrant.  Granted, you cannot ^ from
the creation context more than once, just as you cannot RETURN-FROM it in
CL more than once.  While there existed Lisp implementations with
"spaghetti stacks" where a context could be returned from unlimited number
of times (where, I suppose, Scheme's continuations came from), in CL
standard "it is an error".

--Vassili
From: Vassili Bykov
Subject: Re: block closures
Date: 
Message-ID: <01bc41ff$799057e0$827ceccd@vbykov.hip.cam.org>
Bill Gooch <····@iconcomp.com> wrote in article
<·············@iconcomp.com>...
> CLOS makes no pretense of "purity."  I could be wrong, 
> but I don't believe the standard requires that closures 
> be first-class CLOS objects.

Well, you *are* wrong.  The standard does require values produced by
(FUNCTION (LAMBDA ...)) to be instances of class FUNCTION.  These values
can be freely passed around, assigned or bound to variables, and invoked
using FUNCALL, APPLY, or MULTIPLE-VALUE-CALL.  Methods can specialize on
FUNCTION just as on any other class.  That exactly fits Eliot's definition:

  > Eliot & Linda wrote:
  > [...] First-class refers to the ability to
  > a) pass closures around as freely as any other objects
  > b) the ability to define methods on closures as any other objects

Closures in Lisp and Smalltalk do have the same semantics.  As for
inability to return with ^ from a block after the enclosing method has
returned, this is also the case in CL: the standard specifies that
RETURN-FROM a closure outside the dynamic extent of the defining block is
an error and consequences are undefined (see the end of the section on
RETURN-FROM).

--Vassili
From: Seth Tisue
Subject: Re: block closures
Date: 
Message-ID: <5i6s0c$1m5@Godzilla.cs.nwu.edu>
In article <··························@vbykov.hip.cam.org>,
Vassili Bykov <······@cam.org> wrote:
>Bill Gooch <····@iconcomp.com> wrote in article
><·············@iconcomp.com>...
>> CLOS makes no pretense of "purity."  I could be wrong, 
>> but I don't believe the standard requires that closures 
>> be first-class CLOS objects.
>
>Well, you *are* wrong.  The standard does require values produced by
>(FUNCTION (LAMBDA ...)) to be instances of class FUNCTION.  These values
>can be freely passed around, assigned or bound to variables, and invoked
>using FUNCALL, APPLY, or MULTIPLE-VALUE-CALL.  Methods can specialize on
>FUNCTION just as on any other class.

But you can't subclass built-in classes like FUNCTION -- in that
sense, they're not quite "first class".

-- 
== Seth Tisue <·······@nwu.edu>         http://www.cs.nwu.edu/~tisue/
From: Alan Lovejoy
Subject: Re: block closures
Date: 
Message-ID: <334587A6.697C@concentric.net>
Bill Gooch wrote:
> 
> Stefan Matthias Aust wrote:
> > ....
> > Lisp's if expression is a special form and doesn't use method sending.
> > Otherwise, Lisp's lambda expressions (using only lexically bound variables)
> > have the same semantic as Smalltalk block closures as provided by most
> > Smalltalk implementations.
> 
> Not exactly.  In particular, an explicit return from a
> Smalltalk block is defined as a return from the defining
> method of the block, whereas a (return) in a Common Lisp
> closure is a return from the closure itself.  (Common Lisp
> also provides a mechanism to specify a return from specific
> enclosing contexts by name, which Smalltalk lacks.)  This
> difference has nothing much to do with the ifTrue:/(if ...)
> example, but it does reflect a limitation of Smalltalk in
> dealing with a block which may be invoked outside of the
> context of the method in which it is defined.
> 
> In this sense, Smalltalk blocks do not behave as first-class
> objects.

Perhaps you mean that Smalltalk blocks are not first class **functions**
(or methods).  Because there can be no question that they are first
class **objects** (they have all the same capabilities and privileges
of any other object).

--
Alan L. Lovejoy		| Why Smalltalk?
Smalltalk Consultant    | Because I don't want to follow the crowd,
········@concentric.net	| but to lead it.
From: Rainer Joswig
Subject: Re: block closures
Date: 
Message-ID: <joswig-ya023180000304971955210001@news.lavielle.com>
In article <·············@post.rwth-aachen.de>, ····@eecs.rwth-aachen.de wrote:

> From what I have read, Smalltalk inherited his blocks from LISP. So, if
> somebody is out there with a knowledge of both Smalltalk and LISP:
> - Is there an equivalent to a Smalltalk expression like:
>   (a < 0) ifTrue: [a := 0].
> - If yes, what would this LISP equivalent look like ?
> - What are the differences in the semantics ?
> 
> Thanks in advance

With a little macrology you can do things like:

? (define-modify-macro maxf (&optional (arg 0)) max)

Use it:

? (maxf a)


What it does:

? (macroexpand '(maxf a))
(SETQ A (MAX A 0))


;-)

-- 
http://www.lavielle.com/~joswig/
From: Vassili Bykov
Subject: Re: block closures
Date: 
Message-ID: <5i0in2$84c@stratus.CAM.ORG>
Rolf Breuning (·············@post.rwth-aachen.de) wrote:
: From what I have read, Smalltalk inherited his blocks from LISP. So, if
: somebody is out there with a knowledge of both Smalltalk and LISP:
: - Is there an equivalent to a Smalltalk expression like:
:   (a < 0) ifTrue: [a := 0].
: - If yes, what would this LISP equivalent look like ?

Yet speaking of Smalltalk, I prefer to write such things as

  a := 0 max: a.

--Vassili