Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Quotations revisited

777 views
Skip to first unread message

Marcel Hendrix

unread,
Jul 14, 2012, 9:55:03 AM7/14/12
to
Recently, the subject of quotations popped up again and I remembered
an unfinished project.

It proves that in iForth (a simple form of) quotations takes only three
lines of code. The main limitation is that LOCALS are not (yet) possible
inside a quotation.

You can use a quotation outside of the definition where it was created,
but it does not 'remember' any state.

-marcel

--
0 VALUE dict : myEXIT -R [ -OPT ] ;
: [: ( -- ) POSTPONE AHEAD HERE TO dict -OPT POSTPONE >R ; IMMEDIATE
: ;] ( -- xt ) POSTPONE myEXIT POSTPONE THEN dict POSTPONE LITERAL ; IMMEDIATE

: test PI FLOCAL p
[: F+ F+ ;]
[: F- F- ;]
[: F* F* ;] LOCALS| xt* xt- xt+ |
11e 2e 3e xt+ EXECUTE F.
11e 2e 3e xt- EXECUTE F.
11e 2e 3e xt* EXECUTE F.
p F. ;

defer do-this defer do-that : generic do-this do-that ;

: mode-1 [: ." x" ;] [is] do-this [: ." y" ;] [is] do-that ;
: mode-2 [: ." this " ;] [is] do-this [: ." that " ;] [is] do-that ;

: .ABOUT CR ." Try: test -- Prints `16.000000 12.000000 66.000000 3.141593`"
CR ." mode-1 generic -- Prints `xy`"
CR ." mode-2 generic -- Prints `this that`" ;


Stephen Pelc

unread,
Jul 15, 2012, 3:26:28 PM7/15/12
to
On Sat, 14 Jul 2012 15:55:03 +0200, m...@iae.nl (Marcel Hendrix) wrote:

>Recently, the subject of quotations popped up again and I remembered
>an unfinished project.

Given the increasing popularity of talking about "quotations" and
"closures", would someone like to specify them in Forth terminology.
Andrew provided an implementation that only made sense to people
with carnal knowledge of SwiftForth.

I have seen two or three sets of requirements dicussed, but for
those of us who distinguish between hand-waving and specifications,
would an interested party be prepared to specify what is required?

Stephen
P.S. "Go read this in WikiPedia" is inadequate.


--
Stephen Pelc, steph...@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
web: http://www.mpeforth.com - free VFX Forth downloads

Bernd Paysan

unread,
Jul 15, 2012, 5:53:12 PM7/15/12
to
Stephen Pelc wrote:

> On Sat, 14 Jul 2012 15:55:03 +0200, m...@iae.nl (Marcel Hendrix) wrote:
>
>>Recently, the subject of quotations popped up again and I remembered
>>an unfinished project.
>
> Given the increasing popularity of talking about "quotations" and
> "closures", would someone like to specify them in Forth terminology.
> Andrew provided an implementation that only made sense to people
> with carnal knowledge of SwiftForth.

Ok, quotations are fairly trivial. The experession

: foo ... [: some words ;] ... ;

is equal to

:noname some words ; Constant #temp#
: foo ... #temp# ... ;

I.e.

[: ( -- nestd-sys )
Compilation: suspends compiling to the current definition, starts a new
nested definition, and compilation continues with this nested
definition.

;] ( nested-sys -- )
Compilation: Ends the current nested definition, and resumes compilation
to the previous current definition. It appends the following run-time to
the current definition:

run-time: ( -- xt )
xt is the execution token to execute the nested definition.

If it's just a quotation, it can have its own locals, but it can't
access the locals of the outer word. We have some boy compilers here
(iForth, it would be possible with Gforth, too), which could access
locals from the outer scope, but not as real closure or correctly nested
frame.

Boy compiler:

: foo { a b } ... [: ... a b ... ;] execute ;

Here, a and b referenced in the boy-closure are offsets into the locals
stack which are identical to code generated within foo, and when
executed from within foo directly, they access the same locals. These
are not real closures, not even correctly nested frames.

Algol 60 (with its famous man-or-boy-test) has nested frames, which
requires that the xt carries a reference to the scope it was created in,
i.e. [: would produce an xt at run-time, which sets the frame for access
to outer locals, and then runs the code defined within the [: ;]
boundaries. Algol-like compilers usually solve that by adding an
implicit paramenter to the nested function, which points to the
environment, and the compiler knows to insert the proper parameter, but
in Forth, we can't do this.

Full closures go even further, they make sure that the environment is
active as long as the closure (the xt returned after ;]) is alive. This
means that the locals would be allocated on the heap, an some sort of
garbage collection is necessary to free unused memory.

> I have seen two or three sets of requirements dicussed, but for
> those of us who distinguish between hand-waving and specifications,
> would an interested party be prepared to specify what is required?
>
> Stephen
> P.S. "Go read this in WikiPedia" is inadequate.

Read the source, Luke. There are quotations for VFX in the MINOS
harness.

This is [: ;] in VFX Forth, not taking into account locals, stripped
down to the actual requirement:

: [: ( compile-time: -- nest-sys )
<headerless> @ last @ POSTPONE AHEAD
postpone [ :noname ; immediate

: ;] ( compile-time: nest-sys -- ; run-time: -- xt )
discard-sinline POSTPONE ; ( xt ) >r
] POSTPONE THEN r> POSTPONE Literal
last ! <headerless> ! discard-sinline ; immediate

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://bernd-paysan.de/

Marcel Hendrix

unread,
Jul 15, 2012, 5:54:45 PM7/15/12
to
steph...@mpeforth.com (Stephen Pelc) writes Re: Quotations revisited

> On Sat, 14 Jul 2012 15:55:03 +0200, m...@iae.nl (Marcel Hendrix) wrote:

>>Recently, the subject of quotations popped up again and I remembered
>>an unfinished project.

> Given the increasing popularity of talking about "quotations" and
> "closures", would someone like to specify them in Forth terminology.
> Andrew provided an implementation that only made sense to people
> with carnal knowledge of SwiftForth.

I'll answer in the hope to stand corrected :-)

A "quotation" is :noname definition that can be nested in another
definition. Note that so far it would only be semantics;
obviously

:noname ( -- ) ." yeah" ; constant a
: test ( -- ) a execute ;

does the same as

: test ( -- ) [: ." yeah" ;] execute ;

Technically, some systems may have problems allowing locals in a
quotation, i.e.

: test ( -- ) 8 locals| x | 5 [: locals| x | x 3 * . ;] execute x . ;

A rather easy extension would be to let code access (not necessarily
modify) the locals of the hosting definition (printing 24 here):

: test ( -- ) 8 locals| x | [: x 3 * . ;] execute ;

However, this is getting hairy:

: test ( -- xt ) 8 locals| x | [: x 3 * . ;] ;
test execute ( ? )

AFAIU, when the implementation is such that the quotation permanently
'remembers' the value of 'x' (prints 24), this is called a 'closure.'

Knuth's Man-Or-Boy test creates a quotation that *modifies* the
outer locals and then recursively calls its host, accessing outer
locals that one might have expected to long gone out of
scope. It forces the quotation implementation to store copies of
*all imaginable* outer locals and make them permanently available.

This can get even more interesting when a closure is required to
remember not only locals, but things like BASE, >IN, arbitrary
variables, file handles, buffer addresses, etc..(*)

> I have seen two or three sets of requirements discussed, but for
> those of us who distinguish between hand-waving and specifications,
> would an interested party be prepared to specify what is required?

Maybe we first need a convincing example of the usefulness of
quotations and closures -- (*) would certainly be useful, but
the cost seems to be a little excessive?

-marcel

Bernd Paysan

unread,
Jul 15, 2012, 6:48:42 PM7/15/12
to
Marcel Hendrix wrote:
> Maybe we first need a convincing example of the usefulness of
> quotations and closures -- (*) would certainly be useful, but
> the cost seems to be a little excessive?

Quotations are quite useful when you do higher-order functions. We have
discussed words like LIST>, which take a list as argument, and loop over
the rest of the word with each item. Having a MAP-LIST is easier to
implement (especially for compilers like VFX and iForth, others have no
problems ;-), and quotations make it easier to write code for this.

Closures are something different, they contain both a function *and*
data. We have something like that in Forth - with name and persistent
in the dictionary, it's defined by CREATE and DOES>. Having the same
available with anonymous definition is useful, but it doesn't
necessarily have to be a closure as implementation (a closure always
means access to outer locals).

IMHO the price for real closures are too high to be paid in Forth - real
closures mean that you can't have a stack for locals, you absolutly need
to allocate them from the heap and have garbage collection.

A compromise would be the [:{ I proposed - this is a "poor man's
closure": it would be freed explicitly (you say <xt> free throw), and it
would take arguments from the stack. IMHO it feels much more Forth-
like: It doesn't come with the cost of full closures, where you can't
know the lifetime of a local frame in advance, and therefore you have to
make them live on a heap by default.

It's far better to have only those things to live on the heap which
absolutely must live there.

Elizabeth D. Rather

unread,
Jul 15, 2012, 8:11:37 PM7/15/12
to
On 7/15/12 11:54 AM, Marcel Hendrix wrote:
...
> Maybe we first need a convincing example of the usefulness of
> quotations and closures -- (*) would certainly be useful, but
> the cost seems to be a little excessive?

Um, yeah. Aside from looking obscure & clever and satisfying the "[x]
can do it, why not Forth?" test, what on earth does this buy you?

Cheers,
Elizabeth

--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310.999.6784
5959 West Century Blvd. Suite 700
Los Angeles, CA 90045
http://www.forth.com

"Forth-based products and Services for real-time
applications since 1973."
==================================================


A. K.

unread,
Jul 16, 2012, 1:47:09 AM7/16/12
to
On 16.07.2012 02:11, Elizabeth D. Rather wrote:
> On 7/15/12 11:54 AM, Marcel Hendrix wrote:
> ...
>> Maybe we first need a convincing example of the usefulness of
>> quotations and closures -- (*) would certainly be useful, but
>> the cost seems to be a little excessive?
>
> Um, yeah. Aside from looking obscure & clever and satisfying the "[x]
> can do it, why not Forth?" test, what on earth does this buy you?
>
> Cheers,
> Elizabeth
>

IMO by using MARKER (and/or FORGET), most typical applications for
closures can be solved in standard Forth systems as well.

OTOH Forth native code compilers would have to pack some runtime manager
into the generated code. A two-pass compilation process could determe
the closed code compiled length and then treat the closed code block as
stack item. But...

Roelf Toxopeus

unread,
Jul 16, 2012, 4:14:27 AM7/16/12
to
In article <5881128...@frunobulax.edu>, m...@iae.nl (Marcel Hendrix)
wrote:

[...]

>
> Maybe we first need a convincing example of the usefulness of
> quotations and closures -- (*) would certainly be useful, but
> the cost seems to be a little excessive?

My understanding of quotations and closures is such that I think I
recognize them under different names:

1. Someone actually using them in Forth is Ward McFarland, (co)author of
MacForth. He called them phrases. He would be a good one to ask.
A quick look over MF shows he used them (quite a lot) mostly for dealing
with items in lists, but also for passing xt's to ordinary words and for
setting deferred words. Funny, now I see he has used them in code I
originally supplied, haha! Comparing the code, I'm still not convinced.

2. Where you start to see them frequently is on the Mac OS. Here they're
called blocks. Many calls using function pointers have a 'block' version
as well. Nao Sacrada, author of iMops, is afraid Apple will move to
exclusively using blocks and has implemented them in iMops.
Although blocks are the latest rave with the Apple crews, I'm less
afraid Apple will deprecate calls using function pointers. But then
Apple can be a "los gelaten projectiel", very unpredictable. We'll see
if I have to ask my dear Forth vendors for a solution. For now don't
bother on my behalf.

-Roelf

Andrew Haley

unread,
Jul 16, 2012, 5:23:20 AM7/16/12
to
Marcel Hendrix <m...@iae.nl> wrote:
>
> Maybe we first need a convincing example of the usefulness of
> quotations and closures -- (*) would certainly be useful, but
> the cost seems to be a little excessive?

Closures offer a lot of power for very little cost. Sure, it's really
just syntactic sugar, but it declutters code. It gives a portable way
to do what has historically been done with return stack manipulation
or the creation of auxiliary declarations.

Bend's LIST> is a god example. Another one is CATCH:

:[ fee fi ]; catch if ...


Andrew.

Mark Wills

unread,
Jul 16, 2012, 5:32:19 AM7/16/12
to
On Jul 16, 1:11 am, "Elizabeth D. Rather" <erat...@forth.com> wrote:
> On 7/15/12 11:54 AM, Marcel Hendrix wrote:
> ...
>
> > Maybe we first need a convincing example of the usefulness of
> > quotations and closures -- (*) would certainly be useful, but
> > the cost seems to be a little excessive?
>
> Um, yeah. Aside from looking obscure & clever and satisfying the "[x]
> can do it, why not Forth?" test, what on earth does this buy you?
>
> Cheers,
> Elizabeth
>
> --
> ==================================================
> Elizabeth D. Rather   (US & Canada)   800-55-FORTH
> FORTH Inc.                         +1 310.999.6784
> 5959 West Century Blvd. Suite 700
> Los Angeles, CA 90045http://www.forth.com
>
> "Forth-based products and Services for real-time
> applications since 1973."
> ==================================================

Indeed.

A while back, for my own Forth system, I was looking at a more
intelligent dictionary structure that would allow something like this:

: WORD_A
... ... ...
... ... ...
: WORD_B
... ... ...
... ... ...
;
;

So, WORD_B can see WORD_A (and everything above it) but WORD_A can't
see WORD_B or its children.

Never got the chance to follow up on it. I think it's neat. Though I'm
sure it's not new.

Andrew Haley

unread,
Jul 16, 2012, 5:32:43 AM7/16/12
to
Elizabeth D. Rather <era...@forth.com> wrote:
> On 7/15/12 11:54 AM, Marcel Hendrix wrote:
> ...
>> Maybe we first need a convincing example of the usefulness of
>> quotations and closures -- (*) would certainly be useful, but
>> the cost seems to be a little excessive?
>
> Um, yeah. Aside from looking obscure & clever and satisfying the
> "[x] can do it, why not Forth?" test, what on earth does this buy
> you?

It's a much cleaner way of creating words like DOES> and ACTIVATE that
have historically been implemented by doing very non-portable things
with the return stack. It gives the Forth programmer an entitlement
to do something that has only been possible for the implementer.

And if you say "But all you've got to do is create an auxiliary
declaration!" I'm going to say "Why didn't you write DOES> and
ACTIVATE that way, then?" The answer is IMO clear:

: array ( n) create cells allot does> swap cells + ;

reads much better than:

: do-array ( n a - a) swap cells + ;
: array ( n) create cells allot ['] do-array does ;

Andrew.

m.a.m....@tue.nl

unread,
Jul 16, 2012, 6:39:22 AM7/16/12
to
On Monday, July 16, 2012 11:23:20 AM UTC+2, Andrew Haley wrote:
>> Maybe we first need a convincing example of the usefulness of
>> quotations and closures -- (*) would certainly be useful, but
>> the cost seems to be a little excessive?

> Closures offer a lot of power for very little cost. Sure, it&#39;s really
> just syntactic sugar, but it declutters code. It gives a portable way
> to do what has historically been done with return stack manipulation
> or the creation of auxiliary declarations.

> Bend&#39;s LIST&gt; is a god example.

Can you be a little bit more specific? I think this is the LIST> you mean?

: list> ( thread -- element )
BEGIN @ dup WHILE dup r@ execute
REPEAT drop r> drop ;

How is it used? Quite intricate, that first '@'.

> Another one is CATCH:
>
> :[ fee fi ]; catch if ...

I think I get this one. This indeed gets rid of syntax that is
sometimes quite boring and verbose.

-marcel

Stephen Pelc

unread,
Jul 16, 2012, 7:41:06 AM7/16/12
to
On Mon, 16 Jul 2012 04:32:43 -0500, Andrew Haley
<andr...@littlepinkcloud.invalid> wrote:

Elizabeth said:
>> Um, yeah. Aside from looking obscure & clever and satisfying the
>> "[x] can do it, why not Forth?" test, what on earth does this buy
>> you?

Brilliant! I shall quote you on that.

>It's a much cleaner way of creating words like DOES> and ACTIVATE that
>have historically been implemented by doing very non-portable things
>with the return stack. It gives the Forth programmer an entitlement
>to do something that has only been possible for the implementer.

Most of us can see the point of quotations in generating "kewl
notations". Quotations as nested definitions have been discussed
from time to time for 20 years or more. However, nobody has
convinced me that they are required.

Closures are a very different matter in terms of implementation
requirements. Closures require changes to both scope/visibility
and persistence of data. It could well be a mistake to discuss
them as extended quotations.

Stephen

Stephen Pelc

unread,
Jul 16, 2012, 8:01:30 AM7/16/12
to
A revised summary, 16 July 2012

Given the increasing popularity of talking about "quotations" and
"closures", it would be useful to have a specification to talk
about.

Andrew provided an implementation of quotations that will only
make sense to people with carnal knowledge of SwiftForth. Bernd
provided an implementation that will only make sense to people
with carnal knowledge of VFX Forth.

I see that that quotations can provide pretty notations at little
cost. On closures I remain unconvinced, but have not seen a Forth
implementation or notation.

I have seen two or three sets of requirements dicussed, but for
those of us who distinguish between hand-waving, source code and
specifications, would an interested party be prepared to specify
what is required? It seems that the interested party is going to
have to be me.

Stephen
P.S. "Go read this in WikiPedia" is inadequate.
P.P.S. "Read the source, Luke" is inadequate.

The following notes on quotations and closures incorporate
material from several people, including Andrew Haley, Marcel
Hendrix, Bernd Paysan, and Elizabeth Rather. If you have been left
out and want acknowledgement, please let me know.

Quotations
==========

Discussion
----------
The essence of quotations is to provide nested colon definitions,
in which the inside definition(s) are namess. The expression

: foo ... [: some words ;] ... ;

is equivalent to

:noname some words ; Constant #temp#
: foo ... #temp# ... ;

If quotations are to have the same privileges as words defined
with : and :NONAME they should be able to use local variables and
use RECURSE. Quotations should not be able to access the locals of
the outer word because we have no knowledge of when the quotation
is executed and hence whether outer locals are still alive.

One example use of quotations is to provide a solution to the use
of CATCH in a form close to other languages' TRY ... EXCEPT
blocks.

: foo
...
[: fee fi fo fum ;] catch if ... then
...
;


Specification
-------------

[: ( -- nested-sys )
Compilation: suspends compiling to the current definition, starts a
new
nested definition, and compilation continues with this nested
definition. Outer locals are not visible in the nested definition.
RECURSE applies to the nested definition.

;] ( nested-sys -- )
Compilation: Ends the current nested definition, and resumes
compilation
to the previous current definition. It appends the following run-time
to
the current definition:

run-time: ( -- xt )
xt is the execution token to execute the nested definition.


Closures
========

Discussion
----------
I have chosen to distinguish nameless words intended as closures
by using [[: ... ;]] to define them. I have also chosen to
distinguish the required persistence of data by declaring it using
{{ ... }} which is syntactically like { ... } locals but has very
different persistence requirements.

A quotation can have its own locals, but it can't access the
locals of the outer word. We have Forth compilers which could
access locals from the outer scope, but not as a real closure or
correctly nested frame.

Closures have different requirements for scope (visibility) and for
data persistence.

: foo { a b -- } ... [: ... a b ... ;] execute ;

Here, a and b referenced in the boy-closure are offsets into the
locals
stack which are identical to code generated within foo, and when
executed from within foo directly, they access the same locals. These
are not real closures, not even correctly nested frames.

Algol 60 (with its famous man-or-boy-test) has nested frames, which
requires that the xt carries a reference to the scope it was created
in,
i.e. [: would produce an xt at run-time, which sets the frame for
access
to outer locals, and then runs the code defined within the [: ;]
boundaries. Algol-like compilers usually solve that by adding an
implicit paramenter to the nested function, which points to the
environment, and the compiler knows to insert the proper parameter,
but
in Forth, we can't do this.

Full closures go even further, they make sure that the environment is
active as long as the closure (the xt returned after ;]) is alive.
This
means that the locals would be allocated on the heap, an some sort of
garbage collection is necessary to free unused memory.

: foo {{ a b -- }} ... [[: ... a b ... ;]] execute ;

Knuth's Man-Or-Boy test creates a quotation that *modifies* the
outer locals and then recursively calls its host, accessing outer
locals that one might have expected to long gone out of
scope. It forces the quotation implementation to store copies of
*all imaginable* outer locals and make them permanently available.

This can get even more interesting when a closure is required to
remember not only locals, but things like BASE, >IN, arbitrary
variables, file handles, buffer addresses, etc..(*)

Maybe we first need a convincing example of the usefulness of
quotations and closures -- (*) would certainly be useful, but
the cost seems to be a little excessive?

Aside from looking obscure and clever and satisfying the "[x]
can do it, why not Forth?" test, what on earth does this buy you?

What does a closure achieve that cannot be achieved by other
scoping and persistence mechanisms such as a class and an object
with heap allocation?

Specification
-------------

TBD

Andrew Haley

unread,
Jul 16, 2012, 8:09:21 AM7/16/12
to
m.a.m....@tue.nl wrote:
> On Monday, July 16, 2012 11:23:20 AM UTC+2, Andrew Haley wrote:
>>> Maybe we first need a convincing example of the usefulness of
>>> quotations and closures -- (*) would certainly be useful, but
>>> the cost seems to be a little excessive?
>
>> Closures offer a lot of power for very little cost. Sure, it's really
>> just syntactic sugar, but it declutters code. It gives a portable way
>> to do what has historically been done with return stack manipulation
>> or the creation of auxiliary declarations.
>
>> Bend's LIST> is a god example.
>
> Can you be a little bit more specific? I think this is the LIST> you mean?
>
> : list> ( thread -- element )
> BEGIN @ dup WHILE dup r@ execute
> REPEAT drop r> drop ;
>
> How is it used? Quite intricate, that first '@'.

: print-elements ( a -) list> .element ;

.ELEMENT is called on every element.

Andrew.

Andrew Haley

unread,
Jul 16, 2012, 8:40:15 AM7/16/12
to
Stephen Pelc <steph...@mpeforth.com> wrote:
> On Mon, 16 Jul 2012 04:32:43 -0500, Andrew Haley
> <andr...@littlepinkcloud.invalid> wrote:
>
> Elizabeth said:
>>> Um, yeah. Aside from looking obscure & clever and satisfying the
>>> "[x] can do it, why not Forth?" test, what on earth does this buy
>>> you?
>
> Brilliant! I shall quote you on that.
>
>>It's a much cleaner way of creating words like DOES> and ACTIVATE that
>>have historically been implemented by doing very non-portable things
>>with the return stack. It gives the Forth programmer an entitlement
>>to do something that has only been possible for the implementer.
>
> Most of us can see the point of quotations in generating "kewl
> notations". Quotations as nested definitions have been discussed
> from time to time for 20 years or more. However, nobody has
> convinced me that they are required.

As you know I have said the same thing about "kewl notations" myself,
many times; my preference is for very lean and mean systems.

Quotations are better than that because they replace very nonportable
return stack trickery [AKA partitioning words] which I know you have
seen several times, with a much easier to maintain construct.

In other words, quotations render pointless much of the "kewl
notations" that we've seen by providing a standard portable way to do
things.

For example, quotations provide a portable way to do the trickery of
?PREFIX in

: prefix? \ -- t/f ; true if in prefix mode
<prefix> @
;

: ?prefix \ n -- n' ; executes previous opcode
prefix? if
r>
aprior 2@ 2swap aprior 2!
>r
endif
;

: 2op-r/m \ op1 op2 reg -- ; reg/mem16 --
create
, , ,
does>
?prefix \ do the last one
... \ lay the code
reset \ ready for next opcode

Forgive me if I've misunderstood this code, but I think it could be
written portably as:

: ?prefix \ n xt -- n' ; executes previous opcode
prefix? if
aprior 2@ 2swap aprior 2!
endif
execute
reset \ ready for next opcode
;

: 2op-r/m \ op1 op2 reg -- ; reg/mem16 --
create
, , ,
does>
:[
... \ lay the code
]; ?prefix
;

You'd not need to turn off your optimizer, because there is no
abnormal control flow. And, a big bonus for the maintainer of this
code, you can see at the point of calling ?PREFIX what is going on.
This alone is worth it, IMO.

There clearly is a need for this kind of thing, or you wouldn't have
seen it. Quoting you directly,

> Saying that such code [i.e. partitioning words] is non-standard does
> not affect the reality that such code is in use and that practical
> systems have to cope with such code.

Yes, we must resist pointless syntactic sugar, but we must surely also
avoid Not Invented Here Syndrome.

Andrew.

Anton Ertl

unread,
Jul 16, 2012, 8:47:36 AM7/16/12
to
steph...@mpeforth.com (Stephen Pelc) writes:
>On Sat, 14 Jul 2012 15:55:03 +0200, m...@iae.nl (Marcel Hendrix) wrote:
>Given the increasing popularity of talking about "quotations" and
>"closures", would someone like to specify them in Forth terminology.

A simple quotation is an anonymous colon definition that is defined
inside a colon definition or quotation. It has no access to locals of
the enclosing definitions.

A closure is like a quotation, except that it has (read and write)
access to the locals of the enclosing definitions.

Simple quotations are relatively easy to implement, closures are hard,
because they can extend the life of the enclosed locals beyond the end
if their definition; in general garbage collection is needed to manage
the enclosed locals of closures. Therefore everyone up to now has
only seriously thought about implementing and standardizing simple
quotations, and any discussions about closures are just theoretical
exercises.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2012: http://www.euroforth.org/ef12/

Andrew Haley

unread,
Jul 16, 2012, 9:56:09 AM7/16/12
to
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
> steph...@mpeforth.com (Stephen Pelc) writes:
>>On Sat, 14 Jul 2012 15:55:03 +0200, m...@iae.nl (Marcel Hendrix) wrote:
>>Given the increasing popularity of talking about "quotations" and
>>"closures", would someone like to specify them in Forth terminology.
>
> A simple quotation is an anonymous colon definition that is defined
> inside a colon definition or quotation. It has no access to locals of
> the enclosing definitions.
>
> A closure is like a quotation, except that it has (read and write)
> access to the locals of the enclosing definitions.
>
> Simple quotations are relatively easy to implement, closures are hard,
> because they can extend the life of the enclosed locals beyond the end
> if their definition; in general garbage collection is needed to manage
> the enclosed locals of closures. Therefore everyone up to now has
> only seriously thought about implementing and standardizing simple
> quotations, and any discussions about closures are just theoretical
> exercises.

That's an exceleent summary. I'd personallty delete the "(read and
write)" part in the definition of closures, but as you say that
doesn't matter because discussions about clousures in Forth are just a
theoretical exercise.

Andrew.

Anton Ertl

unread,
Jul 16, 2012, 9:56:23 AM7/16/12
to
"A. K." <a...@nospam.org> writes:
>IMO by using MARKER (and/or FORGET), most typical applications for
>closures can be solved in standard Forth systems as well.

What do you mean with "most typical applications for closures" and
"solved"?

Sure, instead of

: foo { a b } ... [: ... a ... b ... ;] ... ;

One can write

: foo { a b } ...
:noname postpone ...
a postpone literal
postpone ...
b postpone literal
postpone ...
postpone ;
... ;

and at some point, when you know you no longer need the anonymous
definition, you can delete it with a marker.

But when do you know that you no longer need it, that there is no
reference to it anywhere?

Also, even this becomes even more complex if you want to write to a or
b.

Gerry Jackson

unread,
Jul 16, 2012, 10:04:46 AM7/16/12
to
On 16/07/2012 13:47, Anton Ertl wrote:
> steph...@mpeforth.com (Stephen Pelc) writes:
>> On Sat, 14 Jul 2012 15:55:03 +0200, m...@iae.nl (Marcel Hendrix) wrote:
>> Given the increasing popularity of talking about "quotations" and
>> "closures", would someone like to specify them in Forth terminology.
>
> A simple quotation is an anonymous colon definition that is defined
> inside a colon definition or quotation. It has no access to locals of
> the enclosing definitions.
>
> A closure is like a quotation, except that it has (read and write)
> access to the locals of the enclosing definitions.
>
> Simple quotations are relatively easy to implement, closures are hard,
> because they can extend the life of the enclosed locals beyond the end
> if their definition; in general garbage collection is needed to manage
> the enclosed locals of closures. Therefore everyone up to now has
> only seriously thought about implementing and standardizing simple
> quotations, and any discussions about closures are just theoretical
> exercises.
>

Have you already forgotten about this?
https://groups.google.com/group/comp.lang.forth/browse_frm/thread/c411311cc58807f3/8714c635d5758565?hl=en&lnk=gst&q=manorboy#8714c635d5758565

And written in ANS Forth too. Despite its syntax and lack of automatic
garbage collection, the package enables people to experiment with the
concepts in several ANS Forth systems.

www.qlikz.org/forth/lambda.zip

--
Gerry


Stephen Pelc

unread,
Jul 16, 2012, 10:05:14 AM7/16/12
to
On Mon, 16 Jul 2012 07:40:15 -0500, Andrew Haley
<andr...@littlepinkcloud.invalid> wrote:

>For example, quotations provide a portable way to do the trickery of
>?PREFIX in
...
>: 2op-r/m \ op1 op2 reg -- ; reg/mem16 --
> create
> , , ,
> does>
> :[
> ... \ lay the code
> ]; ?prefix
>;

>You'd not need to turn off your optimizer, because there is no
>abnormal control flow. And, a big bonus for the maintainer of this
>code, you can see at the point of calling ?PREFIX what is going on.
>This alone is worth it, IMO.

The suggestion is that the "abnormal control flow" is hidden by
the quotation. In this particular case the partitioning is also
avoided because the quotation provides it.

>There clearly is a need for this kind of thing, or you wouldn't have
>seen it.

Agreed.

>Yes, we must resist pointless syntactic sugar, but we must surely also
>avoid Not Invented Here Syndrome.

I have very little against quotations except creeping complexity.
However, nearly all the arguments I see in favour of quotations
are to do with syntactic sugar. There's almost always an existing
way to do it except in the ?PREFIX case. I don't believe that
the ?PREFIX case justifies a new mechanism. The particular
implementation of ?PREFIX was presented by Bob Smith 25 years
ago and I'm the only person who discusses it. The LIST>
example raises essentially the same issues. That makes two
of us. Given the amount of work to implement quotations
across all systems, it can be argued that we should go back
to the traditional Forth position of accepting a bit of
implementation-specific code; always providing of course that
it has been documented.

I have a very different position on closures. Given that the Forth
community has not established common practice for OOP over the
last 30 years, closures are just "look how clever I am" fodder.

Andrew Haley

unread,
Jul 16, 2012, 10:20:46 AM7/16/12
to
Stephen Pelc <steph...@mpeforth.com> wrote:
> On Mon, 16 Jul 2012 07:40:15 -0500, Andrew Haley
> <andr...@littlepinkcloud.invalid> wrote:
>
>>For example, quotations provide a portable way to do the trickery of
>>?PREFIX in
> ...
>>: 2op-r/m \ op1 op2 reg -- ; reg/mem16 --
>> create
>> , , ,
>> does>
>> :[
>> ... \ lay the code
>> ]; ?prefix
>>;
>
>>You'd not need to turn off your optimizer, because there is no
>>abnormal control flow. And, a big bonus for the maintainer of this
>>code, you can see at the point of calling ?PREFIX what is going on.
>>This alone is worth it, IMO.
>
> The suggestion is that the "abnormal control flow" is hidden by
> the quotation. In this particular case the partitioning is also
> avoided because the quotation provides it.

I suppose that's right, although there isn't really any abnormal
control flow: it's just a definition that gets executed.

>>There clearly is a need for this kind of thing, or you wouldn't have
>>seen it.
>
> Agreed.
>
>>Yes, we must resist pointless syntactic sugar, but we must surely also
>>avoid Not Invented Here Syndrome.
>
> I have very little against quotations except creeping complexity.
> However, nearly all the arguments I see in favour of quotations
> are to do with syntactic sugar. There's almost always an existing
> way to do it except in the ?PREFIX case.

Well, I can always think of reasons that some example doesn't really
count. My take on this one is that the added complexity is slight in
comparison with the added expressive power, but YMMV -- and apparently
does.

> I don't believe that the ?PREFIX case justifies a new mechanism. The
> particular implementation of ?PREFIX was presented by Bob Smith 25
> years ago and I'm the only person who discusses it. The LIST>
> example raises essentially the same issues. That makes two of
> us. Given the amount of work to implement quotations across all
> systems, it can be argued that we should go back to the traditional
> Forth position of accepting a bit of implementation-specific code;
> always providing of course that it has been documented.

It can be argued, but it probably shouldn't be. I'll grant you that
there is always a system-dependent way to do the same kind of thing.
I would suggest that we implement and use quotations for a while and
see how they help. I've already posted the SwiftForth version as an
example.

Andrew.

Andrew Haley

unread,
Jul 16, 2012, 10:23:57 AM7/16/12
to
That doesn't get me to an article, just a very long thread.

Andrew.

Anton Ertl

unread,
Jul 16, 2012, 10:05:31 AM7/16/12
to
m...@iae.nl (Marcel Hendrix) writes:
>Knuth's Man-Or-Boy test creates a quotation that *modifies* the
>outer locals and then recursively calls its host, accessing outer
>locals that one might have expected to long gone out of
>scope. It forces the quotation implementation to store copies of
>*all imaginable* outer locals and make them permanently available.

For writable locals, it's a bad idea to make copies, because then any
write would need to write to all the copies. The typical
implementation approach is to have a structure for each definition
that contains the direct locals of the definition; that structure is
called a frame or actication record. The frame of an enclosed
definition links to the frame of the next-outer definition, and when
accessing an outer local, you follow the links until you are at the
right frame, and then perform the access. Each frame has to be kept
around as long as it can be accessed (or typically, as long as there
is some link to it around).

There are optimizations of that optimization, with various tradeoffs.
E.g., if the locals are read-only, one can copy them.

>Maybe we first need a convincing example of the usefulness of
>quotations and closures -- (*) would certainly be useful, but
>the cost seems to be a little excessive?

Yes, the cost of closures seems excessive. The cost of quotations
doesn't: no outer variables means no frames that have to be kept
around.

Anton Ertl

unread,
Jul 16, 2012, 10:56:32 AM7/16/12
to
Google Groups has stopped working ("To use Google Groups Discussions,
please enable JavaScript in your browser settings, and then refresh
this page."). Do you have a Message-ID?

>And written in ANS Forth too. Despite its syntax and lack of automatic
>garbage collection, the package enables people to experiment with the
>concepts in several ANS Forth systems.
>
>www.qlikz.org/forth/lambda.zip

Sure, you can do approximations of the ideal closures (which look just
like quotations where you access outer locals; that's why closures are
being discussed in connection with quotations) for experimental work.
What I wrote applies to the ideal.

Stephen Pelc

unread,
Jul 16, 2012, 11:46:01 AM7/16/12
to
And we already have at least two naming conventions!

:[ ... ]:
and
[: ... ;]

I have slightly more sympathy with the second form.

Anton Ertl

unread,
Jul 16, 2012, 11:32:49 AM7/16/12
to
steph...@mpeforth.com (Stephen Pelc) writes:
>I have very little against quotations except creeping complexity.

It's of about the same implementation complexity as "valuable"
extensions like N>R NR>. If your current locals implementation makes
it too complex to have locals in quotations, just support locals
without quotations. Hopefully at some point you will redesign your
locals implementation to remove some of the limits, but quotations
without locals are much better than no quotations.

I think that it is much easier to implement quotations than to keep
supporting return-stack tricks (which you are prepared to do).

>However, nearly all the arguments I see in favour of quotations
>are to do with syntactic sugar.

Sure, it is syntactic sugar. Sometimes syntactic sugar is valuable to
have. In this case it is. We don't want bitter programs, do we?

>Given the amount of work to implement quotations
>across all systems, it can be argued that we should go back
>to the traditional Forth position of accepting a bit of
>implementation-specific code;

Do I understand you correctly? To save a few lines of code in every
system, every program that needs quotations should include these lines
for all systems? How does this help? If I understood you
incorrectly, what did you mean?

Andrew Haley

unread,
Jul 16, 2012, 12:33:29 PM7/16/12
to
Stephen Pelc <steph...@mpeforth.com> wrote:
> On Mon, 16 Jul 2012 09:20:46 -0500, Andrew Haley
> <andr...@littlepinkcloud.invalid> wrote:
>
>>I would suggest that we implement and use quotations for a while and
>>see how they help. I've already posted the SwiftForth version as an
>>example.
>
> And we already have at least two naming conventions!
>
> :[ ... ]:
> and
> [: ... ;]
>
> I have slightly more sympathy with the second form.

That's just a Senior Moment of mine. :-)

Andrew.

Gerry Jackson

unread,
Jul 16, 2012, 12:38:52 PM7/16/12
to
Well it gets me straight to message 147 in that thread - written by me.

--
Gerry


Elizabeth D. Rather

unread,
Jul 16, 2012, 1:20:32 PM7/16/12
to
On 7/16/12 3:56 AM, Anton Ertl wrote:
> "A. K." <a...@nospam.org> writes:
>> IMO by using MARKER (and/or FORGET), most typical applications for
>> closures can be solved in standard Forth systems as well.
>
> What do you mean with "most typical applications for closures" and
> "solved"?
>
> Sure, instead of
>
> : foo { a b } ... [: ... a ... b ... ;] ... ;
>
> One can write
>
> : foo { a b } ...
> :noname postpone ...
> a postpone literal
> postpone ...
> b postpone literal
> postpone ...
> postpone ;
> ... ;
>
> and at some point, when you know you no longer need the anonymous
> definition, you can delete it with a marker.

What I don't understand is why you would want to do either of these
things. Why not just write a definition and call it?

Paul Rubin

unread,
Jul 16, 2012, 1:42:53 PM7/16/12
to
steph...@mpeforth.com (Stephen Pelc) writes:
> : foo ... [: some words ;] ... ;
> is equivalent to
> :noname some words ; Constant #temp#
> : foo ... #temp# ... ;

Do you mean

: foo ... ['] #temp# ... ;

?

Andrew Haley

unread,
Jul 16, 2012, 1:58:12 PM7/16/12
to
Gerry Jackson <ge...@jackson9000.fsnet.co.uk> wrote:
> On 16/07/2012 15:23, Andrew Haley wrote:
>> Gerry Jackson <ge...@jackson9000.fsnet.co.uk> wrote:
>>
>>> https://groups.google.com/group/comp.lang.forth/browse_frm/thread/c411311cc58807f3/8714c635d5758565?hl=en&lnk=gst&q=manorboy#8714c635d5758565
>>>
>>> And written in ANS Forth too.
>>
>> That doesn't get me to an article, just a very long thread.
>
> Well it gets me straight to message 147 in that thread - written by me.

It depends on the local settings. It's the "new vs old" Google
Groups.

The URL of the article itself is

https://groups.google.com/group/comp.lang.forth/msg/8714c635d5758565

It's an interesting idea, and as you say is suitbale for playing with,
but IMO explicitly having to delete closures is a non-starter for real
use, even with reference counting.

Andrew.

Stephen Pelc

unread,
Jul 16, 2012, 1:56:15 PM7/16/12
to
On Mon, 16 Jul 2012 15:32:49 GMT, an...@mips.complang.tuwien.ac.at
(Anton Ertl) wrote:

>>However, nearly all the arguments I see in favour of quotations
>>are to do with syntactic sugar.
>
>Sure, it is syntactic sugar. Sometimes syntactic sugar is valuable to
>have. In this case it is. We don't want bitter programs, do we?

Certainly not! Nice comment.

>>Given the amount of work to implement quotations
>>across all systems, it can be argued that we should go back
>>to the traditional Forth position of accepting a bit of
>>implementation-specific code;
>
>Do I understand you correctly? To save a few lines of code in every
>system, every program that needs quotations should include these lines
>for all systems? How does this help? If I understood you
>incorrectly, what did you mean?

At MPE, certain proposals are known as WIBNIs - "Wouldn't It
Be Nice If". We'll certainly play with quotations, we may even ship
them as source code. In the scheme of things, quotations are
not a high priority, especially given the lack of a specification.

Stephen Pelc

unread,
Jul 16, 2012, 2:06:49 PM7/16/12
to
No; #temp# returns the xt of the nameless word.

Stephen

Elizabeth D. Rather

unread,
Jul 16, 2012, 5:08:35 PM7/16/12
to
On 7/16/12 8:06 AM, Stephen Pelc wrote:
> On Mon, 16 Jul 2012 10:42:53 -0700, Paul Rubin
> <no.e...@nospam.invalid> wrote:
>
>> steph...@mpeforth.com (Stephen Pelc) writes:
>>> : foo ... [: some words ;] ... ;
>>> is equivalent to
>>> :noname some words ; Constant #temp#
>>> : foo ... #temp# ... ;
>>
>> Do you mean
>>
>> : foo ... ['] #temp# ... ;
>
> No; #temp# returns the xt of the nameless word.
>
> Stephen
>

What I'm not seeing is why you would want to do this, instead of:

: temp ... ;
: foo ... ['] temp ... ;

...which looks much cleaner to me.

Bernd Paysan

unread,
Jul 16, 2012, 5:37:51 PM7/16/12
to
Stephen Pelc wrote:
> At MPE, certain proposals are known as WIBNIs - "Wouldn't It
> Be Nice If". We'll certainly play with quotations, we may even ship
> them as source code.

You already ship them as source code. Well, I've written them, because
MINOS needs them, you ship them, as part of the VFX harness for MINOS.
They don't support locals within, because that was too complicated to
figure out how to do, and actually not necessary. In Gforth and
bigForth, it's a breeze to support locals within quotations.

I've changed my syntax to [: ;], so that's how it should look like (more
friendly smileys). I also support using this syntax in interpretation
mode (where it is equal to :noname ;), for consistency reasons.

The two major Forth derivates (PostScript and Factor) both have
quotations, Postscript using { } and Factor using [ ].

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://bernd-paysan.de/

Stephen Pelc

unread,
Jul 16, 2012, 5:38:52 PM7/16/12
to
On Mon, 16 Jul 2012 11:08:35 -1000, "Elizabeth D. Rather"
<era...@forth.com> wrote:

>What I'm not seeing is why you would want to do this, instead of:
>
>: temp ... ;
>: foo ... ['] temp ... ;
>
>...which looks much cleaner to me.

I don't disagree. I was just answering the question!

Marcel Hendrix

unread,
Jul 16, 2012, 5:47:42 PM7/16/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes Re: Quotations revisited

> m.a.m....@tue.nl wrote:
[..]
>> Can you be a little bit more specific? I think this is the LIST> you mean?

>> : list> ( thread -- element )
>> BEGIN @ dup WHILE dup r@ execute
>> REPEAT drop r> drop ;

>> How is it used? Quite intricate, that first '@'.

> : print-elements ( a -) list> .element ;

> .ELEMENT is called on every element.

Like this?


: ITERATE ( addr xt -- ) >R BEGIN DUP WHILE DUP @ SWAP CELL+ R@ EXECUTE REPEAT DROP -R ;

0 VALUE data
: LINK, ALIGN HERE data , TO data ;

: privatedata1 ( -- addr )
[: [ 0 TO data
LINK, ," ! "
LINK, ," World"
LINK, ," Hello, "
] ;] drop [ data ] LITERAL ;

: privatedata2 ( -- addr )
[: [ 0 TO data
LINK, ," ? "
LINK, ," Wereld"
LINK, ," Hallo, "
] ;] drop [ data ] LITERAL ;

: .elements ( addr -- ) [: count type ;] ITERATE ;
: #elements ( addr -- ) 0 local #cnt [: drop 1 +TO #cnt ;] ITERATE #cnt . ." elements." ;
: .dump ( addr -- ) [: #20 dump ;] ITERATE ;
: .bytes ( addr -- ) 0 local #cnt [: c@ +TO #cnt ;] ITERATE #cnt . ." bytes used." ;

\ FORTH> privatedata2 .elements Hallo, Wereld? ok
\ FORTH> privatedata1 .elements Hello, World! ok
\ FORTH> privatedata1 #elements 3 elements. ok
\ FORTH> privatedata2 #elements 3 elements. ok
\ FORTH> privatedata2 .bytes 15 bytes used. ok
\ FORTH> privatedata1 .bytes 14 bytes used. ok

-marcel

Albert van der Horst

unread,
Jul 16, 2012, 6:53:16 PM7/16/12
to
In article <2012Jul1...@mips.complang.tuwien.ac.at>,
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>steph...@mpeforth.com (Stephen Pelc) writes:
>>On Sat, 14 Jul 2012 15:55:03 +0200, m...@iae.nl (Marcel Hendrix) wrote:
>>Given the increasing popularity of talking about "quotations" and
>>"closures", would someone like to specify them in Forth terminology.
>
>A simple quotation is an anonymous colon definition that is defined
>inside a colon definition or quotation. It has no access to locals of
>the enclosing definitions.

As a definition that is probably not sufficient. We have anonymous
colon definitions ( :NONAME ) , but they are only usable because
they leave and xt. How that works out "inside a colon definition"
is not clear to me.

Is
: AAP 1 2 DROP { 3 5 SWAP . } EXECUTE 2 * ;
equivalent to
: AAP 1 2 DROP 3 5 SWAP . 2 * ;
??

>
>A closure is like a quotation, except that it has (read and write)
>access to the locals of the enclosing definitions.

Closures are a more familiar concept because they are well defined
in other languages.

<SNIP>

>
>- anton
>--

Groetjes Albert

--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

Bernd Paysan

unread,
Jul 16, 2012, 6:29:59 PM7/16/12
to
Stephen Pelc wrote:

> On Mon, 16 Jul 2012 11:08:35 -1000, "Elizabeth D. Rather"
> <era...@forth.com> wrote:
>
>>What I'm not seeing is why you would want to do this, instead of:
>>
>>: temp ... ;
>>: foo ... ['] temp ... ;
>>
>>...which looks much cleaner to me.
>
> I don't disagree. I was just answering the question!

It was about equivalence. The code above is not equivalent, as temp is
a named word - quotations are unnamed.

That I still have to use a constant, so the :noname ; still sort-of gets
a name, is unfortunately necessary, so the equivalence is still broken.

Elizabeth D. Rather

unread,
Jul 16, 2012, 6:38:19 PM7/16/12
to
On 7/16/12 12:29 PM, Bernd Paysan wrote:
> Stephen Pelc wrote:
>
>> On Mon, 16 Jul 2012 11:08:35 -1000, "Elizabeth D. Rather"
>> <era...@forth.com> wrote:
>>
>>> What I'm not seeing is why you would want to do this, instead of:
>>>
>>> : temp ... ;
>>> : foo ... ['] temp ... ;
>>>
>>> ...which looks much cleaner to me.
>>
>> I don't disagree. I was just answering the question!
>
> It was about equivalence. The code above is not equivalent, as temp is
> a named word - quotations are unnamed.

Why does that matter?

> That I still have to use a constant, so the :noname ; still sort-of gets
> a name, is unfortunately necessary, so the equivalence is still broken.

Why is it important not to have a name? Names are useful! In
cross-compilers, it's possible to specify whether a definition will have
a name in the target. In resident systems, I don't see that having a
name is a liability.

BruceMcF

unread,
Jul 16, 2012, 10:59:32 PM7/16/12
to
On Monday, July 16, 2012 6:53:16 PM UTC-4, Albert van der Horst wrote:

> As a definition that is probably not sufficient. We have
> anonymous colon definitions ( :NONAME ) , but they are
> only usable because they leave an xt. How that works out
> "inside a colon definition" is not clear to me.

It jumps over the quotation and leaves an xt.


> Is
> : AAP 1 2 DROP { 3 5 SWAP . } EXECUTE 2 * ;
> equivalent to
> : AAP 1 2 DROP 3 5 SWAP . 2 * ;

Yes.

Also:
: AAP [: 3 5 SWAP . ;] DUP EXECUTE EXECUTE ;

is equivalent to:
: AAP 3 5 SWAP . 3 5 SWAP . ;

... though of course neither of those are all that useful.

: foo [: set-up bar clean-up ;] CATCH ;
... may be more useful, if the error handling following the CATCH is also included.

> ??
>
> &gt;
> &gt;A closure is like a quotation, except that it has (read and write)
> &gt;access to the locals of the enclosing definitions.
>
> Closures are a more familiar concept because they are well defined
> in other languages.
>
> &lt;SNIP&gt;
>
> &gt;
> &gt;- anton
> &gt;--
>
> Groetjes Albert
>
> --
> --
> Albert van der Horst, UTRECHT,THE NETHERLANDS
> Economic growth -- being exponential -- ultimately falters.
> albert@spe&amp;ar&amp;c.xs4all.nl &amp;=n http://home.hccnet.nl/a.w.m.van.der.horst

Elizabeth D. Rather

unread,
Jul 16, 2012, 11:04:56 PM7/16/12
to
On 7/16/12 4:59 PM, BruceMcF wrote:
...
> : foo [: set-up bar clean-up ;] CATCH ;
> ... may be more useful, if the error handling following the CATCH is also included.

That's the first example I've seen that actually makes a little sense
(assuming, of course, that the error handling code follows).

Anton Ertl

unread,
Jul 17, 2012, 2:51:27 AM7/17/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:
>On 7/16/12 4:59 PM, BruceMcF wrote:
>...
>> : foo [: set-up bar clean-up ;] CATCH ;
>> ... may be more useful, if the error handling following the CATCH is also included.
>
>That's the first example I've seen that actually makes a little sense
>(assuming, of course, that the error handling code follows).

I posted such an example already in 2009 (with slightly different syntax):

|Date: Tue, 27 Oct 2009 12:02:10 GMT
|Message-ID: <2009Oct2...@mips.complang.tuwien.ac.at>
...
|Here's one example I have: Reusable code often needs CATCH to ensure
|that all exits from a word go through some common cleanup code. CATCH
|takes an xt, and in Forth-94 that often leads to adding a helper
|definition, e.g.:
|
|: hex.-helper ( u -- )
| hex u. ;
|
|: hex. ( u -- )
| base @ >r
| ['] hex.-helper catch
| r> base ! throw ;
|
|With :[ ... ]; (or similar syntax) we can put the helper definition
|right where it is used, and don't need to name it:
|
|: hex. ( u -- )
| base @ >r
| :[ hex u. ]; catch
| r> base ! throw ;
|
|Shorter, and IMO easier to read.

Concerning "Names are useful": That's not the case for HEX.-HELPER
here, as indicated by the actual name. Having that name is just an
artifact of not having quotations.

Elizabeth D. Rather

unread,
Jul 17, 2012, 3:39:34 AM7/17/12
to
Less useful, IMO, because H. has been around in a lot of systems,
including Open Firmware, for a long time, defined simply as:

: H. ( n -- ) BASE @ HEX U. BASE ! ;

No need for CATCH/THROW or funny business. Bruce's example at least had
the virtue of suggesting a scenario that would be reasonably one-time
code, and hence not worth making into a separate definition.

Anton Ertl

unread,
Jul 17, 2012, 3:48:34 AM7/17/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:
>On 7/16/12 8:51 PM, Anton Ertl wrote:
>> |: hex. ( u -- )
>> | base @ >r
>> | :[ hex u. ]; catch
>> | r> base ! throw ;
>> |
>> |Shorter, and IMO easier to read.
...
>Less useful, IMO, because H. has been around in a lot of systems,
>including Open Firmware, for a long time, defined simply as:
>
>: H. ( n -- ) BASE @ HEX U. BASE ! ;

That prints the base in hex, if everything works fine. I guess you
mean:

: H. ( n -- ) BASE @ HEX swap U. BASE ! ;

>No need for CATCH/THROW or funny business.

But if somebody types Ctrl-C (user interrupt) while U. is working,
BASE is not restored. That's why the CATCH/THROW is in HEX.

There is still a short window of vulnerability between CATCH and !,
but that's the best we can do in standard Forth. Gforth has a feature
for that, and this feature and other ideas are discussed in:

@InProceedings{ertl08euroforth,
author = {M. Anton Ertl},
title = {Cleaning up After Yourself},
crossref = {euroforth08},
pages = {35--38},
url = {http://www.complang.tuwien.ac.at/anton/euroforth/ef08/papers/ertl.pdf},
psurl = {http://www.complang.tuwien.ac.at/papers/ertl08euroforth.ps.gz},
OPTnote = {not refereed},
abstract = {Performing cleanup actions such as restoring a
variable or closing a file used to be impossible to
guarantee in Forth before Forth-94 gave us
\code{catch}. Even with \code{catch}, the cleanup
code can be skipped due to user interrupts if you
are unlucky. We introduce a construct that
guarantees that the cleanup code is always
completed. We also discuss a cheaper implementation
approach for cleanup code than using a full
exception frame.}

Elizabeth D. Rather

unread,
Jul 17, 2012, 4:24:36 AM7/17/12
to
On 7/16/12 9:48 PM, Anton Ertl wrote:
> "Elizabeth D. Rather" <era...@forth.com> writes:
>> On 7/16/12 8:51 PM, Anton Ertl wrote:
>>> |: hex. ( u -- )
>>> | base @ >r
>>> | :[ hex u. ]; catch
>>> | r> base ! throw ;
>>> |
>>> |Shorter, and IMO easier to read.
> ...
>> Less useful, IMO, because H. has been around in a lot of systems,
>> including Open Firmware, for a long time, defined simply as:
>>
>> : H. ( n -- ) BASE @ HEX U. BASE ! ;
>
> That prints the base in hex, if everything works fine. I guess you
> mean:
>
> : H. ( n -- ) BASE @ HEX swap U. BASE ! ;

Oops! Of course. Too late at night, here!

>> No need for CATCH/THROW or funny business.
>
> But if somebody types Ctrl-C (user interrupt) while U. is working,
> BASE is not restored. That's why the CATCH/THROW is in HEX.

Really, pretty hard to do. Have you ever succeeded?

Andrew Haley

unread,
Jul 17, 2012, 5:14:37 AM7/17/12
to
Marcel Hendrix <m...@iae.nl> wrote:
> Andrew Haley <andr...@littlepinkcloud.invalid> writes Re: Quotations revisited
>
>> m.a.m....@tue.nl wrote:
> [..]
>>> Can you be a little bit more specific? I think this is the LIST> you mean?
>
>>> : list> ( thread -- element )
>>> BEGIN @ dup WHILE dup r@ execute
>>> REPEAT drop r> drop ;
>
>>> How is it used? Quite intricate, that first '@'.
>
>> : print-elements ( a -) list> .element ;
>
>> .ELEMENT is called on every element.
>
> Like this?

...

> : #elements ( addr -- ) 0 local #cnt [: drop 1 +TO #cnt ;] ITERATE #cnt . ." elements." ;

Not exactly, no, because the quotation is supposed to have its own
locals. If you want to pass data to the quotation you're supposed to
use the stack. As God and Nature intended. ;-)

Andrew.

Andrew Haley

unread,
Jul 17, 2012, 5:20:47 AM7/17/12
to
Elizabeth D. Rather <era...@forth.com> wrote:
> On 7/16/12 12:29 PM, Bernd Paysan wrote:
>> Stephen Pelc wrote:
>>
>>> On Mon, 16 Jul 2012 11:08:35 -1000, "Elizabeth D. Rather"
>>> <era...@forth.com> wrote:
>>>
>>>> What I'm not seeing is why you would want to do this, instead of:
>>>>
>>>> : temp ... ;
>>>> : foo ... ['] temp ... ;
>>>>
>>>> ...which looks much cleaner to me.
>>>
>>> I don't disagree. I was just answering the question!
>>
>> It was about equivalence. The code above is not equivalent, as temp is
>> a named word - quotations are unnamed.
>
> Why does that matter?
>
>> That I still have to use a constant, so the :noname ; still sort-of gets
>> a name, is unfortunately necessary, so the equivalence is still broken.
>
> Why is it important not to have a name? Names are useful! In
> cross-compilers, it's possible to specify whether a definition will have
> a name in the target. In resident systems, I don't see that having a
> name is a liability.

So why does ACTIVATE not take a task and an xt? Why does DOES> not
take an xt? I'm pretty sure it's all to do with notational
convenience.

Andrew.

Alex McDonald

unread,
Jul 17, 2012, 6:14:20 AM7/17/12
to
> Los Angeles, CA 90045http://www.forth.com
>
> "Forth-based products and Services for real-time
> applications since 1973."
> ==================================================


Combining TRAVERSE-WORDLIST and quotations;

: (count-words) ( n node -- n true )
drop 1+ true ;

: count-words ( wid -- n )
0 ['] (count-words)
-rot traverse-wordlist drop ;

becomes

: count-words ( wid -- n )
0
[: ( n node ) drop 1+ true ;]
-rot traverse-wordlist drop ;

Traversal, iteration and so on benefit (IMHO) from such a
nomenclature. There are a significant number of (NAME) or _NAME
helpers in the context of Win32Forth that simply clutter up the
dictionary and serve no secondary purpose. The reaction has been to
stuff them in an ad-hoc manner into a hidden wordlist, which pushes
the problem elsewhere.

Anton Ertl

unread,
Jul 17, 2012, 6:48:35 AM7/17/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:
>> But if somebody types Ctrl-C (user interrupt) while U. is working,
>> BASE is not restored. That's why the CATCH/THROW is in HEX.
>
>Really, pretty hard to do. Have you ever succeeded?

: H. ( n -- ) BASE @ HEX swap U. BASE ! ; ok
: test decimal 1000000 0 do i h. loop ; ok
test
...
4FEF2 4FEF3 4FEF4 4FEF5 4FEF6 4FEF7 4FEF8 4FEF9
:3: User interrupt
>>>test<<<
Backtrace:
$7FFFF69F1E70 write-file
$7FFFF69F2C68 type
$7FFFF69F2DE0 ud.r
$7FFFF69F2E90 ud.
$7FFFF6A44338 u.
$7FFFF6A443D0 H.
$501A4
$F4240
base @ decimal . 16 ok

First try.

You can see in the backtrace where the user interrupt happened.

Alex McDonald

unread,
Jul 17, 2012, 6:21:40 AM7/17/12
to
On Jul 17, 10:20 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:
I suspect that, had DOES> not existed and was being discussed here as
a proposal, it would not receive much support for several reasons.

Albert van der Horst

unread,
Jul 17, 2012, 8:22:13 AM7/17/12
to
In article <G9Odner46_fHS5nN...@supernews.com>,
Elizabeth D. Rather <era...@forth.com> wrote:
>On 7/16/12 4:59 PM, BruceMcF wrote:
>...
>> : foo [: set-up bar clean-up ;] CATCH ;
>> ... may be more useful, if the error handling following the CATCH is also included.
>
>That's the first example I've seen that actually makes a little sense
>(assuming, of course, that the error handling code follows).

Now I can find more examples that make some sense.

My words looks like this

: WORDS ['] ID. CONTEXT @ FOR-WORDS ;

It would be reasonable to want words on a separate line:
: WORDS_ [: ID. CR ;] CONTEXT @ FOR-WORDS ;

This triggers the question whether the following is supposed
to work:

[: ID. CR ;] CONTEXT @ FOR-WORDS

and how it differs from

:NONAME ID. CR ; CONTEXT @ FOR-WORDS


>
>Cheers,
>Elizabeth

Groetjes Albert

--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

Andrew Haley

unread,
Jul 17, 2012, 8:30:13 AM7/17/12
to
Albert van der Horst <alb...@spenarnc.xs4all.nl> wrote:
> In article <G9Odner46_fHS5nN...@supernews.com>,
> Elizabeth D. Rather <era...@forth.com> wrote:
>>On 7/16/12 4:59 PM, BruceMcF wrote:
>>...
>>> : foo [: set-up bar clean-up ;] CATCH ;
>>> ... may be more useful, if the error handling following the CATCH is also included.
>>
>>That's the first example I've seen that actually makes a little sense
>>(assuming, of course, that the error handling code follows).
>
> Now I can find more examples that make some sense.
>
> My words looks like this
>
> : WORDS ['] ID. CONTEXT @ FOR-WORDS ;
>
> It would be reasonable to want words on a separate line:
> : WORDS_ [: ID. CR ;] CONTEXT @ FOR-WORDS ;
>
> This triggers the question whether the following is supposed
> to work:
>
> [: ID. CR ;] CONTEXT @ FOR-WORDS

I don't think that anyone has proposed it, because:

> and how it differs from
>
> :NONAME ID. CR ; CONTEXT @ FOR-WORDS

Does quite nicely. Indeed, you could argue that quotations are an
indefintion version of :NONAME .

Andrew.

Alex McDonald

unread,
Jul 17, 2012, 9:34:04 AM7/17/12
to
On Jul 17, 1:30 pm, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:
> Albert van der Horst <alb...@spenarnc.xs4all.nl> wrote:
>
>
>
>
>
>
>
>
>
> > In article <G9Odner46_fHS5nNnZ2dnUVZ_redn...@supernews.com>,
> > Elizabeth D. Rather <erat...@forth.com> wrote:
> >>On 7/16/12 4:59 PM, BruceMcF wrote:
> >>...
> >>>     : foo [: set-up bar clean-up ;] CATCH ;
> >>> ... may be more useful, if the error handling following the CATCH is also included.
>
> >>That's the first example I've seen that actually makes a little sense
> >>(assuming, of course, that the error handling code follows).
>
> > Now I can find more examples that make some sense.
>
> > My words looks like this
>
> > : WORDS   ['] ID. CONTEXT @ FOR-WORDS ;
>
> > It would be reasonable to want words on a separate line:
> > : WORDS_  [: ID. CR ;] CONTEXT @ FOR-WORDS ;
>
> > This triggers the question whether the following is supposed
> > to work:
>
> > [: ID. CR ;] CONTEXT @ FOR-WORDS
>
> I don't think that anyone has proposed it, because:
>
> > and how it differs from
>
> > :NONAME ID. CR ; CONTEXT @ FOR-WORDS
>
> Does quite nicely.  Indeed, you could argue that quotations are an
> indefintion version of :NONAME .
>
> Andrew.

Then perhaps it should be [:noname and ;] ?

The implementation is trivial, the intention is clear, and it's very
useful in eliminating "noise" words. I like this!

STC Experimental 32bit: 0.06.02 Build: 36
: [:
postpone ahead
over swap ( carnal knowledge about control stack )
; immediate ok
: ;]
postpone unnest
postpone then
postpone literal
; immediate ok
ok
: word-count 0 [: drop 1+ true ;] rot voc-iterate ; ok
ok
' forth word-count . 1153 ok


see word-count
: word-count ( ? -- ? )
\ std call compiles; code=$41B616 len=63 type=20
\ defined in (console)
( $0 ) mov dword { $-4 ebp } eax \ 8945FC
( $3 ) and eax $0 \ 83E000
( $6 ) sub ebp $4 \ 83ED04
( $9 ) jmp ' word-count $21 + \ E913000000
( $E ) mov eax dword { $0 ebp } \ 8B4500
( $11 ) add ebp $4 \ 83C504
( $14 ) add eax $1 \ 83C001
( $17 ) mov dword { $-4 ebp } eax \ 8945FC
( $1A ) or eax $-1 \ 83C8FF
( $1D ) sub ebp $4 \ 83ED04
( $20 ) ret \ C3
( $21 ) mov dword { $-4 ebp } eax \ 8945FC
( $24 ) mov eax ' word-count $E + \ B824B64100
( $29 ) sub ebp $4 \ 83ED04
( $2C ) mov ecx dword { $0 ebp } \ 8B4D00
( $2F ) mov edx dword { $4 ebp } \ 8B5504
( $32 ) mov dword { $0 ebp } eax \ 894500
( $35 ) mov dword { $4 ebp } ecx \ 894D04
( $38 ) mov eax edx \ 8BC2
( $3A ) jmp ' voc-iterate \ E9E58DFEFF
( $3F ) ret \ C3 ( end ) ok

Andrew Haley

unread,
Jul 17, 2012, 10:04:22 AM7/17/12
to
Alex McDonald <bl...@rivadpm.com> wrote:
> On Jul 17, 1:30?pm, Andrew Haley <andre...@littlepinkcloud.invalid>
> wrote:
>> you could argue that quotations are an
>> indefintion version of :NONAME .
>
> Then perhaps it should be [:noname and ;] ?

Naah: longer, fuglier. :-)

> The implementation is trivial, the intention is clear, and it's very
> useful in eliminating "noise" words. I like this!
>
> STC Experimental 32bit: 0.06.02 Build: 36
> : [:
> postpone ahead
> over swap ( carnal knowledge about control stack )
> ; immediate ok
> : ;]
> postpone unnest
> postpone then
> postpone literal
> ; immediate ok

Modulo RECURSE and locals, that's what all of them seem to look like.
My first SwiftForth version was:

icode (quotation)
here $400 + call
ret end-code

: [: postpone (quotation) postpone begin ; immediate
: ;] postpone exit postpone then
postpone r> postpone code> ; immediate

The big difference here is that SwiftForth is PIC, so you have to do a
little work at runtime to find out where the quotation is.

Andrew.

Anton Ertl

unread,
Jul 17, 2012, 9:49:49 AM7/17/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:
>On 7/16/12 3:56 AM, Anton Ertl wrote:
>> "A. K." <a...@nospam.org> writes:
>>> IMO by using MARKER (and/or FORGET), most typical applications for
>>> closures can be solved in standard Forth systems as well.
>>
>> What do you mean with "most typical applications for closures" and
>> "solved"?
>>
>> Sure, instead of
>>
>> : foo { a b } ... [: ... a ... b ... ;] ... ;
>>
>> One can write
>>
>> : foo { a b } ...
>> :noname postpone ...
>> a postpone literal
>> postpone ...
>> b postpone literal
>> postpone ...
>> postpone ;
>> ... ;
>>
>> and at some point, when you know you no longer need the anonymous
>> definition, you can delete it with a marker.
>
>What I don't understand is why you would want to do either of these
>things. Why not just write a definition and call it?

What do you mean? Please post some code that would replace this
example.

Or maybe I should give a more concrete example:

: val {: x -- to-xt xt :}
[: to x ;] [: x ;] ;

5 val alias foo alias to-foo
8 val alias bar alias to-bar
foo . \ prints 5
bar . \ prints 8
7 to-foo
bar . \ prints 8
foo . \ prints 7

You will say that we have VALUE already, but keep in mind that this is
an example designed to make use of a few things you already know, to
make it easier to understand. There are all things you can do with
closures, e.g., something similar to object-oriented programming.
There are books about this stuff (I would start with "Structure and
Interpretation of Computer Programs", which contains nice examples).

Still, while it would be cool, I don't think that the benefits are
worth the costs.

Coos Haak

unread,
Jul 17, 2012, 11:39:21 AM7/17/12
to
Op Tue, 17 Jul 2012 04:14:37 -0500 schreef Andrew Haley:
With a rewrite of ITERATE that's possible

: ITERATE ( list xt -- )
>R BEGIN @ DUP WHILE R@ OVER >R EXECUTE R> REPEAT DROP RDROP ;

: #elements ( addr -- ) 0 swap [: drop 1+ ;] iterate . ." elements " ;

--
Coos

CHForth, 16 bit DOS applications
http://home.hccnet.nl/j.j.haak/forth.html

Andrew Haley

unread,
Jul 17, 2012, 1:18:45 PM7/17/12
to
Coos Haak <chf...@hccnet.nl> wrote:
> Op Tue, 17 Jul 2012 04:14:37 -0500 schreef Andrew Haley:
>
>> Marcel Hendrix <m...@iae.nl> wrote:
>>> Andrew Haley <andr...@littlepinkcloud.invalid> writes Re: Quotations revisited
>>>> .ELEMENT is called on every element.
>>>
>>> Like this?
>>
>> ...
>>
>>>: #elements ( addr -- ) 0 local #cnt [: drop 1 +TO #cnt ;] ITERATE #cnt . ." elements." ;
>>
>> Not exactly, no, because the quotation is supposed to have its own
>> locals. If you want to pass data to the quotation you're supposed to
>> use the stack. As God and Nature intended. ;-)
>
> With a rewrite of ITERATE that's possible
>
> : ITERATE ( list xt -- )
> >R BEGIN @ DUP WHILE R@ OVER >R EXECUTE R> REPEAT DROP RDROP ;
>
> : #elements ( addr -- ) 0 swap [: drop 1+ ;] iterate . ." elements " ;

Precisely so. A well-designed iterator leaves the stack clean beneath
the data it passes to the word being iterated over.

So, as another example, to total the COST field of every element of a
list you'd have

0 swap [: cost @ + ;] list>

And, for the skeptics reading, I really do think this is easier to
read than iterating over the list with a WHILE loop, if not very much
better than specially-crafted compiling words.

Indidentally, I don't much like the name LIST> , but I'm at a loss to
think of a better way to name an interator.

Andrew.

Bernd Paysan

unread,
Jul 17, 2012, 1:58:21 PM7/17/12
to
Elizabeth D. Rather wrote:
>> It was about equivalence. The code above is not equivalent, as temp
>> is a named word - quotations are unnamed.
>
> Why does that matter?

It's to illustrate a point. A quotation is unnamed.

>> That I still have to use a constant, so the :noname ; still sort-of
>> gets a name, is unfortunately necessary, so the equivalence is still
>> broken.
>
> Why is it important not to have a name? Names are useful! In
> cross-compilers, it's possible to specify whether a definition will
> have a name in the target. In resident systems, I don't see that
> having a name is a liability.

Ok, let me illustrate how quotations are used in MINOS: An object (e.g.
a button) has some actions being done, e.g. when you click on it. These
actions are defined as quotations. Should they have a name? Sometimes,
yes - when it's a common factor. More often, no, because it's a one-
time thing. If they always need to have a name, Theseus would have to
invent one.

Quotations open up another style of programming, which apparently
doesn't happen when you have to give these snippets a name. As
wittnessed by Factor and Postscript, which have quotations, and use them
regularly in places where Forth doesn't have an equivalent word which
takes an xt.

Andrew Haley

unread,
Jul 17, 2012, 2:05:09 PM7/17/12
to
Bernd Paysan <bernd....@gmx.de> wrote:
>
> Quotations open up another style of programming, which apparently
> doesn't happen when you have to give these snippets a name. As
> wittnessed by Factor and Postscript, which have quotations, and use
> them regularly in places where Forth doesn't have an equivalent word
> which takes an xt.

That's the key to it, I think.

Andrew.

Bernd Paysan

unread,
Jul 17, 2012, 2:09:09 PM7/17/12
to
Andrew Haley wrote:
>> This triggers the question whether the following is supposed
>> to work:
>>
>> [: ID. CR ;] CONTEXT @ FOR-WORDS
>
> I don't think that anyone has proposed it.

There's no need to do this, but the definition in bigForth works when
used that way (and the VFXharness one, too). It's a natural way to
define [:'s (currently undefined) interpretation semantics as extension
beyond a possible standard.

Elizabeth D. Rather

unread,
Jul 17, 2012, 2:19:41 PM7/17/12
to
On 7/17/12 12:48 AM, Anton Ertl wrote:
> "Elizabeth D. Rather" <era...@forth.com> writes:
>>> But if somebody types Ctrl-C (user interrupt) while U. is working,
>>> BASE is not restored. That's why the CATCH/THROW is in HEX.
>>
>> Really, pretty hard to do. Have you ever succeeded?
>
> : H. ( n -- ) BASE @ HEX swap U. BASE ! ; ok
> : test decimal 1000000 0 do i h. loop ; ok
> test
> ...
> 4FEF2 4FEF3 4FEF4 4FEF5 4FEF6 4FEF7 4FEF8 4FEF9
> :3: User interrupt
>>>> test<<<
> Backtrace:
> $7FFFF69F1E70 write-file
> $7FFFF69F2C68 type
> $7FFFF69F2DE0 ud.r
> $7FFFF69F2E90 ud.
> $7FFFF6A44338 u.
> $7FFFF6A443D0 H.
> $501A4
> $F4240
> base @ decimal . 16 ok
>
> First try.
>
> You can see in the backtrace where the user interrupt happened.

That's a pathological example because of the massively iterated short
loop. H. isn't used that way in real-world code.

I have no problem with your putting in unnecessary CATCHes, just with
inventing obscure structures in order to do so.

Marcel Hendrix

unread,
Jul 17, 2012, 2:26:45 PM7/17/12
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes Re: Quotations revisited

> Marcel Hendrix <m...@iae.nl> wrote:
>> Andrew Haley <andr...@littlepinkcloud.invalid> writes Re: Quotations revisited
[..]
>> : #elements ( addr -- ) 0 local #cnt [: drop 1 +TO #cnt ;] ITERATE #cnt . ." elements." ;

> Not exactly, no, because the quotation is supposed to have its own
> locals. If you want to pass data to the quotation you're supposed to
> use the stack. As God and Nature intended. ;-)

Passing data in and out is not the problem here.

My extended example demonstrates that it quite natural for a quotation
to need semi-permanent storage. A local local doesn't provide that,
but a local of the enclosing definition works fine. Surely, one wouldn't
go through the trouble of implementing quotations if all their variables
have to be named globals :-)

I think that quotations don't offer much if they can't access outer
locals. Not having their own private locals and RECURSE is OK with
me; quotations won't have long complicated multi-page definitions,
and they can trivially call themselves by the return token (especially
if this is accessible in an outer local :-)

-marcel


Aleksej Saushev

unread,
Jul 17, 2012, 5:31:37 PM7/17/12
to
Thus, if I dump a big memory region with the "h." above or with a loop
enclosed into "base @ hex ... base !", will that be "pathological" too?


--
HE CE3OH...

Alex McDonald

unread,
Jul 18, 2012, 10:07:25 AM7/18/12
to
[snipped]

I like it even more. Supporting (LOCAL) is one PITA in my Forth, and
the code is convoluted by lots of little extraneous supporting words
that clutter the implementation. This style of quotation makes the
whole thing so much clearer, as the definitions are directly in the
code.

: "var [: create , does> @ ;] execute-parsing ; ok
10 s" var1" "var ok
var1 . 10 ok



Coos Haak

unread,
Jul 18, 2012, 11:43:11 AM7/18/12
to
Op Wed, 18 Jul 2012 07:07:25 -0700 (PDT) schreef Alex McDonald:
: "var postfix create , does> @ ;
10 s" var1" "var

Alex McDonald

unread,
Jul 18, 2012, 12:29:09 PM7/18/12
to

Alex McDonald

unread,
Jul 18, 2012, 1:18:54 PM7/18/12
to
On Jul 18, 4:43 pm, Coos Haak <chfo...@hccnet.nl> wrote:
On inspection that's the equivalent of

: "var ['] create execute-parsing , does> @ ;

The advantage of [: ;] is flexibility; it works anywhere you need an
XT.

: "var 2dup ['] create execute-parsing cr ." created variable " type
dup [: , does> @ ;] execute ." with the value " . ; ok
10 s" test" "var
created variable test with the value 10 ok
test . 10 ok




Coos Haak

unread,
Jul 18, 2012, 2:59:46 PM7/18/12
to
Op Wed, 18 Jul 2012 09:29:09 -0700 (PDT) schreef Alex McDonald:

> On Jul 18, 4:43�pm, Coos Haak <chfo...@hccnet.nl> wrote:
<snip>
>>>: "var [: create , does> @ ;] execute-parsing ; �ok
>>> 10 s" var1" "var �ok
>>> var1 . 10 �ok
>>
>>: "var postfix create , does> @ ;
>> 10 s" var1" "var
>>
>> --
>> Coos
>>
>> CHForth, 16 bit DOS applicationshttp://home.hccnet.nl/j.j.haak/forth.html
>
>
> Long link;
>
> http://groups.google.com/group/comp.lang.forth/browse_frm/thread/695e2f8cda2ebf14/525cc0cb44fa92c9?lnk=gst&q=postfix#525cc0cb44fa92c9
>
> I'm presuming POSTFIX is a parsing word.

No, it's sneakier, it patches HEADER (factor of CREATE etc.) to accept a
string on the stack to create the name. After that it 'unpatches' to return
HEADER to parse the next time it is used.

"
( PARSE-NAME or NAME , the first word in HEADER is replaced )
:NONAME
['] PARSE-NAME [ ' HEADER >BODY @ ] LITERAL L!
; TMP !

\G The next invocation of $r{kernel,HEADER} or a word containing
\G HEADER will not use $r{kernel,PARSE-NAME} to get the name of the
\G definition but expects a string c-addr u on the stack.
: POSTFIX ( -- ) \ POSTFIX
[ TMP @ ] LITERAL [ ' HEADER >BODY @ ] LITERAL L!
;
"

The bodies of colon definitions are accessed with L@ and L! because they
are a in a different segment and can't be accessed with @ and !

Coos Haak

unread,
Jul 18, 2012, 3:14:55 PM7/18/12
to
Op Wed, 18 Jul 2012 20:59:46 +0200 schreef Coos Haak:
Or with CO (couroutine call):

: POSTFIX
['] NOOP [ ' HEADER >BODY @ ] LITERAL L!
CO
['] PARSE-NAME [ ' HEADER >BODY @ ] LITERAL L! ;

But, I like quotations too.

Anton Ertl

unread,
Jul 19, 2012, 12:05:35 PM7/19/12
to
Coos Haak <chf...@hccnet.nl> writes:
>Op Wed, 18 Jul 2012 09:29:09 -0700 (PDT) schreef Alex McDonald:
>> I'm presuming POSTFIX is a parsing word.
>
>No, it's sneakier, it patches HEADER (factor of CREATE etc.) to accept a
>string on the stack to create the name. After that it 'unpatches' to return
>HEADER to parse the next time it is used.

In order to make use of that all defining words have to be written
such that there is no internal data on the stack when HEADER is
called.

Gforth has a word NEXTNAME ( c-addr u -- ) that works similarly, but
you pass the string to NEXTNAME and it is then used for the name of
the next defined word.

However, EXECUTE-PARSING makes NEXTNAME and PREFIX mostly unnecessary
and is cleaner and more general.

Anton Ertl

unread,
Jul 19, 2012, 12:11:31 PM7/19/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:
>On 7/17/12 12:48 AM, Anton Ertl wrote:
>> "Elizabeth D. Rather" <era...@forth.com> writes:
>>>> But if somebody types Ctrl-C (user interrupt) while U. is working,
>>>> BASE is not restored. That's why the CATCH/THROW is in HEX.
>>>
>>> Really, pretty hard to do. Have you ever succeeded?
>>
>> : H. ( n -- ) BASE @ HEX swap U. BASE ! ; ok
>> : test decimal 1000000 0 do i h. loop ; ok
>> test
...
>That's a pathological example because of the massively iterated short
>loop. H. isn't used that way in real-world code.

You may consider I/O-bound code pathological, but it is not at all
unusual in the real world. A simple example is DUMP. I would hope
that this unsafe H. is not used in real-world code, but I fear that it
is.

Anton Ertl

unread,
Jul 19, 2012, 12:21:37 PM7/19/12
to
m...@iae.nl (Marcel Hendrix) writes:
>My extended example demonstrates that it quite natural for a quotation
>to need semi-permanent storage. A local local doesn't provide that,
>but a local of the enclosing definition works fine. Surely, one wouldn't
>go through the trouble of implementing quotations if all their variables
>have to be named globals :-)

What trouble? And yes, quotations that do not have any locals access
at all are useful; sure, it's just the usefulness of convenience, but
it's still useful.

>I think that quotations don't offer much if they can't access outer
>locals.

If you want to use locals of the enclosing defintions, you want
closures. Yes, one can do cool things with closures, but the
implementation cost is very high. IMO too high, but if you want to do
it, go ahead. Maybe you can convince us that the cost is low enough
and the benefits are high enough that we will all go for it.

>Not having their own private locals and RECURSE is OK with
>me; quotations won't have long complicated multi-page definitions,
>and they can trivially call themselves by the return token (especially
>if this is accessible in an outer local :-)

Making RECURSE work in quotations is pretty easy.

Anton Ertl

unread,
Jul 19, 2012, 1:00:17 PM7/19/12
to
Alex McDonald <bl...@rivadpm.com> writes:
>: "var [: create , does> @ ;] execute-parsing ; ok

Somebody asked some time ago if there is anything beyond RECURSE and
locals that has to be considered. I thought about mentioning DOES>,
but did not expect anyone to use it. I have been proved wrong
quickly.

Alex McDonald

unread,
Jul 19, 2012, 6:34:16 PM7/19/12
to
On Jul 19, 6:00 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
wrote:
I'm full of surprises. It just worked, btw; no changes were needed to
support it.

Elizabeth D. Rather

unread,
Jul 19, 2012, 6:41:14 PM7/19/12
to
On 7/19/12 6:11 AM, Anton Ertl wrote:
> "Elizabeth D. Rather" <era...@forth.com> writes:
>> On 7/17/12 12:48 AM, Anton Ertl wrote:
>>> "Elizabeth D. Rather" <era...@forth.com> writes:
>>>>> But if somebody types Ctrl-C (user interrupt) while U. is working,
>>>>> BASE is not restored. That's why the CATCH/THROW is in HEX.
>>>>
>>>> Really, pretty hard to do. Have you ever succeeded?
>>>
>>> : H. ( n -- ) BASE @ HEX swap U. BASE ! ; ok
>>> : test decimal 1000000 0 do i h. loop ; ok
>>> test
> ...
>> That's a pathological example because of the massively iterated short
>> loop. H. isn't used that way in real-world code.
>
> You may consider I/O-bound code pathological, but it is not at all
> unusual in the real world. A simple example is DUMP. I would hope
> that this unsafe H. is not used in real-world code, but I fear that it
> is.

Most implementations of DUMP I know of are interruptible but not by
trapping H. A more appropriate strategy is with a KEY? in the loop,
maybe once/line. Likewise anything else capable of generating a lot of
output.

Alex McDonald

unread,
Jul 19, 2012, 6:58:15 PM7/19/12
to
On Jul 19, 5:21 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
wrote:
> m...@iae.nl (Marcel Hendrix) writes:
> >My extended example demonstrates that it quite natural for a quotation
> >to need semi-permanent storage. A local local doesn't provide that,
> >but a local of the enclosing definition works fine. Surely, one wouldn't
> >go through the trouble of implementing quotations if all their variables
> >have to be named globals :-)
>
> What trouble?  And yes, quotations that do not have any locals access
> at all are useful; sure, it's just the usefulness of convenience, but
> it's still useful.

We have a few solutions; the lexically bound variety that I think you
mean here, a value bound variety and not binding at all.

For example, as I've implemented it, locals in scope are available;

: foo { local } [: local 1+ . ;] execute ; ok
10 foo 11 ok

It also allows the quotation a lifetime outside of the local's scope,
but not lexically bound (and the local declaration with no
corresponding use in TEST is confusing to say the least);

defer bar ok
: foo { local } [: local 1+ . ;] dup execute ; ok
10 foo is bar 11 ok
: test { a } bar ; ok
20 test 21 ok

The alternative is a value bind as in the C++11 case; but it's too
late at night for me to code up a working example.


>
> >I think that quotations don't offer much if they can't access outer
> >locals.
>
> If you want to use locals of the enclosing defintions, you want
> closures.  Yes, one can do cool things with closures, but the
> implementation cost is very high.  IMO too high, but if you want to do
> it, go ahead.  Maybe you can convince us that the cost is low enough
> and the benefits are high enough that we will all go for it.
>
> >Not having their own private locals and RECURSE is OK with
> >me; quotations won't have long complicated multi-page definitions,
> >and they can trivially call themselves by the return token (especially
> >if this is accessible in an outer local :-)
>
> Making RECURSE work in quotations is pretty easy.

Agreed, trivial.

Alex McDonald

unread,
Jul 19, 2012, 7:08:57 PM7/19/12
to
And I see why. My compiler supports DOES> while interpreting.

create x , does> @ ;

Stephen Pelc

unread,
Jul 20, 2012, 7:12:21 AM7/20/12
to
A revised summary, 18 July 2012

The following notes on quotations and closures incorporate
material from several people, including Anton Ertl, Andrew Haley,
Marcel Hendrix, Ward Mcfarland, Bernd Paysan, and Elizabeth
Rather. If you have been left out and want acknowledgement, please
let me know.

Quotations
==========

Discussion
----------
The essence of quotations is to provide nested colon definitions,
in which the inner definition(s) are nameless. The expression

: foo ... [: some words ;] ... ;

is equivalent to

:noname some words ; Constant #temp#
: foo ... #temp# ... ;

A simple quotation is an anonymous colon definition that is
defined inside a colon definition or quotation. It has no access
to locals of the enclosing definitions.

If quotations are to have the same privileges as words defined
with : and :NONAME they should be able to use local variables and
use RECURSE. Quotations should not be able to access the locals of
the outer word because we have no knowledge of when the quotation
is executed and hence whether outer locals are still alive.

One example use of quotations is to provide a solution to the use
of CATCH in a form close to other languages' TRY ... EXCEPT
blocks.

: foo \ i*x -- j*x
setup
[: fee fi fo fum ;] catch
if ... then
teardown
( throw again )
;

Under the term "Phrases", quotations have been in MacForth since
at least 1987. They are documented in the infamous "missing
chapter" of the MacForth manual.

Specification
-------------
The following notations have been seen in the wild, oldest first.
:| ... |;
:[ ... ]:
[: ... ;]

[: ( -- nested-sys )
Compilation: suspends compiling to the current definition, starts a
new
nested definition, and compilation continues with this nested
definition. Outer locals are not visible in the nested definition.
Locals may be defined in the nested definition. Inside the nested
definition RECURSE applies to the nested definition.

;] ( nested-sys -- )
Compilation: Ends the current nested definition, and resumes
compilation
to the previous current definition. It appends the following run-time
to
the current definition:

run-time: ( -- xt )
xt is the execution token to execute the nested definition.


Closures
========

Discussion
----------
A closure is like a quotation, except that it has (read and write)
access to the locals of the enclosing definitions.

Simple quotations are relatively easy to implement, closures are hard,
because they can extend the life of the enclosed locals beyond the end
if their definition; in general garbage collection is needed to manage
the enclosed locals of closures. Therefore everyone up to now has
only seriously thought about implementing and standardizing simple
quotations, and any discussions about closures are just theoretical
exercises.

I have chosen to distinguish nameless words intended as closures
by using [[: ... ;]] to define them. I have also chosen to
distinguish the required persistence of data by declaring it using
{{ ... }} which is syntactically like { ... } locals but has very
different persistence requirements.

: foo {{ a b -- }} ... [[: ... a b ... ;]] execute ;

Knuth's Man-Or-Boy test creates a quotation that *modifies* the
outer locals and then recursively calls its host, accessing outer
locals that one might have expected to long gone out of
scope. It forces the quotation implementation to store copies of
*all imaginable* outer locals and make them permanently available.

This can get even more interesting when a closure is required to
remember not only locals, but things like BASE, >IN, arbitrary
variables, file handles, buffer addresses, etc..(*)

There is a Forth example by Gerry Jackson which provides an
example of lambda definitions. This example is in ANS Forth and
runs on a range of systems.
www.qlikz.org/forth/lambda.zip

Comments
--------
Maybe we first need a convincing example of the usefulness of
quotations and closures.

Aside from looking obscure and clever and satisfying the "[x]
can do it, why not Forth?" test, what on earth does this buy you?

What does a closure achieve that cannot be achieved by other
scoping and persistence mechanisms such as a class and an object
with heap allocation?

Specification
-------------

TBD


--
Stephen Pelc, steph...@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
web: http://www.mpeforth.com - free VFX Forth downloads

Alex McDonald

unread,
Jul 20, 2012, 8:40:53 AM7/20/12
to
On Jul 20, 12:12 pm, stephen...@mpeforth.com (Stephen Pelc) wrote:
> A revised summary, 18 July 2012
>
> The following notes on quotations and closures incorporate
> material from several people, including Anton Ertl, Andrew Haley,
> Marcel Hendrix, Ward Mcfarland, Bernd Paysan, and Elizabeth
> Rather. If you have been left out and want acknowledgement, please
> let me know.
>
> Quotations
> ==========
>
> Discussion
> ----------
> The essence of quotations is to provide nested colon definitions,
> in which the inner definition(s) are nameless. The expression
>
> : foo ... [: some words ;] ... ;
>
> is equivalent to
>
> :noname some words ; Constant #temp#
> : foo ... #temp# ... ;
>
> A simple quotation is an anonymous colon definition that is
> defined inside a colon definition or quotation.  It has no access
> to locals of the enclosing definitions.

See below.
If I read this correctly, it would arbitrarily disallow

: foo { local } create [: local , ;] execute ;

but allow

: foo create [: , ;] execute ;

>
> ;] ( nested-sys -- )
> Compilation: Ends the current nested definition, and resumes
> compilation
> to the previous current definition. It appends the following run-time
> to
> the current definition:
>
> run-time: ( -- xt )
> xt is the execution token to execute the nested definition.

"Nested definition" sounds like an implementation detail. "Quoted
definition".

>
> Closures
> ========
>
> Discussion
> ----------
> A closure is like a quotation, except that it has (read and write)
> access to the locals of the enclosing definitions.
>
> Simple quotations are relatively easy to implement, closures are hard,
> because they can extend the life of the enclosed locals beyond the end
> if their definition; in general garbage collection is needed to manage
> the enclosed locals of closures.  Therefore everyone up to now has
> only seriously thought about implementing and standardizing simple
> quotations, and any discussions about closures are just theoretical
> exercises.

That eliminates value binding; what you're describing is lexical
binding or binding by reference. There's also an implicit assumption
that the XT returned by [[: and ;]] is constant for all executions of
the enclosing code. Plus, locals are not variables but values, so
binding the value seems more appropriate.

: foo { local } [[: local ( value bound ) 1+ . ;]] ;

10 foo returns an XT that, when executed, returns the equivalent of

:noname 10 1+ . ;

And the next execution of 10 foo returns a different XT. There is
nothing very strange about this; CREATEd words do it all the time,
returning a different XT that points at this word's private data and
then executes common DOES> code. A value bound closure is the
equivalent of a nameless CREATE.
> Stephen Pelc, stephen...@mpeforth.com

Albert van der Horst

unread,
Jul 20, 2012, 10:50:17 AM7/20/12
to
In article <2012Jul1...@mips.complang.tuwien.ac.at>,
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>Coos Haak <chf...@hccnet.nl> writes:
>>Op Wed, 18 Jul 2012 09:29:09 -0700 (PDT) schreef Alex McDonald:
>>> I'm presuming POSTFIX is a parsing word.
>>
>>No, it's sneakier, it patches HEADER (factor of CREATE etc.) to accept a
>>string on the stack to create the name. After that it 'unpatches' to return
>>HEADER to parse the next time it is used.
>
>In order to make use of that all defining words have to be written
>such that there is no internal data on the stack when HEADER is
>called.

Indirect threaded code allows for a very simple trick ^H^H^H^H
technique that works for all defining words provided they use
PARSE-NAME.
POSTFIX replaces the pointer to high level code of PARSE-NAME
to high level code that ... restores the old pointer of PARSE-NAME.
The bottomline is that PARSE-NAME is suspended for one time,
such that the HEADER word uses a name from the stack.

Example :

class AAP \ Creates defining word AAP
..
endclass

AAP my-aap \ Defining my-aap

"my-aap" POSTFIX AAP \ Equivalent

>
>Gforth has a word NEXTNAME ( c-addr u -- ) that works similarly, but
>you pass the string to NEXTNAME and it is then used for the name of
>the next defined word.
>
>However, EXECUTE-PARSING makes NEXTNAME and PREFIX mostly unnecessary
>and is cleaner and more general.

>
>- anton

Groetjes Albert

--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

Anton Ertl

unread,
Jul 20, 2012, 11:08:54 AM7/20/12
to
Albert van der Horst <alb...@spenarnc.xs4all.nl> writes:
>In article <2012Jul1...@mips.complang.tuwien.ac.at>,
>Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>>Coos Haak <chf...@hccnet.nl> writes:
>>>Op Wed, 18 Jul 2012 09:29:09 -0700 (PDT) schreef Alex McDonald:
>>>> I'm presuming POSTFIX is a parsing word.
>>>
>>>No, it's sneakier, it patches HEADER (factor of CREATE etc.) to accept a
>>>string on the stack to create the name. After that it 'unpatches' to return
>>>HEADER to parse the next time it is used.
>>
>>In order to make use of that all defining words have to be written
>>such that there is no internal data on the stack when HEADER is
>>called.
>
>Indirect threaded code allows for a very simple trick ^H^H^H^H
>technique that works for all defining words provided they use
>PARSE-NAME.
>POSTFIX replaces the pointer to high level code of PARSE-NAME
>to high level code that ... restores the old pointer of PARSE-NAME.
>The bottomline is that PARSE-NAME is suspended for one time,
>such that the HEADER word uses a name from the stack.

That does not remove the stack depth requirement I described above.

Also, you don't need threaded code for that. DEFERred words allow one
to do that on any kind of Forth as long as one can change the words
into deferred words.

Stephen Pelc

unread,
Jul 20, 2012, 11:55:53 AM7/20/12
to
As it said at the top, the summary is just a collation of postings
from this thread.

On Fri, 20 Jul 2012 05:40:53 -0700 (PDT), Alex McDonald
<bl...@rivadpm.com> wrote:

>> [: ( -- nested-sys )
>> Compilation: suspends compiling to the current definition, starts a
>> new
>> nested definition, and compilation continues with this nested
>> definition. Outer locals are not visible in the nested definition.
>> Locals may be defined in the nested definition. Inside the nested
>> definition RECURSE applies to the nested definition.
>
>If I read this correctly, it would arbitrarily disallow
>
>: foo { local } create [: local , ;] execute ;
>
>but allow
>
>: foo create [: , ;] execute ;

The suggestions is that locals are permitted in quotations but
that they are separate from any in the enclosing definition.

Given that we don't know where the xt for EXECUTE came from
or when the enclosed quotation will be executed, it's the only
sensible thing to do for *quotations*. Closures are way out of
my interest at the moment. Except for Gerry's implementation,
there's no common practice, whereas quotations have been
around for a long time.

Perhaps the authors of the original closures text would be
prepared to comment.

Stephen

--
Stephen Pelc, steph...@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691

Aleksej Saushev

unread,
Jul 20, 2012, 5:24:37 PM7/20/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:

> On 7/19/12 6:11 AM, Anton Ertl wrote:
>> "Elizabeth D. Rather" <era...@forth.com> writes:
>>> On 7/17/12 12:48 AM, Anton Ertl wrote:
>>>> "Elizabeth D. Rather" <era...@forth.com> writes:
>>>>>> But if somebody types Ctrl-C (user interrupt) while U. is working,
>>>>>> BASE is not restored. That's why the CATCH/THROW is in HEX.
>>>>>
>>>>> Really, pretty hard to do. Have you ever succeeded?
>>>>
>>>> : H. ( n -- ) BASE @ HEX swap U. BASE ! ; ok
>>>> : test decimal 1000000 0 do i h. loop ; ok
>>>> test
>> ...
>>> That's a pathological example because of the massively iterated short
>>> loop. H. isn't used that way in real-world code.
>>
>> You may consider I/O-bound code pathological, but it is not at all
>> unusual in the real world. A simple example is DUMP. I would hope
>> that this unsafe H. is not used in real-world code, but I fear that it
>> is.
>
> Most implementations of DUMP I know of are interruptible but not
> by trapping H. A more appropriate strategy is with a KEY? in the
> loop, maybe once/line. Likewise anything else capable of
> generating a lot of output.

Do you mean that there're no other ways to interrupt program than by
writing it so that it constantly polls for some event?


--
HE CE3OH...

Elizabeth D. Rather

unread,
Jul 20, 2012, 10:20:10 PM7/20/12
to
It's the cleanest to implement and has fewest side-effects. The cost of
a KEY? per line out output is pretty minimal, a lot less than a CATCH
around every H.

Albert van der Horst

unread,
Jul 21, 2012, 7:27:14 AM7/21/12
to
In article <2012Jul2...@mips.complang.tuwien.ac.at>,
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>Albert van der Horst <alb...@spenarnc.xs4all.nl> writes:
>>In article <2012Jul1...@mips.complang.tuwien.ac.at>,
>>Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>>>Coos Haak <chf...@hccnet.nl> writes:
>>>>Op Wed, 18 Jul 2012 09:29:09 -0700 (PDT) schreef Alex McDonald:
>>>>> I'm presuming POSTFIX is a parsing word.
>>>>
>>>>No, it's sneakier, it patches HEADER (factor of CREATE etc.) to accept a
>>>>string on the stack to create the name. After that it 'unpatches' to return
>>>>HEADER to parse the next time it is used.
>>>
>>>In order to make use of that all defining words have to be written
>>>such that there is no internal data on the stack when HEADER is
>>>called.
>>
>>Indirect threaded code allows for a very simple trick ^H^H^H^H
>>technique that works for all defining words provided they use
>>PARSE-NAME.
>>POSTFIX replaces the pointer to high level code of PARSE-NAME
>>to high level code that ... restores the old pointer of PARSE-NAME.
>>The bottomline is that PARSE-NAME is suspended for one time,
>>such that the HEADER word uses a name from the stack.
>
>That does not remove the stack depth requirement I described above.

That is the nice thing about this trick. It doesn't!
Think about it. At the point were a name would be parsed,
effectively nothing is done.

>
>Also, you don't need threaded code for that. DEFERred words allow one
>to do that on any kind of Forth as long as one can change the words
>into deferred words.

I was sure only about ITC, where it is particularly easy.

>
>- anton
>--

Alex McDonald

unread,
Jul 21, 2012, 6:59:02 AM7/21/12
to
On Jul 21, 3:20 am, "Elizabeth D. Rather" <erat...@forth.com> wrote:
> On 7/20/12 11:24 AM, Aleksej Saushev wrote:
>
>
>
>
>
>
>
>
>
> > "Elizabeth D. Rather" <erat...@forth.com> writes:
>
> >> On 7/19/12 6:11 AM, Anton Ertl wrote:
> >>> "Elizabeth D. Rather" <erat...@forth.com> writes:
> >>>> On 7/17/12 12:48 AM, Anton Ertl wrote:
> Los Angeles, CA 90045http://www.forth.com
>
> "Forth-based products and Services for real-time
> applications since 1973."
> ==================================================

In many hosted Forths, the executed instruction cost of KEY? per line
will be much higher than a CATCH per H.; a call to the OS, context
switching and stream management at the cost of several thousand
instructions per KEY? is not minimal.

Albert van der Horst

unread,
Jul 21, 2012, 8:10:11 AM7/21/12
to
In article <cpydnX_9HJlBjJfN...@supernews.com>,
I'm with Anton on this one. In this day and age you expect to be able
to hit ^C and interrupt an infinite loop, without killing your
environment. Once you have that it is silly to have KEY? in DUMP.
If you're as uncompromisingly correct as the gForth guys, the code for
H. follows.

>
>Cheers,
>Elizabeth

Andrew Haley

unread,
Jul 21, 2012, 10:19:50 AM7/21/12
to
Albert van der Horst <alb...@spenarnc.xs4all.nl> wrote:
>
> I'm with Anton on this one. In this day and age you expect to be able
> to hit ^C and interrupt an infinite loop, without killing your
> environment. Once you have that it is silly to have KEY? in DUMP.
> If you're as uncompromisingly correct as the gForth guys, the code for
> H. follows.

In practice it's nearly impossible to allow code to be interrupted at
any random point. You want to restore things as you unwind the stack,
but if you allow the code that is doing the restoring to be
interrupted things won't work well. You could disable interruption
when unwinding, but exception handlers are normal code. The solution
adopted by Java and pthreads is to have specific safepoints and only
allow interruption there; all I/O is a safepoint, for example.

Andrew.

Bernd Paysan

unread,
Jul 21, 2012, 12:58:43 PM7/21/12
to
Andrew Haley wrote:

> Albert van der Horst <alb...@spenarnc.xs4all.nl> wrote:
>>
>> I'm with Anton on this one. In this day and age you expect to be able
>> to hit ^C and interrupt an infinite loop, without killing your
>> environment. Once you have that it is silly to have KEY? in DUMP.
>> If you're as uncompromisingly correct as the gForth guys, the code
>> for H. follows.
>
> In practice it's nearly impossible to allow code to be interrupted at
> any random point. You want to restore things as you unwind the stack,
> but if you allow the code that is doing the restoring to be
> interrupted things won't work well.

It's not really that problematic. It's a normal transaction: You first
unwind the stack and restore things (without actually corrupting the
exception frame - this might be a bit tricky, but it is doable). Then,
as last point of the transaction, you unwind the exception frame itself
- this needs to be an atomic operation (i.e. it is ! in Gforth, to a
user-space variable called HANDLER). If there is any interrupt in
between, the exception frame is still intact, and you get another chance
to unwind it.

> You could disable interruption
> when unwinding, but exception handlers are normal code. The solution
> adopted by Java and pthreads is to have specific safepoints and only
> allow interruption there; all I/O is a safepoint, for example.

If you need a bit more than ! to successfully unwind your exception
frame, rethink your method.

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://bernd-paysan.de/

Albert van der Horst

unread,
Jul 21, 2012, 3:29:27 PM7/21/12
to
In article <j-WdndimvvgbJ5fN...@supernews.com>,
I have ^C interruptibility in lina, as a loadable enhancement.
It vectors to a warm start, which is about as far as I want to
go in a minimalistic system.

>
>Andrew.

Elizabeth D. Rather

unread,
Jul 22, 2012, 3:33:04 AM7/22/12
to
On 7/21/12 12:59 AM, Alex McDonald wrote:
> On Jul 21, 3:20 am, "Elizabeth D. Rather" <erat...@forth.com> wrote:
>> On 7/20/12 11:24 AM, Aleksej Saushev wrote:
...
>>>> Most implementations of DUMP I know of are interruptible but not
>>>> by trapping H. A more appropriate strategy is with a KEY? in the
>>>> loop, maybe once/line. Likewise anything else capable of
>>>> generating a lot of output.
>>
>>> Do you mean that there're no other ways to interrupt program than by
>>> writing it so that it constantly polls for some event?
>>
>> It's the cleanest to implement and has fewest side-effects. The cost of
>> a KEY? per line out output is pretty minimal, a lot less than a CATCH
>> around every H.
>
> In many hosted Forths, the executed instruction cost of KEY? per line
> will be much higher than a CATCH per H.; a call to the OS, context
> switching and stream management at the cost of several thousand
> instructions per KEY? is not minimal.

In my experience, a keystroke is captured by an interrupt which records
the keyboard event. It does not take either an I/O operation nor an OS
call to inquire whether an event has occurred, merely a check of a
memory location. Thereupon code can obtain the key if it cares, but
often you're just interested in the existence of the event. Very cheap.

Alex McDonald

unread,
Jul 22, 2012, 4:35:26 AM7/22/12
to
On Jul 22, 8:33 am, "Elizabeth D. Rather" <erat...@forth.com> wrote:
> On 7/21/12 12:59 AM, Alex McDonald wrote:
>
>
>
>
>
>
>
>
>
> > On Jul 21, 3:20 am, "Elizabeth D. Rather" <erat...@forth.com> wrote:
> >> On 7/20/12 11:24 AM, Aleksej Saushev wrote:
> ...
> >>>> Most implementations of DUMP I know of are interruptible but not
> >>>> by trapping H. A more appropriate strategy is with a KEY? in the
> >>>> loop, maybe once/line. Likewise anything else capable of
> >>>> generating a lot of output.
>
> >>> Do you mean that there're no other ways to interrupt program than by
> >>> writing it so that it constantly polls for some event?
>
> >> It's the cleanest to implement and has fewest side-effects. The cost of
> >> a KEY? per line out output is pretty minimal, a lot less than a CATCH
> >> around every H.
>
> > In many hosted Forths, the executed instruction cost of KEY? per line
> > will be much higher than a CATCH per H.; a call to the OS, context
> > switching and stream management at the cost of several thousand
> > instructions per KEY? is not minimal.
>
> In my experience, a keystroke is captured by an interrupt which records
> the keyboard event. It does not take either an I/O operation nor an OS
> call to inquire whether an event has occurred, merely a check of a
> memory location. Thereupon code can obtain the key if it cares, but
> often you're just interested in the existence of the event. Very cheap.
>

Ah, how times have changed...

> Cheers,
> Elizabeth
>
> --
> ==================================================
> Elizabeth D. Rather   (US & Canada)   800-55-FORTH
> FORTH Inc.                         +1 310.999.6784
> 5959 West Century Blvd. Suite 700
> Los Angeles, CA 90045http://www.forth.com

Andrew Haley

unread,
Jul 22, 2012, 5:24:01 AM7/22/12
to
Bernd Paysan <bernd....@gmx.de> wrote:
> Andrew Haley wrote:
>
>> Albert van der Horst <alb...@spenarnc.xs4all.nl> wrote:
>>>
>>> I'm with Anton on this one. In this day and age you expect to be able
>>> to hit ^C and interrupt an infinite loop, without killing your
>>> environment. Once you have that it is silly to have KEY? in DUMP.
>>> If you're as uncompromisingly correct as the gForth guys, the code
>>> for H. follows.
>>
>> In practice it's nearly impossible to allow code to be interrupted
>> at any random point. You want to restore things as you unwind the
>> stack, but if you allow the code that is doing the restoring to be
>> interrupted things won't work well.
>
> It's not really that problematic. It's a normal transaction: You
> first unwind the stack and restore things (without actually
> corrupting the exception frame - this might be a bit tricky, but it
> is doable). Then, as last point of the transaction, you unwind the
> exception frame itself - this needs to be an atomic operation
> (i.e. it is ! in Gforth, to a user-space variable called HANDLER).
> If there is any interrupt in between, the exception frame is still
> intact, and you get another chance to unwind it.

It's not simply a matter of unwinding: it's all the things that the
CATCH handlers themselves have to do. You really don't want to
interrupt unlocking, for example, or closing a file.

Andrew.

Bernd Paysan

unread,
Jul 22, 2012, 8:25:44 AM7/22/12
to
Andrew Haley wrote:
> It's not simply a matter of unwinding: it's all the things that the
> CATCH handlers themselves have to do. You really don't want to
> interrupt unlocking, for example, or closing a file.

The Unix approach to that was always "EAGAIN", i.e. if an operation is
interrupted and it hasn't completed, you can do that operation again -
and you are actually supposed to do that. It really becomes critical
when you can reuse that resource quickly again, so that a double-close
will close the next file opened under the same file ID. Or double-free
memory frees the next allocated block.

Java's approach to this problem is to have critical sections, i.e.
atomic, uninterruptable code blocks. STM's approach is to implement
these blocks as transactions, i.e. they try doing what they want to
achieve, and commit their result in an atomic operation when they have
successfully completed. In the latter approach, the operation can fail
at any point, and then restarted later.

Gforth's CATCH handler tries this approach, but we might fail if we call
functions that don't work that way.

Albert van der Horst

unread,
Jul 22, 2012, 11:01:42 AM7/22/12
to
In article <jtvhcc$sdm$1...@online.de>, Bernd Paysan <bernd....@gmx.de> wrote:
>Marcel Hendrix wrote:
>> Maybe we first need a convincing example of the usefulness of
>> quotations and closures -- (*) would certainly be useful, but
>> the cost seems to be a little excessive?
>
>Quotations are quite useful when you do higher-order functions. We have
>discussed words like LIST>, which take a list as argument, and loop over
>the rest of the word with each item. Having a MAP-LIST is easier to
>implement (especially for compilers like VFX and iForth, others have no
>problems ;-), and quotations make it easier to write code for this.
>
>Closures are something different, they contain both a function *and*
>data. We have something like that in Forth - with name and persistent
>in the dictionary, it's defined by CREATE and DOES>. Having the same
>available with anonymous definition is useful, but it doesn't
>necessarily have to be a closure as implementation (a closure always
>means access to outer locals).

Real closures probably require to remember the search order.
I think that Forth collapses if the weight of closures is added.

>
>IMHO the price for real closures are too high to be paid in Forth - real
>closures mean that you can't have a stack for locals, you absolutly need
>to allocate them from the heap and have garbage collection.

Indeed.

>A compromise would be the [:{ I proposed - this is a "poor man's
>closure": it would be freed explicitly (you say <xt> free throw), and it
>would take arguments from the stack. IMHO it feels much more Forth-
>like: It doesn't come with the cost of full closures, where you can't
>know the lifetime of a local frame in advance, and therefore you have to
>make them live on a heap by default.

If we compare the situation with LISP then Forth lacks a rigorous
theoretical framework. In LISP you may define something general and
it may work in unexpected ways. In Forth we must restrict ourselves
or we get unexpected difficulties.

>
>It's far better to have only those things to live on the heap which
>absolutely must live there.
>
>--
>Bernd Paysan

Andrew Haley

unread,
Jul 22, 2012, 12:07:26 PM7/22/12
to
Bernd Paysan <bernd....@gmx.de> wrote:

> IMHO the price for real closures are too high to be paid in Forth - real
> closures mean that you can't have a stack for locals, you absolutly need
> to allocate them from the heap and have garbage collection.

I don't think that's really true: only the closures themselves need to
be heap-allocated.

> A compromise would be the [:{ I proposed - this is a "poor man's
> closure": it would be freed explicitly (you say <xt> free throw),
> and it would take arguments from the stack. IMHO it feels much more
> Forth- like: It doesn't come with the cost of full closures, where
> you can't know the lifetime of a local frame in advance, and
> therefore you have to make them live on a heap by default.
>
> It's far better to have only those things to live on the heap which
> absolutely must live there.

Indeed.

Andrew.

Andrew Haley

unread,
Jul 22, 2012, 12:11:30 PM7/22/12
to
Bernd Paysan <bernd....@gmx.de> wrote:
> Andrew Haley wrote:
>> It's not simply a matter of unwinding: it's all the things that the
>> CATCH handlers themselves have to do. You really don't want to
>> interrupt unlocking, for example, or closing a file.
>
> The Unix approach to that was always "EAGAIN", i.e. if an operation is
> interrupted and it hasn't completed, you can do that operation again -
> and you are actually supposed to do that. It really becomes critical
> when you can reuse that resource quickly again, so that a double-close
> will close the next file opened under the same file ID. Or double-free
> memory frees the next allocated block.

I really don't see how EAGAIN helps you if you ctrl-C during closing a
file. The point is that if you're going to handle asynchronous
termination in a robust way, you need to do it when you know it's
safe.

> Java's approach to this problem is to have critical sections, i.e.
> atomic, uninterruptable code blocks.

Java's internal approach is safepoints, as I described, or at least
that's the way the HotSpot VM does it.

Andrew.

Aleksej Saushev

unread,
Jul 22, 2012, 1:19:59 PM7/22/12
to
"Elizabeth D. Rather" <era...@forth.com> writes:

> On 7/21/12 12:59 AM, Alex McDonald wrote:
>> On Jul 21, 3:20 am, "Elizabeth D. Rather" <erat...@forth.com> wrote:
>>> On 7/20/12 11:24 AM, Aleksej Saushev wrote:
> ...
>>>>> Most implementations of DUMP I know of are interruptible but not
>>>>> by trapping H. A more appropriate strategy is with a KEY? in the
>>>>> loop, maybe once/line. Likewise anything else capable of
>>>>> generating a lot of output.
>>>
>>>> Do you mean that there're no other ways to interrupt program than by
>>>> writing it so that it constantly polls for some event?
>>>
>>> It's the cleanest to implement and has fewest side-effects. The cost of
>>> a KEY? per line out output is pretty minimal, a lot less than a CATCH
>>> around every H.
>>
>> In many hosted Forths, the executed instruction cost of KEY? per line
>> will be much higher than a CATCH per H.; a call to the OS, context
>> switching and stream management at the cost of several thousand
>> instructions per KEY? is not minimal.
>
> In my experience, a keystroke is captured by an interrupt which
> records the keyboard event. It does not take either an I/O
> operation nor an OS call to inquire whether an event has
> occurred, merely a check of a memory location. Thereupon code
> can obtain the key if it cares, but often you're just interested
> in the existence of the event. Very cheap.

Not at all! You have to write the polling code everywhere you know
it can be interrupted. You need to track all those places too.
With "catch" you write all that code only once. Now compare the price.


--
HE CE3OH...
It is loading more messages.
0 new messages