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

Are locals evil?

94 views
Skip to first unread message

DavidM

unread,
Apr 23, 2009, 8:44:28 PM4/23/09
to
Hi,

What are the prevailing thoughts within the Forth community on the use of
locals?

Locals are:

(a) Vile pollution and resource wastage in an otherwise elegant language,
a result of lame concessions to intellectual cripples

(b) Horrible in every way, but in some situations very hard to avoid

(c) Neutral in themselves, good in some situations and wasteful in others

(d) A great contribution to the language that can make code much more
readable and maintainable, for a small performance cost

(e) A good programming practice in general, except for the most trivial
of operations

Slava Pestov

unread,
Apr 23, 2009, 10:22:58 PM4/23/09
to
On Apr 23, 7:44 pm, DavidM <nos...@nowhere.com> wrote:
> (c) Neutral in themselves, good in some situations and wasteful in others
>
> (d) A great contribution to the language that can make code much more
>     readable and maintainable, for a small performance cost

I'd say (c) and (d). If your dataflow is complex and there's really no
way around it, locals make code more readable than a mess of rot/roll/
2dup etc. In simpler situations they seem overkill. I feel the same
way about OOP techniques as well.

Slava

BruceMcF

unread,
Apr 24, 2009, 12:42:44 AM4/24/09
to
On Apr 23, 8:44 pm, DavidM <nos...@nowhere.com> wrote:
> Hi,
> What are the prevailing thoughts within the Forth community on the use of locals?

From watching various discussions on locals over the past five or ten
years, I'd say prevailing thoughts would be a through e.

Ed

unread,
Apr 24, 2009, 2:19:14 AM4/24/09
to

Here are some more:

(f) Easy to port foreign programs to forth with least effort.

(g) Makes forth 'readable' i.e. forth should look like other languages
even at low level.

(h) Embedded apps typically don't have locals, yet substantial
programs manage to be written.

(i) Locals can chew up lots of return stack space.

The general issue with locals and forth, is that locals promote a
dual syntax. It thus becomes difficult to know when one ought
to use locals and when not. Consequently -

Those that use locals sparsely can often avoid them entirely.
Those who like locals find them impossible to live without.

han...@bigfoot.com

unread,
Apr 24, 2009, 2:28:45 AM4/24/09
to
On Apr 24, 2:44 am, DavidM <nos...@nowhere.com> wrote:
IMHO locals are another attempt to the C-afication of Forth. It takes
away all the characteristics that make Forth Forth. I had the same
comment when OO was introduced, escape characters, ANS file handling,
even a discussion on scanf()!! What's next? Stackprototypes? Infix?
Why not write C right away?

Note, I love and use C a lot, but most problems are handled more
elegantly with Forth, due to its special characteristics. If I have a
problem that is better handled by C, I write C, not Forth. And vice
versa.

Hans Bezemer

Albert van der Horst

unread,
Apr 24, 2009, 8:38:48 AM4/24/09
to
In article <gsrlip$ad3$1...@news-01.bur.connect.com.au>,

Ed <nos...@invalid.com> wrote:
>DavidM wrote:
>> Hi,
>>
>> What are the prevailing thoughts within the Forth community on the use of
>> locals?
>>
>> Locals are:
>>
>> (a) Vile pollution and resource wastage in an otherwise elegant language,
>> a result of lame concessions to intellectual cripples
>>
>> (b) Horrible in every way, but in some situations very hard to avoid
>>
>> (c) Neutral in themselves, good in some situations and wasteful in others
>>
>> (d) A great contribution to the language that can make code much more
>> readable and maintainable, for a small performance cost
>>
>> (e) A good programming practice in general, except for the most trivial
>> of operations
>
>Here are some more:
>
>(f) Easy to port foreign programs to forth with least effort.
>
>(g) Makes forth 'readable' i.e. forth should look like other languages
> even at low level.
>
>(h) Embedded apps typically don't have locals, yet substantial
> programs manage to be written.
>
>(i) Locals can chew up lots of return stack space.

(j) Locals are superfluous.
Locals are mostly used where VARIABLE would do.
(Only in the rare case of recursion you need to put them
on the return stack.

ADSTRUCTION
Instead of
: aap LOCAL x ... x ... TO x ;
A sain person would do
\ Do some aap-ing away
VARIABLE x \ x component, local
: aap x ! .. x @ ... x ! .. ;
'x SMUDGED

Without introducing an extra concept.
(Or even
: LOCAL VARIABLE PRIVATE ; \ Variables that have local scope only.
PRIVATE sets a flag in the header to indicate that
things are to be smudged.

Groetjes Albert

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

Marcel Hendrix

unread,
Apr 24, 2009, 1:28:26 PM4/24/09
to
"Ed" <nos...@invalid.com> writes Re: Are locals evil?

> DavidM wrote:
>> Hi,

>> What are the prevailing thoughts within the Forth community on the use of
>> locals?

>> Locals are:

>> (a) Vile pollution and resource wastage in an otherwise elegant language,
>> a result of lame concessions to intellectual cripples

>> (b) Horrible in every way, but in some situations very hard to avoid

>> (c) Neutral in themselves, good in some situations and wasteful in others

>> (d) A great contribution to the language that can make code much more
>> readable and maintainable, for a small performance cost

>> (e) A good programming practice in general, except for the most trivial
>> of operations

> Here are some more:

> (f) Easy to port foreign programs to forth with least effort.

This doesn't answer the question.

> (g) Makes forth 'readable' i.e. forth should look like other languages
> even at low level.

The explanation is even more suggestive than the question itself.

> (h) Embedded apps typically don't have locals, yet substantial
> programs manage to be written.

> (i) Locals can chew up lots of return stack space.

These could be arguments to support a belief. As Albert van der Horst
argued, you can make variables behave like locals in many cases, so
maybe (i) is false, and (h) might be true because programmers kludge
along with variables where they should have been using locals.

My belief is that, for general programming, locals help to deliver working
code faster. As such they are in one's toolbag, so there will be a place
and a time.

> The general issue with locals and forth, is that locals promote a
> dual syntax. It thus becomes difficult to know when one ought
> to use locals and when not.

Not if you are a serious programmer.

> Consequently -
> Those that use locals sparsely can often avoid them entirely.
> Those who like locals find them impossible to live without.

The former is trivially true. You can also work around DO LOOP and DUP
and rename OR to + .

I like the concept of having locals in my toolbag but don't see how
they could be impossible to live without.

Without locals:

-- Leo Wong
\ From day month year, calculate the day of the week
\ using Zeller's Congruence
: fmod ( n1 n2 -- floored-mod ) >R S>D R> FM/MOD DROP ;
: DoW(LW) ( d m ccyy -- 0=Sunday...6=Saturday )
OVER 3 < IF 1- THEN \ adjust year if Jan or Feb
100 /MOD 2>R ( d m ) ( R: yy cc )
3 - 12 fmod 1+ \ m: 1->11 2->12 3->1 4->2...12->10
\ Zeller's Congruence:
\ dow = (d + (26*m - 2)/10 + cc/4 - 2*cc + yy/4 + yy) mod 7
26 * 2 - 10 / + \ d + (26*m - 2)/10
R@ 4 / + R> 2* - \ + cc/4 - 2*cc
R@ 4 / + R> + \ + yy/4 + yy
7 fmod ; \ mod 7 = dow

With locals (untested):

: DoW ( d m y -- 0=Sunday...6=Saturday )
0 LOCALS| cc year month day |
month 3 < IF -1 +TO year THEN \ adjust year if Jan or Feb
year 100 /MOD TO cc TO year
month 3 - 12 fmod 1+ TO month \ m: 1->11 2->12 3->1 4->2...12->10
month 26 * 2- 10 / day + cc 4 / + cc 2* -
year 4 / + year + 7 fmod ; ( Zeller's Congruence )

-marcel

Jeff Fox

unread,
Apr 24, 2009, 1:44:22 PM4/24/09
to

For C the answer is E. For Forth the answer is A.
For a mix of Forth and C the answer is C.

Best Wishes

Jeff Fox

unread,
Apr 24, 2009, 1:51:26 PM4/24/09
to

Without locals it might look something like

: DoW ( -- 0=Sunday...6=Saturday )
month @ 3 < IF -1 year +! THEN \ adjust year if Jan or Feb
year @ 100 /MOD cc ! year @
month @ 3 - 12 fmod 1+ month @ + cc @ 4 / + cc @ 2* -
year @ 4 / + year @ + 7 fmod ; ( Zeller's Congruence )

No need for locals, not much change from local style except
that it looks less like C for C processors.

Best Wishes

BruceMcF

unread,
Apr 25, 2009, 8:22:30 AM4/25/09
to
On Apr 24, 1:44 pm, Jeff Fox <f...@ultratechnology.com> wrote:
> > (c) Neutral in themselves, good in some situations and wasteful in others

> For a mix of Forth and C the answer is C.

Given that the dominant external function calls are designed
for dynamic link libraries written in C or C++, mixing Forth
and C is a wide field.

The problem with locals is that they discourage factoring,
whereas if written with private variables, a definition
may be factored more freely.

David N. Williams

unread,
Apr 25, 2009, 9:05:38 AM4/25/09
to
BruceMcF wrote:
> On Apr 24, 1:44 pm, Jeff Fox <f...@ultratechnology.com> wrote:
>>> (c) Neutral in themselves, good in some situations and wasteful in
others
>
>> For a mix of Forth and C the answer is C.
>
> Given that the dominant external function calls are designed
> for dynamic link libraries written in C or C++, mixing Forth
> and C is a wide field.

Indeed!

> The problem with locals is that they discourage factoring,
> whereas if written with private variables, a definition
> may be factored more freely.

I see this as more a prescription for factoring locals than a
problem. :-)

-- David

Doug Hoffman

unread,
Apr 25, 2009, 9:23:00 AM4/25/09
to
David N. Williams wrote:
> BruceMcF wrote:

> > The problem with locals is that they discourage factoring,
> > whereas if written with private variables, a definition
> > may be factored more freely.
>
> I see this as more a prescription for factoring locals than a
> problem. :-)

Agreed. I'm still waiting to see an example of how the use of locals
prevents or even just discourages factoring.

-Doug

BruceMcF

unread,
Apr 25, 2009, 11:00:08 AM4/25/09
to

It introduces additional points where cut and paste factoring does not
work, where the cut and paste factor has to be after the last local is
named that introduces data operated on.

In

: DoW ( -- 0=Sunday...6=Saturday )
month @ 3 < IF -1 year +! THEN \ adjust year if Jan or Feb
year @ 100 /MOD cc ! year @
month @ 3 - 12 fmod 1+ month @ + cc @ 4 / +
cc @ 2* - year @ 4 / + year @ + 7 fmod ;

... the only boundary on factoring is ``IF -1 year +! THEN'' should be
in a single factor.

: DoW ( d m y -- 0=Sunday...6=Saturday )
0 LOCALS| cc year month day |
month 3 < IF -1 +TO year THEN
\ adjust year if Jan or Feb
year 100 /MOD TO cc TO year
month 3 - 12 fmod 1+ TO month
\ m: 1->11 2->12 3->1 4->2...12->10
month 26 * 2- 10 / day + cc 4 / + cc 2* -
year 4 / + year + 7 fmod ; ( Zeller's Congruence)

''month 3 < IF -1 +TO year THEN'' cannot be directly factored, ``year
100 /MOD TO cc TO year'' cannot be directly factored, ``month 3 - 12
fmod 1+ TO month'' cannot be directly factored, and etc.

Marcel Hendrix

unread,
Apr 25, 2009, 12:26:04 PM4/25/09
to
BruceMcF <agi...@netscape.net> writes Re: Are locals evil?

> On Apr 25, 9:23 am, Doug Hoffman <dhoff...@talkamerica.net> wrote:

[..]


> Agreed. I'm still waiting to see an example of how the use of locals
> prevents or even just discourages factoring.

> It introduces additional points where cut and paste factoring does not
> work, where the cut and paste factor has to be after the last local is
> named that introduces data operated on.

> In

> : DoW ( -- 0=Sunday...6=Saturday )
> month @ 3 < IF -1 year +! THEN \ adjust year if Jan or Feb
> year @ 100 /MOD cc ! year @
> month @ 3 - 12 fmod 1+ month @ + cc @ 4 / +
> cc @ 2* - year @ 4 / + year @ + 7 fmod ;

> ... the only boundary on factoring is ``IF -1 year +! THEN'' should be
> in a single factor.

Because DoW modifies the VARIABLEs year and cc, you can't move around
its call in the source without checking first if year has been
properly set up beforehand. Also, you must check if any word between
"year !" (assuming no trickier ways to change it are used) and DoW
is secretly modifying year. If DoW is used more than once in the
source, the things to check for become even more "interesting."

If you cut up this DoW definition arbitrarily, it will be necessary
to prevent that the pieces are executed in arbitrary order, execute
multiple times, or are re-used improperly (if at all) in other parts
of the source. Factoring would degenerate into a tool to make sources
more "readable," and you could get the same effect by pretty-printing
the source.

Note that month is modified in the definition, but its changed value
is kept on the stack (immediately obvious in the locals version). If you
want to cut up the variables version, you must analyze and document
the stack diagram to make sure the pieces fit together correctly.

A slightly better DoW (apart from it being completely unreadable)
would initialize the variables from the stack:

: DoW ( d m y -- 0=Sunday...6=Saturday )

year ! month ! day !


month @ 3 < IF -1 year +! THEN \ adjust year if Jan or Feb

year @ #100 /MOD cc ! year @
month @ 3 - #12 fmod 1+ month @ + cc @ 4 / +


cc @ 2* - year @ 4 / + year @ + 7 fmod ;

Your remaining problem is now making sure that other parts of the
code are not using year, month and day uninitialized (they may
assume DoW executed and did it already). This could be prevented
by hiding the three variables to all other code (note there is no
standard Forth construction for this).

Now, if you want to paste the definition of DoW in another piece
of code, first make sure that you have selected all its constituent
subdefinitions, and its three variables. Then make sure that the
used variable names are not in use already in the target code.
Additionally make sure that the target code doesn't want to use
DoW recursively. (And that the target word isn't used recursively
itself.)

-marcel

Doug Hoffman

unread,
Apr 25, 2009, 5:46:40 PM4/25/09
to

I agree with everything Marcel said. I'll add the following:


1) I didn't know that factoring was supposed to be a robotic cut and
paste code segment replacement. Shouldn't some thought be applied and
then one can often find simplifications and improvements?


2) Actually I would approach the problem by making use of Leo's original
comments about the base algorithms. This helps to reduce errors and
lessens my work. My preferred solution:

: DoW(DH) { d m y \ c -- 0=Sunday...6=Saturday }
m 3 < IF -1 +to y THEN \ adjust year if Jan or Feb
y 100 /mod to c to y \ input y(ccyy) => cc yy => c y
m 3 - 12 fmod 1+ to m \ m: 1->11 2->12 3->1 4->2...12->10
\ Zeller's Congruence:
i' (d + (26*m - 2)/10 + c/4 - 2*c + y/4 + y)' 7 fmod ;

25 4 2009 DoW(DH) . 6 ok


3) If I felt the need to factor (though I wouldn't in this case), no
problem:

: f1 ( y m -- y )
3 < IF 1- THEN ;

: f2 ( y -- y c )
100 /MOD ;

: f3 ( m -- m )
3 - 12 fmod 1+ ;

: DoW(DHfact) { d m y \ c -- 0=Sunday...6=Saturday }
y m f1 to y \ adjust year if Jan or Feb
y f2 to c to y \ input y(ccyy) => cc yy => c y
m f3 to m \ m: 1->11 2->12 3->1 4->2...12->10
\ Zeller's Congruence:
i' (d + (26*m - 2)/10 + c/4 - 2*c + y/4 + y)' 7 fmod ;

25 4 2009 DoW(DHfact) . 6 ok


4) I don't understand Jeff Fox's code. Are there really no stack input
parameters? It doesn't seem to work, but perhaps I'm missing something.
Marcel accurately points out the several pitfalls of Jeff's approach.
We avoid those pitfalls with the locals approach, though I'm not
saying locals are the only way to solve this problem. Locals are a
valuable set of tools, at least to me, and enable me to quickly produce
accurate solutions to real problems. I can still factor my code.

-Doug

Albert van der Horst

unread,
Apr 26, 2009, 6:23:15 AM4/26/09
to
In article <a494b$49f30eb3$c4b2e92$98...@DIALUPUSA.NET>,

A quotation from some euler problem. Obsfuscated, to prevent spoiler.
\ -----------------------
VARIABLE p
VARIABLE t
VARIABLE s

: g() IF 0 ELSE s @ #g x^x THEN ;

: f() .S p @ >R t @ >R s @ >R s ! t ! p !
t @ 0 <= IF
g()
ELSE t @ s @ * p @ < IF
0
ELSE
0 p @ s @ / 1+ 0 DO
p @ I s @ * - t @ I - s @ 1- RECURSE
I t @ #g + (/) * +
LOOP
THEN THEN
R> s ! R> t ! R> p ! .S ;
\ -----------------------

The factoring into g() is impossible with true locals.
The practice of the example is that g() has to be made
a helluvalot more complicated.
This demonstrates emulated local variables in a recursive
context.

>
>-Doug

Ed

unread,
Apr 26, 2009, 5:54:40 AM4/26/09
to
Marcel Hendrix wrote:
> "Ed" <nos...@invalid.com> writes Re: Are locals evil?
> ...

> > Here are some more:
>
> > (f) Easy to port foreign programs to forth with least effort.
>
> This doesn't answer the question.
>
> > (g) Makes forth 'readable' i.e. forth should look like other languages
> > even at low level.
>
> The explanation is even more suggestive than the question itself.
> ...

Given the subject title of this thread I doubt the OP was seriously
seeking answers. Perhaps he's just testing the temperature :)

The answer (which everyone already knows) is that Chuck saw no
need for locals when forth was created, nor since. Given he's
fastidious when it comes to performance it must say something.

Locals in forth is the invention of some forth followers.

Marcel Hendrix

unread,
Apr 26, 2009, 7:13:25 AM4/26/09
to
Albert van der Horst <alb...@spenarnc.xs4all.nl> writes Re: Are locals evil?

> In article <a494b$49f30eb3$c4b2e92$98...@DIALUPUSA.NET>,
> Doug Hoffman <dhof...@talkamerica.net> wrote:

[..]


>> Agreed. I'm still waiting to see an example of how the use of locals
>> prevents or even just discourages factoring.

> A quotation from some euler problem. Obsfuscated, to prevent spoiler.

Real code, without errors, and with stack diagrams,
would be so much more instructive.

> \ -----------------------
> VARIABLE p
> VARIABLE t
> VARIABLE s

> : g() IF 0 ELSE s @ #g x^x THEN ;

> : f() .S p @ >R t @ >R s @ >R s ! t ! p !
> t @ 0 <= IF
> g()
> ELSE t @ s @ * p @ < IF
> 0
> ELSE
> 0 p @ s @ / 1+ 0 DO
> p @ I s @ * - t @ I - s @ 1- RECURSE
> I t @ #g + (/) * +
> LOOP
> THEN THEN
> R> s ! R> t ! R> p ! .S ;
> \ -----------------------

Ugh :-)

> The factoring into g() is impossible with true locals.
> The practice of the example is that g() has to be made
> a helluvalot more complicated.
> This demonstrates emulated local variables in a recursive
> context.

: g() ( s flag -- u ) IF DROP 0 EXIT ENDIF #g x^x ;

: f() ( p t s -- u ) RECURSIVE
LOCALS| s t p |
t 0<= IF s aap? g() EXIT ENDIF
t s * p < IF 0 EXIT ENDIF
0 p s / 1+ 0 DO p I s * - t I - s 1- f()
I t #g + (/) * +
LOOP ;

or, if you prefer,

DEFER TheWorkx ( p t s -- u )

: h() ( sum a b -- u ) #g + (/) * ;

: g() ( s flag -- u ) IF DROP 0 EXIT ENDIF #g x^x ;

: f() ( p t s -- u )
OVER 0<= IF NIP NIP aap? g() EXIT ENDIF
2DUP * 3 PICK < IF 0 EXIT ENDIF
TheWorkx ;

:NONAME ( p t s -- u )
LOCALS| s t p |
0 p s / 1+ 0 DO p I s * - t I - s 1- f()
I t h()
+
LOOP ; IS TheWorkx

-marcel

Andrew Haley

unread,
Apr 26, 2009, 7:34:07 AM4/26/09
to
DavidM <nos...@nowhere.com> wrote:

> Locals are:

IMO, none of the above. Most modern computers have a number of
hardware registers that a simple Forth virtual machine doesn't
use. [*] The locals word set provides a portable way to store a few
values in those registers. Not every implementation actually puts
locals into registers, but that's a quality of implementation issue.

Andrew.

[*] Yes, I know that a heavy-duty optimizing Forth VM can use every
register that a processor has and a bunch more, but that's a different
thing altogether.

Doug Hoffman

unread,
Apr 26, 2009, 9:43:07 AM4/26/09
to
Ed wrote:

> The answer (which everyone already knows) is that Chuck saw no
> need for locals when forth was created, nor since. Given he's
> fastidious when it comes to performance it must say something.
>
> Locals in forth is the invention of some forth followers.

The answer is not "The" answer, it is Chuck's answer.

The world is full of inventions that were later modified by those other
than the originator, with or without the approval of the originator.
Whether or not the modifications are an improvement surely varies and is
often likely to be the subject of debate. No surprises there.

-Doug

Jeff Fox

unread,
Apr 26, 2009, 12:49:31 PM4/26/09
to
On Apr 25, 2:46 pm, Doug Hoffman <dhoff...@talkamerica.net> wrote:
> I agree with everything Marcel said.  I'll add the following:
>
> 1) I didn't know that factoring was supposed to be a robotic cut and
> paste code segment replacement.  Shouldn't some thought be applied and
> then one can often find simplifications and improvements?

Sure everyone says that you have to think. To argue against the
need for thought is a straw man.

> 2) Actually I would approach the problem by making use of Leo's original
> comments about the base algorithms.  This helps to reduce errors and
> lessens my work.

Well I suppose that's my biggest problem with Marcel's code. I
have looked at examples with pages of code and not a single
comment. I agree that comments help. The proper amount is
a matter of style and of the level of the intended audience
for the code. If Marcel writes for himself then maybe he
doesn't need any comments, but it does help other people
understand the goals, the algorithms etc. I am with you
on that.

> 4) I don't understand Jeff Fox's code.  Are there really no stack input
> parameters?  It doesn't seem to work, but perhaps I'm missing something.

I just took Marcel's example factored to stack and locals and used
stack and global variables to make it simpler. Instead of LOCAL
it used GLOBAL @ to do the same thing. Instead of TO LOCAL it
used GLOBAL !. It is a very simple idea unless you have to do
recursion or want to prevent Forth style factoring you can use
globals or locals in much the same way.

As Albert already correctly stated:

"(j) Locals are superfluous.
Locals are mostly used where VARIABLE would do.
(Only in the rare case of recursion you need to put them
on the return stack."

I just trying to show that people look for awful stack
code to compare to what they think looks like good C
factoring. But better factoring can be done with
globals or locals instead of 100% stack nonsense
since locals are superfluous.

People promoting locals select the worst code they
can find to represent stack use, often without
any variables where most people would be inclined to
use some kind of variable. They are just comparisons
of bad stack code to code with stacks and variables.

The reason you can't refactor is that if you use
YEAR as a local, and you split the definition and
refactor in to two words you have two different
YEAR variables and the parameter is not going
to passed across two different words. So you
introduce a set of C rules about factoring that
defeat Forth factoring pretty well.

You have broken the concept of factoring by
insuring that your factors exist ONLY in the
scope of single definition. As a result you
can no longer pull out code from one word
and drop it into another using the Forth
rules about what you have to think about
in Forth. Now you have a bigger set of
rules some from C some from Forth to make
factoring more complicated unless the C
part is your habit more than the Forth part.
C factoring seems easier to C programmers
than Forth factoring. Forth factoring seems
easier to Forth programmers than C factoring.
You can mix them together and come up with
a bigger set that is harder than either one.
You can choose between being able to factor
as in Forth or being able to use locals
and factor like in C.

>   Marcel accurately points out the several pitfalls of Jeff's approach.

"Jeff's approach" was just Marcels local code with globals instead.
It was just a comparison of globals to locals rather than a comparison
of locals to silly stack only code that gets very involved. It
assumes
that it is safe to have global variables in Forth and that Forth
programmers understand the rules of Forth factoring. Sometimes that
might not be the case. If they don't get the rules for Forth
factoring well enough to find them easy they may abandon Forth
style so they can use the old C rules they always did. I have
heard many times that if you teach beginners how to stick to
their old C style with locals they will not learn how we
factor in Forth.

I was just demonstrating an example of what Albert said,
"Locals are superfluous." And trying to explain why the
inventor of Forth says that they are actually harmful.

Marcel says you have to setup globals. True. But you have to
setup locals too so it is mute point with little difference.
Yes, I removed his setup of locals and assumed that people
would know that the setup of global variables would have to
happen somewhere. But it is six of this vs a half dozen of that.

Marcel says that if you use traditional factoring that you will
have to follow the rules of traditional factoring. True. He
doesn't say that if you use locals and follow C factoring that
you will have to follow those rules. Yes you have to pay
attention to the order of your code in Forth while the idea
in C is to try to make small pieces of code more isolated
from other code. It looks to me like Marcel just explained
a little about traditional Forth factoring that people should
already know.

Marcel does give a detailed explanation of the complications
of traditional refactoring in Forth that makes it Forth. He
doesn't however give a detailed explanation of the
complications introduced by using locals and factoring like
in C. It just looks to me like a case of complaining
about a few complications in traditional Forth factoring
while trying to hide the problems that one causes when
one abandons traditional Forth factoring and refactoring
for C style factoring instead.

If you show both sides with the same level of detail or
show the bigger picture in each case it will mostly just
be an issue about abandoning Forth style factoring in
favor of C style factoring, because that's what locals
introduce and why they are harmful to your Forth code.

Isn't it obvious why limiting scope to a single definition
means that you can't split it into definitions without other
refactoring complications that have been left out of the
discussion? If you use traditional Forth factoring locals
will break it. You can always use C factoring instead and
do your Forth in C style.

If much of your Forth code is really written in C, if
you are being hosted in a system written in C, if you
want to mix your Forth with C calls you pretty much
need to deal with code factored in the C way and with
locals. It makes sense that if your top priorities is
dealing with C complications like locals that your
Forth will deal with locals.

The other excuse for using locals that people give
is that they find it easier to using C style
allocation of local variables to registers on
machines designed to run C and that they find
writing a compiler that allocates stack items to
registers. When they focus their attention on
optimizing locals more than stack they then say
they should use them because they intentionally
made the stack work slower than locals. This is
why Chuck says that the argument that they
optimized their locals more is no excuse for
doing it, it was just a choice to do C style
in the first place and after well down the road
rationalization that it was for performance
reasons instead of just prefering C style.

>   We avoid those pitfalls

apparently you
: Forth-factoring pitfalls ;
: C-factoring pitfalls not ;

> with the locals approach,

And introduce a much bigger set of bigger pitfalls from C.

> though I'm not saying locals are the only way to solve this
> problem.  Locals are a valuable set of tools,

For C and in a C/Forth mix that is true.

> at least to me, and enable me to quickly produce
> accurate solutions to real problems.  I can still factor my code.

Sure one can always abandon Forth style factoring for
C sytle factoring. Everyone uses the word factor, it is
just that it has different complications, different methods,
and different degrees to which it can be done in different
languages.

Just as when people go to the effort to optimize their
locals more than their stack so that they can rationalize
that they do it for performance reasons if they learn
to factor in the C way before they learn to factor in
the Forth way they will always be better at C style
factoring and will rationalize that it works better
than Forth style factoring without giving Forth style
factoring a change.

This is why the major vendors say that they try not
cover locals at all when they are trying to teach
new people Forth. If they teach them locals they tempt
them to do what they always did and assume from then on
that it is easier for them than the Forth factoring that
they never tried.

C for instance does not allow functions to be factored to be
as short as they are in Forth. If you see no difference between
Forth factoring and C factoring in the long list of the
methods and complications in either approach then perhaps
you can see that C can't be factored to the degree that
Forth can be factored. It this is not true please point
me at real examples of C code where most function definitions
are about a dozen characters long and I will admit that
I was wrong about C factoring being bigger than Forth
factoring. It only involves counting up the size of
the code so it is not an intellectually complex idea
or one that can be debated away. All evidence says it is
true unless you have some evidence I haven't seen yet.

Are you claiming that real C programs are factored to
the same extent as Forth programs written Forth not
C/Forth style? If so do you have any evidence of this?

If your argument is that you use locals and they work
for you that's fine. If it is your habit to use locals
then it is likely that don't understand why locals
disrupt Forth factoring, or don't care about that
because C factoring is fine with you. You get to
pick your own style and do it your way.

When people who prefer locals say that they don't
understand why traditional Forth programmers think
they are harmful we try to explain it.

Best Wishes

Jeff Fox

unread,
Apr 26, 2009, 1:01:02 PM4/26/09
to
On Apr 26, 4:34 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:

> DavidM <nos...@nowhere.com> wrote:
> > What are the prevailing thoughts within the Forth community on the use of
> > locals?
> > Locals are:
> > (a) Vile pollution and resource wastage in an otherwise elegant
> >     language, a result of lame concessions to intellectual cripples
> > (b) Horrible in every way, but in some situations very hard to avoid
> > (c) Neutral in themselves, good in some situations and wasteful in
>
>       others
>
> > (d) A great contribution to the language that can make code much
> >     more readable and maintainable, for a small performance cost
> > (e) A good programming practice in general, except for the most
> >     trivial of operations
>
> IMO, none of the above.  Most modern computers have a number of
> hardware registers that a simple Forth virtual machine doesn't
> use. [*]  

That's why the most popular Forths quit using a simple virtual
machine twenty years ago and started allocating stack items to
all those registers needed for C in those architectures.

> The locals word set provides a portable way to store a few
> values in those registers.  

Yes it is more simplistic than Forth compilers that do a
better job by allocating stack items to those registers.

Chuck says it is a backwards argument to say that because you
optimized locals but didn't optimize your stack because you
use locals and you use locals because they are more optimized
than your stack.

> Not every implementation actually puts
> locals into registers, but that's a quality of implementation
> issue.

Yes, locals can be much more complicated and add much more
overhead when they have to be allocated on the return stack
with stack frames. Bad vs worse.

> [*] Yes, I know that a heavy-duty optimizing Forth VM can use every
> register that a processor has and a bunch more, but that's a different
> thing altogether.

Yes. What would be the point of comparing optimized locals to
optimized stacks? That wouldn't show that optimized locals in
registers is faster than a threaded interpreted Forth with
stacks in memory. It would make it harder to rationalize
that locals have any performance advantage unless you rig the
game.

Best Wishes

Albert van der Horst

unread,
Apr 26, 2009, 4:07:08 PM4/26/09
to
In article <3010102...@frunobulax.edu>, Marcel Hendrix <m...@iae.nl> wrote:
>Albert van der Horst <alb...@spenarnc.xs4all.nl> writes Re: Are locals evil?
>
>> In article <a494b$49f30eb3$c4b2e92$98...@DIALUPUSA.NET>,
>> Doug Hoffman <dhof...@talkamerica.net> wrote:
>[..]
>>> Agreed. I'm still waiting to see an example of how the use of locals
>>> prevents or even just discourages factoring.
>
>> A quotation from some euler problem. Obsfuscated, to prevent spoiler.
>
>Real code, without errors, and with stack diagrams,
>would be so much more instructive.

This is real code. One of my solutions of an euler problem.
(As I set.)

>
>> \ -----------------------
>> VARIABLE p
>> VARIABLE t
>> VARIABLE s
>
>> : g() IF 0 ELSE s @ #g x^x THEN ;
>
>> : f() .S p @ >R t @ >R s @ >R s ! t ! p !
>> t @ 0 <= IF
>> g()
>> ELSE t @ s @ * p @ < IF
>> 0
>> ELSE
>> 0 p @ s @ / 1+ 0 DO
>> p @ I s @ * - t @ I - s @ 1- RECURSE
>> I t @ #g + (/) * +
>> LOOP
>> THEN THEN
>> R> s ! R> t ! R> p ! .S ;
>> \ -----------------------
>
>Ugh :-)

That is what I say when I encounter LOCAL. I don't think
this is much worse.

>
>> The factoring into g() is impossible with true locals.
>> The practice of the example is that g() has to be made
>> a helluvalot more complicated.

^^^^^^^^^^^^^^^^
I think you may have missed this.

>> This demonstrates emulated local variables in a recursive
>> context.
>

<Alternative SNIPPED>
The problem with your solution is that it is refactored.
The original solution is hard won mathematical insight.
I could not win that insight and refactor at the same time.

There are more alternatives.
Of course you can get around it by using macro's,
then you can use ``s'' with impunity:

: g() "IF 0 ELSE s #g x^x THEN" EVALUATE ;
(Anton has expressed concern about this type of macro,
but I think it doesn't apply because g() has very
limited scope.)

The bottom line could be that if you go far in math
you probably want infix after all.
I'll try Algol 68 if there is a suitable euler problem.

P.S.
Of course I make it a sport to solve eulerproject problems
with a 30 K Forth, not with just any Forth.

>
>-marcel

Groetjes Albert

BruceMcF

unread,
Apr 26, 2009, 3:50:05 PM4/26/09
to
On Apr 25, 12:26 pm, m...@iae.nl (Marcel Hendrix) wrote:
> If you cut up this DoW definition arbitrarily,

And what if you don't? What if you cut up this DoW definition
deliberately?

You are arguing presuming that the burden of proof lies on the side of
proving a need to factor.

I take the benefit of effective factoring for granted, and so presume
that the burden of proof lies on the side of showing that the
constraint on factoring is not a binding constraint.

Marcel Hendrix

unread,
Apr 26, 2009, 4:45:57 PM4/26/09
to
Albert van der Horst <alb...@spenarnc.xs4all.nl> writes Re: Are locals evil?

> In article <3010102...@frunobulax.edu>, Marcel Hendrix <m...@iae.nl> wrote:
>> Albert van der Horst <alb...@spenarnc.xs4all.nl> writes Re: Are locals evil?

>> Real code, without errors, and with stack diagrams,


>> would be so much more instructive.

> This is real code. One of my solutions of an euler problem.
> (As I set.)

Well, g() needs a flag which evidently isn't there :-)

[..]


>>> : g() IF 0 ELSE s @ #g x^x THEN ;

>>> : f() .S p @ >R t @ >R s @ >R s ! t ! p !
>>> t @ 0 <= IF
>>> g()

[..]

> The bottom line could be that if you go far in math
> you probably want infix after all.
> I'll try Algol 68 if there is a suitable euler problem.

If languages grow so advanced that they understand any mathematical
(and/or numerical) problem one throws at them, I'll certainly stop
using postfix unnecessarily. But we are not completely there yet,
and anyway, without (physical/resources/financial/time) constraints
engineering would stop being fun. Given the fact that power/monopoly
inevitably corrupts, I'll keep with Forth for a bit.

> P.S.
> Of course I make it a sport to solve eulerproject problems
> with a 30 K Forth, not with just any Forth.

Although appearances may point the other way, I am deeply
impressed by your incredible score in the Euler project,
especially given the enormous handicap you voluntarily
suffer under :-)

-marcel

Stephen Pelc

unread,
Apr 26, 2009, 6:26:36 PM4/26/09
to
On 24 Apr 2009 13:44:28 +1300, DavidM <nos...@nowhere.com> wrote:

>What are the prevailing thoughts within the Forth community on the use of
>locals?

>(c) Neutral in themselves, good in some situations and wasteful in others

Just because a language provides a feature, you are not compelled to
use it. In particular, MPE does not teach locals during introductory
Forth courses. Good use of locals in Forth requires you to be a
competent classical Forth programmer first. We have seen many
Forth programmers who come from C using locals to reduce the
culture shock of programming in Forth.

However, local buffers are pretty much a requirement for serious
programming on a hosted system that uses a C-style API to the
operating system. Careful use of local buffers can simplify
some of the OS interface code.

In some instances, heavy use of locals can reduce factoring
whereas heavy use of factoring can remove/reduce the need for
locals. Overall, on register-limited CPUs, e.g. x86 and ARM,
our *measurements* for the VFX code generator show that
removing locals reduces code size by 25% and improves speed
by up to 50%. VFX is not aggressive with locals for various
reasons, whereas it is aggressive with stack traffic. Other
optimising Forth compilers may show very different results.

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
web: http://www.mpeforth.com - free VFX Forth downloads

Doug Hoffman

unread,
Apr 26, 2009, 8:58:25 PM4/26/09
to
Jeff Fox wrote:
> On Apr 25, 2:46 pm, Doug Hoffman <dhoff...@talkamerica.net> wrote:

>> I don't understand Jeff Fox's code. Are there really no stack input
>> parameters? It doesn't seem to work, but perhaps I'm missing something.
>
> I just took Marcel's example factored to stack and locals and used
> stack and global variables to make it simpler. Instead of LOCAL
> it used GLOBAL @ to do the same thing.

Yes. I understood that. Here is what I didn't understand:

: DoW ( -- 0=Sunday...6=Saturday )
month @ 3 < IF -1 year +! THEN \ adjust year if Jan or Feb
year @ 100 /MOD cc ! year @
month @ 3 - 12 fmod 1+ month @ + cc @ 4 / + cc @ 2* -

year @ 4 / + year @ + 7 fmod ; ( Zeller's Congruence )

Where is day? No global variable and the stack comment shows nothing
being passed in, so I assumed that it was just an oversight and tried
the following:

variable year
variable month
variable cc

: DoW' ( d m y -- 0=Sunday...6=Saturday )

year ! month !


month @ 3 < IF -1 year +! THEN \ adjust year if Jan or Feb
year @ 100 /MOD cc ! year @
month @ 3 - 12 fmod 1+ month @ + cc @ 4 / + cc @ 2* -

year @ 4 / + year @ + 7 fmod ; ( Zeller's Congruence )

25 4 2009 Dow' .s => ( 4 ) \ 25 \ 9 \ 2009 \ 4 ok

At that point I stopped. Marcel's code (and mine) returned a single
stack item = 6 which I believe is correct.


> You have broken the concept of factoring by
> insuring that your factors exist ONLY in the
> scope of single definition. As a result you
> can no longer pull out code from one word
> and drop it into another

Did you actually *look* at my factored example? Here's one factored word:

: f1 ( y m -- y )

3 < IF 1- THEN ; \ adjust year if Jan or Feb

This can be dropped into any word you wish. Or test it stand-alone or
whatever. Kind of looks like a Forth definition.


> using the Forth
> rules about what you have to think about
> in Forth. Now you have a bigger set of
> rules some from C some from Forth to make
> factoring more complicated unless the C
> part is your habit more than the Forth part.
> C factoring seems easier to C programmers
> than Forth factoring.

I Googled "C factoring", not having heard the term before. The hits I
got were like this one:

"The crucial step in the second approach of Example C.1 was recognizing
that (x^2 - 2x + 1) was the same as the product of factors: (x - 1)( x
- 1). The operation of converting the "expanded" expression, (x^2 - 2x
+ 1), into a product of two factors is called "factoring" the algebraic
expression."

Seems reasonable but not relevant to our locals discussion. Maybe I
just didn't Google hard enough or something.


> Are you claiming that real C programs are factored to
> the same extent as Forth programs written Forth not
> C/Forth style? If so do you have any evidence of this?

I can't make any such claim. I have never coded a line of C in my life.
I wouldn't know how.

-Doug

Celime

unread,
Apr 27, 2009, 4:16:48 AM4/27/09
to

"Jeff Fox" <f...@ultratechnology.com> a �crit dans le message de news:
da050bf6-0bb9-4192...@k19g2000prh.googlegroups.com...

On Apr 25, 2:46 pm, Doug Hoffman <dhoff...@talkamerica.net> wrote:

[...]

>Sure one can always abandon Forth style factoring for
>C sytle factoring. Everyone uses the word factor, it is
>just that it has different complications, different methods,
>and different degrees to which it can be done in different
>languages.

[...]

In the next example, the assembly listing for the SUMPROD function
show that a basic C compiler optimize perfectly fine grained
factoring. (no calls, optimized registers usage...)

C�lime

----- C sample -----

static inline int PROD(int a, int b)
{
return a*b;
}

int SUMPROD(int x, int y, int u, int v)
{
return prod(x, y)+prod(u, v);

/* Compiler resulting asm code
mov eax, DWORD PTR _v$[esp-4]
mov ecx, DWORD PTR _y$[esp-4]
imul eax, DWORD PTR _u$[esp-4]
imul ecx, DWORD PTR _x$[esp-4]
add eax, ecx
*/
}


Ed

unread,
Apr 27, 2009, 4:19:34 AM4/27/09
to

An improvement is frequently demonstrable and then universally accepted.

Locals supporters have been arguing their case for decades without
achieving the acceptance they've always sought. Even among themselves
they haven't agreed upon a suitable syntax, or decided how far it should
extend. "A universe of its own" - as one person put it.

Forth came premised with certain principles. Take them away or mix
it up with incompatible or unnecessary elements from other languages
and what has one got?

Recently someone asked the question "When isn't it Forth anymore?".
This question wasn't from a newcomer but someone clearly familiar
with forth, the Standard and features found in current implementations.

When forthers can no longer discriminate what constitutes good forth
then clearly the guidelines have become lost or confused.

Locals in forth are neither optional, nor harmless. It fundamentally
alters the language. In fact it is another language - and a confusing
and complicated one at that.

Albert van der Horst

unread,
Apr 27, 2009, 4:59:26 AM4/27/09
to
In article <9878332...@frunobulax.edu>, Marcel Hendrix <m...@iae.nl> wrote:
>Albert van der Horst <alb...@spenarnc.xs4all.nl> writes Re: Are locals evil?
>
>> In article <3010102...@frunobulax.edu>, Marcel Hendrix <m...@iae.nl> wrote:
>>> Albert van der Horst <alb...@spenarnc.xs4all.nl> writes Re: Are locals evil?
>
>>> Real code, without errors, and with stack diagrams,
>>> would be so much more instructive.
>
>> This is real code. One of my solutions of an euler problem.
>> (As I set.)
>
>Well, g() needs a flag which evidently isn't there :-)

You're right. Made a mistake while obfuscating ...
Anyway, the code looks the same.

<SNIP>

Krishna Myneni

unread,
Apr 27, 2009, 6:34:34 AM4/27/09
to
Ed wrote:
> Doug Hoffman wrote:
>> Ed wrote:
>>
>>> The answer (which everyone already knows) is that Chuck saw no
>>> need for locals when forth was created, nor since. Given he's
>>> fastidious when it comes to performance it must say something.
>>>
...

>
> Locals in forth are neither optional, nor harmless. It fundamentally
> alters the language. In fact it is another language - and a confusing
> and complicated one at that.
>
>
>

I have no horse in this race. Speaking from personal experience, the
one case (and only case, thus far) where I have encountered great
difficulty is in trying to rewrite Julian Noble's FTRAN formula
translation without the use of locals. This is because FTRAN defines
words that are recursive *and* use locals. In such a situation, one
cannot simply replace the use of locals with variables. If someone
knows of a clean solution for such a situation, with classic Forth
(i.e. no locals), I'd be very interested to see such a solution.

Krishna

BruceMcF

unread,
Apr 27, 2009, 11:07:59 AM4/27/09
to
On Apr 27, 4:19 am, "Ed" <nos...@invalid.com> wrote:
> Forth came premised with certain principles. Take them away or mix
> it up with incompatible or unnecessary elements from other languages
> and what has one got?

A language that is easier to interface to systems dominated by other
languages with other language philosophies?

I am certainly in favor of *having* locals available for :

(1) interfacing with external operating systems / function libraries
via external calls designed for C and its descendents

(2) programming low level floating point functions that are most
commonly rendered as random access algebraic expressions.

That doesn't make locals a CORE concept, but it makes it a handy one.

OTOH, for using locals as private variables, I'd rather use VARIABLEs
and make them PRIVATE.

Andreas

unread,
Apr 27, 2009, 3:51:31 PM4/27/09
to
Celime schrieb:

> In the next example, the assembly listing for the SUMPROD function
> show that a basic C compiler optimize perfectly fine grained
> factoring. (no calls, optimized registers usage...)
>

> Cᅵlime


>
> ----- C sample -----
>
> static inline int PROD(int a, int b)
> {
> return a*b;
> }
>
> int SUMPROD(int x, int y, int u, int v)
> {
> return prod(x, y)+prod(u, v);
>
> /* Compiler resulting asm code
> mov eax, DWORD PTR _v$[esp-4]
> mov ecx, DWORD PTR _y$[esp-4]
> imul eax, DWORD PTR _u$[esp-4]
> imul ecx, DWORD PTR _x$[esp-4]
> add eax, ecx
> */
> }

For a "true" comparison one should also mention the de/allocation of the
pertaining stack frame for sumprod.

BTW I wonder whether anybody uses a Forth locals implementation without
removing them from the data stack.

Andreas

Marcel Hendrix

unread,
Apr 27, 2009, 4:15:52 PM4/27/09
to
Andreas <a...@nospam.org> writes Re: Are locals evil?

> Celime schrieb:
[..]


>> ----- C sample -----
>>
>> static inline int PROD(int a, int b)
>> {
>> return a*b;
>> }
>>
>> int SUMPROD(int x, int y, int u, int v)
>> {
>> return prod(x, y)+prod(u, v);
>>
>> /* Compiler resulting asm code
>> mov eax, DWORD PTR _v$[esp-4]
>> mov ecx, DWORD PTR _y$[esp-4]
>> imul eax, DWORD PTR _u$[esp-4]
>> imul ecx, DWORD PTR _x$[esp-4]
>> add eax, ecx
>> */
>> }

> For a "true" comparison one should also mention the de/allocation of the
> pertaining stack frame for sumprod.

> BTW I wonder whether anybody uses a Forth locals implementation without
> removing them from the data stack.

> Andreas

Depends what you mean with "removing them from the data stack."

iForth64:

: PROD ( a b -- c ) * ;
: SUMPROD1 ( x y u v -- n ) * -ROT * + ;
: SUMPROD2 PARAMS| x y u v | x y PROD u v PROD + ;

FORTH> ' SUMPROD1 idis
$0121F180 : [trashed]
$0121F18A pop rbx
$0121F18B pop rdi
$0121F18C imul rdi, rbx
$0121F190 pop rbx
$0121F191 pop rax
$0121F192 imul rax, rbx
$0121F196 lea rbx, [rdi rax*1] qword
$0121F19A push rbx
$0121F19B ;

FORTH> ' SUMPROD2 idis
$0121F200 : [trashed]
$0121F20A pop rbx
$0121F20B pop rdi
$0121F20C pop rax
$0121F20D pop rdx
$0121F20E mov r9, rdx
$0121F211 imul r9, rax
$0121F215 mov r10, rdi
$0121F218 imul r10, rbx
$0121F21C lea rbx, [r9 r10*1] qword
$0121F220 push rbx
$0121F221 ;

-marcel

Elizabeth D Rather

unread,
Apr 27, 2009, 6:02:16 PM4/27/09
to
Better still, what if you reconsider the whole process of managing
dates? FORTH, Inc. has always kept dates internally as an integer
number of days since Jan. 1, 1900, with conversion words for input and
output in various formats. So,

: DoW ( n1 -- n2 ) \ n2 = the day of the week for n1
7 mod ;

No locals needed.

Cheers,
Elzabeth


--
==================================================
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."
==================================================

Elizabeth D Rather

unread,
Apr 27, 2009, 6:12:00 PM4/27/09
to
Stephen Pelc wrote:
> On 24 Apr 2009 13:44:28 +1300, DavidM <nos...@nowhere.com> wrote:
>
>> What are the prevailing thoughts within the Forth community on the use of
>> locals?
>
>> (c) Neutral in themselves, good in some situations and wasteful in others
>
> Just because a language provides a feature, you are not compelled to
> use it. In particular, MPE does not teach locals during introductory
> Forth courses. Good use of locals in Forth requires you to be a
> competent classical Forth programmer first. We have seen many
> Forth programmers who come from C using locals to reduce the
> culture shock of programming in Forth.

Well said, and I entirely agree.

> However, local buffers are pretty much a requirement for serious
> programming on a hosted system that uses a C-style API to the
> operating system. Careful use of local buffers can simplify
> some of the OS interface code.

I agree here, too. SwiftForth uses locals for preparing OS calls, and a
very few other purposes. We do not support locals in SwiftX, because we
haven't found them helpful in embedded systems programming, nor have our
customers requested them.

> In some instances, heavy use of locals can reduce factoring
> whereas heavy use of factoring can remove/reduce the need for
> locals. Overall, on register-limited CPUs, e.g. x86 and ARM,
> our *measurements* for the VFX code generator show that
> removing locals reduces code size by 25% and improves speed
> by up to 50%. VFX is not aggressive with locals for various
> reasons, whereas it is aggressive with stack traffic. Other
> optimising Forth compilers may show very different results.

We have not had the experience of removing locals from a program, but
I'm not at all surprised by your results.

Cheers,
Elizabeth

BruceMcF

unread,
Apr 27, 2009, 11:26:25 PM4/27/09
to
On Apr 27, 6:02 pm, Elizabeth D Rather <erat...@forth.com> wrote:

> : DoW ( n1 -- n2 ) \ n2 = the day of the week for n1
> 7 mod ;

> No locals needed.

Of course, when working with British Customs House data on Caribbean
sugar prices in the 1700's and 1800's, that convention gives a
negative number for date ... but OTOH, DoW still works, since the
modulus just keeps wrapping around.

With a 32 bit Forth, I guess it would be possible to set a "calendar
start" somewhere back near the beginning of recorded history, to cover
Gilgamesh through George the III.

Andreas

unread,
Apr 28, 2009, 1:50:30 AM4/28/09
to
Marcel Hendrix schrieb:

> Andreas <a...@nospam.org> writes Re: Are locals evil?

Thanks, your iforth looks real good by using processor registers instead
of using a locals or the return stack in the first place. However when
you call another word within a word you still have to move and save
register contents before and after calls. So it is only 'delayed'.

The Forth standard forbids to leave local parameters in the data stack.
So there's nearly always some data shuffling between different stacks
involved. I was thinking about a simple locals scheme that leaves them
in their original place as a compound locals frame. Only when leaving
the word, the frame could be discarded by a single block move within the
stack memory.

Andreas


Elizabeth D Rather

unread,
Apr 28, 2009, 4:10:24 AM4/28/09
to
If you're going back as far as Gilgamesh, you have to worry about
pre-Julian and Gregorian calendars. Can of worms. May even require
locals ;-)

Cheers,
Elizabeth

peter...@tin.it

unread,
Apr 28, 2009, 5:46:41 AM4/28/09
to

Yes if you do not have anything that forces a call or similar it can
work nice. Also with using the returnstack. This is from my forth (ntf/
lxf) that uses virtual stacks during compilation.

: t1 * -rot * + ; ok
: t2 locals| v u y x | u v * x y * + ; ok
: t3 * >r * r> + ; ok
see t1
A49568 408029 23 C80000 5 normal T1

408029 8BC3 mov eax , ebx
40802B F76D00 imul dword [ebp]
40802E 894500 mov [ebp] , eax
408031 8B4504 mov eax , [ebp+4h]
408034 F76D08 imul dword [ebp+8h]
408037 034500 add eax , [ebp]
40803A 8BD8 mov ebx , eax
40803C 8D6D0C lea ebp , [ebp+Ch]
40803F C3 ret near
ok
see t2
A4957C 408040 23 C80000 5 normal T2

408040 8BC3 mov eax , ebx
408042 F76D00 imul dword [ebp]
408045 8945FC mov [ebp-4h] , eax
408048 8B4504 mov eax , [ebp+4h]
40804B F76D08 imul dword [ebp+8h]
40804E 0345FC add eax , [ebp-4h]
408051 8BD8 mov ebx , eax
408053 8D6D0C lea ebp , [ebp+Ch]
408056 C3 ret near
ok
see t3
A49590 408057 23 C80000 5 normal T3

408057 8BC3 mov eax , ebx
408059 F76D00 imul dword [ebp]
40805C 894500 mov [ebp] , eax
40805F 8B4504 mov eax , [ebp+4h]
408062 F76D08 imul dword [ebp+8h]
408065 034500 add eax , [ebp]
408068 8BD8 mov ebx , eax
40806A 8D6D0C lea ebp , [ebp+Ch]
40806D C3 ret near
ok
1 2 3 4 t1 . 14 ok
1 2 3 4 t2 . 14 ok
1 2 3 4 t3 . 14 ok

Peter Fälth

Ed

unread,
Apr 28, 2009, 8:52:18 AM4/28/09
to

The last version I found is v2.02. For the words that had locals and
RECURSE e.g.

: <expr> \ expr -> term | term & expr
$pop LOCALS| op beg end |
end beg [CHAR] + op_find ( ptr | false)
?DUP IF ( ptr) DUP c@ >R \ save op'
\ $stack:
( ptr) end OVER 1+ R> $push \ expr' op'
( ptr) 1- beg op $push \ term op
term RECURSE
ELSE end beg op $push term \ term op
THEN
;

try replacing with:

0 value end
0 value beg
0 value op

: <expr> \ expr -> term | term & expr
end >r beg >r op >r
$pop to op to beg to end
end beg [CHAR] + op_find ( ptr | false)
?DUP IF ( ptr) DUP c@ >R \ save op'
\ $stack:
( ptr) end OVER 1+ R> $push \ expr' op'
( ptr) 1- beg op $push \ term op
term
RECURSE
ELSE end beg op $push term \ term op
THEN
r> to op r> to beg r> to end
;

I think it will work.


Albert van der Horst

unread,
Apr 28, 2009, 10:08:01 AM4/28/09
to
In article <qKfJl.33886$9a.2...@bignews1.bellsouth.net>,

Krishna Myneni <krishn...@bellsouth.net> wrote:
>I have no horse in this race. Speaking from personal experience, the
>one case (and only case, thus far) where I have encountered great
>difficulty is in trying to rewrite Julian Noble's FTRAN formula
>translation without the use of locals. This is because FTRAN defines
>words that are recursive *and* use locals. In such a situation, one
>cannot simply replace the use of locals with variables. If someone
>knows of a clean solution for such a situation, with classic Forth
>(i.e. no locals), I'd be very interested to see such a solution.

Indeed it is in recursion where things get cumbersome.
A straightforward, simple and inelegant solution is to put the previous
value on the return stack.
p @ >R p !
..
R> p !

Groetjes Albert

>
>Krishna

BruceMcF

unread,
Apr 28, 2009, 9:33:57 AM4/28/09
to
On Apr 28, 4:10 am, Elizabeth D Rather <erat...@forth.com> wrote:
> BruceMcF wrote:
> > On Apr 27, 6:02 pm, Elizabeth D Rather <erat...@forth.com> wrote:

> >> : DoW ( n1 -- n2 ) \ n2 = the day of the week for n1
> >> 7 mod ;

> >> No locals needed.

> > Of course, when working with British Customs House data on Caribbean
> > sugar prices in the 1700's and 1800's, that convention gives a
> > negative number for date ... but OTOH, DoW still works, since the
> > modulus just keeps wrapping around.

> > With a 32 bit Forth, I guess it would be possible to set a "calendar
> > start" somewhere back near the beginning of recorded history, to cover
> > Gilgamesh through George the III.

> If you're going back as far as Gilgamesh, you have to worry about
> pre-Julian and Gregorian calendars. Can of worms. May even require
> locals ;-)

Can't see how it would *require* locals. OOP, perhaps, but then
the context specific variables come for free.

But of course, OOP doesn't *require* more than the CORE, given
that it can be built on the CORE (though several approaches can
*benefit* in performance terms from non-CORE primitives supporting
their most common internal operations, eg ``(a u ) @EXECUTE-NTH'')
... so arguing that the *capacity to support* OOP is evil is
arguing that the CORE has too much capability.

BruceMcF

unread,
Apr 28, 2009, 9:42:23 AM4/28/09
to
On Apr 28, 1:50 am, Andreas <a...@nospam.org> wrote:
> Thanks, your iforth looks real good by using processor registers instead
> of using a locals or the return stack in the first place. However when
> you call another word within a word you still have to move and save
> register contents before and after calls. So it is only 'delayed'.

But if locals are used primarily in low level words ... since
well designed high level words will not require them ... and
in OS calls, then deferring may still be a win. Indeed, if
primitives can be marked as "locals safe", and words defined
with all locals safe words marked as "locals safe", it could
be quite possible to get very good performance with the words
using locals, provided they are used sparingly.

> The Forth standard forbids to leave local parameters in the data stack.
> So there's nearly always some data shuffling between different stacks
> involved. I was thinking about a simple locals scheme that leaves them
> in their original place as a compound locals frame. Only when leaving
> the word, the frame could be discarded by a single block move within the
> stack memory.

But their original place is the data stack, so if new data is
brought onto the stack after the declaration of the locals,
it would write into the local frame.

Indeed, each execution of any local name would at the very least
overwrite the bottom-most slot in the frame, without special
casing for stack slots "above" and "below" the "hidden" stack
frame.

BruceMcF

unread,
Apr 28, 2009, 10:00:14 AM4/28/09
to
On Apr 28, 10:08 am, Albert van der Horst <alb...@spenarnc.xs4all.nl>
wrote:

> Indeed it is in recursion where things get cumbersome.
> A straightforward, simple and inelegant solution is to put the previous
> value on the return stack.
> p @ >R p !
> ..
> R> p !

A more elegant solution is a local stackpad, along the lines of

lpad: foo
lcell: a
lcell: b
ldouble: s
128 ldepth;

and then in a word defined with those names in scope:

... foo lpush a ! b ! ... RECURSE ... foo lpop ...

Albert van der Horst

unread,
Apr 28, 2009, 12:42:42 PM4/28/09
to
In article <49f69926$0$31866$9b4e...@newsspool3.arcor-online.net>,

Andreas <a...@nospam.org> wrote:
>
>The Forth standard forbids to leave local parameters in the data stack.
>So there's nearly always some data shuffling between different stacks
>involved. I was thinking about a simple locals scheme that leaves them
>in their original place as a compound locals frame. Only when leaving
>the word, the frame could be discarded by a single block move within the
>stack memory.

That is an attractive idea, I have been pondering too.
Most of the time one doesn't want to reach under the parameters
that are named and passed, so it might not be very restrictive
in that respect.
However I didn't manage to find a reasonable way to do it;
especially returning a value is problematic.

>
>Andreas

Groetjes

Andreas

unread,
Apr 28, 2009, 12:16:15 PM4/28/09
to
Albert van der Horst schrieb:

> In article <49f69926$0$31866$9b4e...@newsspool3.arcor-online.net>,
> Andreas <a...@nospam.org> wrote:
>> The Forth standard forbids to leave local parameters in the data stack.
>> So there's nearly always some data shuffling between different stacks
>> involved. I was thinking about a simple locals scheme that leaves them
>> in their original place as a compound locals frame. Only when leaving
>> the word, the frame could be discarded by a single block move within the
>> stack memory.
>
> That is an attractive idea, I have been pondering too.
> Most of the time one doesn't want to reach under the parameters
> that are named and passed, so it might not be very restrictive
> in that respect.
> However I didn't manage to find a reasonable way to do it;
> especially returning a value is problematic.

The values on top of the so enclosed locals would be moved too, i.e.
they would "drop" downwards.

Andreas

Marcel Hendrix

unread,
Apr 28, 2009, 12:34:14 PM4/28/09
to
peter...@tin.it writes Re: Are locals evil?

> On Apr 27, 10:15 pm, m...@iae.nl (Marcel Hendrix) wrote:
> > Andreas <a...@nospam.org> writes Re: Are locals evil?

[..]


> Yes if you do not have anything that forces a call or similar it can
> work nice.

[..]

Well, that can go a long way, as demonstrated below.

iForth version 3.0.3, generated 18:04:29, April 26, 2009.
x86_32 binary, native floating-point, double precision.
Copyright 1996 - 2009 Marcel Hendrix.

FORTH> : PROD * ; ok
FORTH> : connect PARAMS| u v x y | u v PROD x y PROD + ; ok
FORTH> : test1 PARAMS| a b | a b 2* b a 2- connect a a b b connect + 5 XOR ; ok

FORTH> : test2 22 11 test1 ; ok
FORTH> see test2
Flags: TOKENIZE, ANSI
: test2 22 11 test1 ; ok
FORTH> ' test2 idis
$005BF6C0 : [trashed]
$005BF6C8 push $00000518 d#
$005BF6CD ; \ i.e. the result was worked out while compiling.

FORTH> : test3 ( a -- c ) 33 test1 ; ok ( now it has to do something )
FORTH> see test3
Flags: TOKENIZE, ANSI
: test3 33 test1 ; ok
FORTH> ' test3 idis
$005BF740 : [trashed]
$005BF748 pop ebx
$005BF749 imul ecx, ebx, #66 b#
$005BF74C lea edi, [ebx -2 +] dword
$005BF74F mov eax, edi
$005BF751 shl eax, 5 b#
$005BF754 lea edi, [edi eax*1] dword
$005BF757 mov eax, ebx
$005BF759 imul eax, ebx
$005BF75C lea eax, [eax $00000441 +] dword
$005BF762 lea edx, [ecx edi*1] dword
$005BF765 lea edx, [edx eax*1] dword
$005BF768 xor edx, 5 b#
$005BF76B push edx
$005BF76C ;

Now more code has been compiled, but still no intermediate references to locals,
the return stack, or even the data stack.

-marcel

Thomas Pornin

unread,
Apr 28, 2009, 12:57:41 PM4/28/09
to
According to Elizabeth D Rather <erather...@removeme.forth.com>:

> If you're going back as far as Gilgamesh, you have to worry about
> pre-Julian and Gregorian calendars.

Just for nitpicking, worrying about differences between Julian and
Gregorian calendars is already needed for "working with British Customs
House data on Caribbean sugar prices in the 1700's" since what was
known at that time as the British Empire switched from Julian to
Gregorian in 1752.


--Thomas Pornin

Marcel Hendrix

unread,
Apr 28, 2009, 1:07:43 PM4/28/09
to
Elizabeth D Rather <era...@forth.com> writes Re: Are locals evil?
[..]

> Better still, what if you reconsider the whole process of managing
> dates? FORTH, Inc. has always kept dates internally as an integer
> number of days since Jan. 1, 1900, with conversion words for input and
> output in various formats. So,

> : DoW ( n1 -- n2 ) \ n2 = the day of the week for n1
> 7 mod ;

> No locals needed.

How does that help me when I need to know DoW of Jan. 26, 1956?

-marcel

BruceMcF

unread,
Apr 28, 2009, 2:21:56 PM4/28/09
to
On Apr 28, 1:07 pm, m...@iae.nl (Marcel Hendrix) wrote:
> Elizabeth D Rather <erat...@forth.com> writes Re: Are locals evil?

You use the word that converts Jan. 26, 1956 to a number of days since
Jan. 1, 1900.

If you have DtilY (days til Y) and DtilM (days til Month), wouldn't
that be something like:

: >Date# ( day month year )
DUP 1900 - 0< ABORT" Date after 1900, please"
DtilY SWAP DtilM + + ;

26 1 1956 >Date# DoW

Stephen Pelc

unread,
Apr 28, 2009, 7:51:45 PM4/28/09
to
On Tue, 28 Apr 2009 18:34:14 +0200, m...@iae.nl (Marcel Hendrix) wrote:

>iForth version 3.0.3, generated 18:04:29, April 26, 2009.
>x86_32 binary, native floating-point, double precision.
>Copyright 1996 - 2009 Marcel Hendrix.
>
>FORTH> : PROD * ; ok
>FORTH> : connect PARAMS| u v x y | u v PROD x y PROD + ; ok
>FORTH> : test1 PARAMS| a b | a b 2* b a 2- connect a a b b connect + 5 XOR ; ok

I would call that a way of avoiding using the stack! It's exactly what
locals-haters complain about. However, as a demo of iForth it would be
excellent.

The downside of all this is that VFX Version: 4.30 [build 2869] with
its new tokeniser and stack-oriented code can do better, except
perhaps for the nice multiply by 33. The VFX code is shorter.

: prod \ a b -- a*b
* ;
: sumprod \ x y u v -- a
prod -rot prod + ;
: test1 \ a b -- c
2dup 2* 2over swap 2- sumprod -rot
over swap dup sumprod +
5 xor ;
: test2 \ -- a
22 11 test1 ;
: test3
33 test1 ;

dis test2
TEST2
( 004BD8F0 8D6DFC ) LEA EBP, [EBP+-04]
( 004BD8F3 895D00 ) MOV [EBP], EBX
( 004BD8F6 BB18050000 ) MOV EBX, 00000518
( 004BD8FB C3 ) NEXT,
( 12 bytes, 4 instructions )
ok
dis test3
TEST3
( 004BD920 8BD3 ) MOV EDX, EBX
( 004BD922 83EB02 ) SUB EBX, 02
( 004BD925 6BDB21 ) IMUL EBX, EBX, # 21
( 004BD928 6BCA42 ) IMUL ECX, EDX, # 42
( 004BD92B 03D9 ) ADD EBX, ECX
( 004BD92D 8BCA ) MOV ECX, EDX
( 004BD92F 0FAFCA ) IMUL ECX, EDX
( 004BD932 81C141040000 ) ADD ECX, 00000441
( 004BD938 03D9 ) ADD EBX, ECX
( 004BD93A 83F305 ) XOR EBX, 05
( 004BD93D C3 ) NEXT,
( 30 bytes, 11 instructions )

There's no doubt that if you put in enough effort, you can make
locals code as fast as stack code. However, to do this, you throw
away the ability of locals and local buffers (as MPE uses them)
to be addressed. At least for OS interfacing, where locals are
most valuable, I don't want to throw this facility away, and I
certainly don't want to introduce yet another notation with
another set of "twiddly bits" attached.

What we've seen in this discussion is that, apart from OS interfacing
(and that means buffers too), locals can save you notationally for
thread-safe recursion. What I have noticed over the last few years
is that I personally am considerably reducing the number of locals I
use in favour of factoring and commenting/documentation.

As the results above show in both iForth and VFX, a tokeniser
can be a very good thing. With the advent of tokenisers, heavy
or extreme factoring can be done with no performance penalty.
This perhaps reduces the need for locals in high-performance
code.

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
web: http://www.mpeforth.com - free VFX Forth downloads

Andreas

unread,
Apr 29, 2009, 2:02:20 AM4/29/09
to
Stephen Pelc schrieb:

> As the results above show in both iForth and VFX, a tokeniser
> can be a very good thing. With the advent of tokenisers, heavy
> or extreme factoring can be done with no performance penalty.
> This perhaps reduces the need for locals in high-performance
> code.

Could you please explain a bit what you mean with tokenising here?
Thanks in advance
Andreas

Samuel Tardieu

unread,
Apr 29, 2009, 5:33:12 AM4/29/09
to
In another thread (about locals), Marcel wrote:

: connect PARAMS| u v x y | u v PROD x y PROD + ;

This is the kind of situation where I miss Factor combinators:

: connect ( u v x y -- n ) [ PROD ] 2bi@ + ;

Here, "[ ... ]" introduces an unnamed executable block (a lambda
expression), which is respectively applied to "u v" and then to "x
y" through "2bi@". Its effect is similar to

: connect ( u v x y -- n ) 2>r PROD 2r> PROD + ;

and better expresses the intent of what you are trying to do.

Another useful example is the "keep" combinator which preserves the data
element located on the stack and uses it for a call:

: do-something ( x -- f(x) x ) [ f ] keep ;

which is equivalent to:

: do-something ( x -- f(x) x ) >r r@ f r> ;

This is easy to do so in Factor because the stack is typed and can hold
any kind of element, including an unnamed block of code. Since it uses
garbage collection, memory management of those lambda blocks is not an
issue and they can even be dynamically built.

I am thinking of including those combinators into rforth1, my Forth
cross-compiler for Microchip PIC18f microcontrollers. It is easy to
design them to use simple words (instead of lambdas) called through
"execute":

: keep ( x f -- f(x) x ) over >r execute r> ; inline

: test ( x -- f(x) x ) ['] f keep ;

but I'd like to have real lambdas, to be able to do something like

: test ( x -- f(g(x)) x ) [[ g f ]] keep ;

From my Forth and Factor experience, it makes the code much more
readable by allowing an extra level of factorization, and reduces
explicit stack manipulation a lot.

Has anyone already implemented lambdas in Forth? Before reinventing the
wheel, I'd like to see if it has been done already, preferably in a
portable way. "[[ ... ]]" would define an unnamed word whose address
would be put on the stack so that "execute" could call it. Of course,
lambda expressions should also be nestable.

Sam
--
Samuel Tardieu -- s...@rfc1149.net -- http://www.rfc1149.net/

Andreas

unread,
Apr 29, 2009, 5:52:38 AM4/29/09
to
Samuel Tardieu schrieb:

> Has anyone already implemented lambdas in Forth? Before reinventing the
> wheel, I'd like to see if it has been done already, preferably in a
> portable way.


HTH

http://www.complang.tuwien.ac.at/anton/euroforth/ef06/lynas-stoddart06.pdf
http://www.forth.org.ru/~mlg/ef99/gassanenko99a.pdf

Andreas

Samuel Tardieu

unread,
Apr 29, 2009, 5:57:44 AM4/29/09
to
>>>>> "Andreas" == Andreas <a...@nospam.org> writes:

Andreas> http://www.complang.tuwien.ac.at/anton/euroforth/ef06/lynas-stoddart06.pdf

I knew this one, but it brings little information.

Andreas> http://www.forth.org.ru/~mlg/ef99/gassanenko99a.pdf

Will have a look, thanks.

Samuel Tardieu

unread,
Apr 29, 2009, 5:59:53 AM4/29/09
to
Andreas> http://www.forth.org.ru/~mlg/ef99/gassanenko99a.pdf

Sam> Will have a look, thanks.

Not that much relevant with lambda functions, it is an analysis of Forth
from a lambda calculus perspective.

Andrew Haley

unread,
Apr 29, 2009, 6:46:19 AM4/29/09
to
Samuel Tardieu <s...@rfc1149.net> wrote:

> Has anyone already implemented lambdas in Forth? Before reinventing
> the wheel, I'd like to see if it has been done already, preferably
> in a portable way. "[[ ... ]]" would define an unnamed word whose
> address would be put on the stack so that "execute" could call
> it. Of course, lambda expressions should also be nestable.

I've often wondered about that, but the use of locals would complicate
things. A considerable simplification would be that the local
variables in the block were read-only copies of the locals in the
enclosing scope rather than the same variables. I don't think it can
be done portably.

Andrew.

Samuel Tardieu

unread,
Apr 29, 2009, 7:13:14 AM4/29/09
to
>>>>> "Andrew" == Andrew Haley <andr...@littlepinkcloud.invalid> writes:

Andrew> I've often wondered about that, but the use of locals would
Andrew> complicate things. A considerable simplification would be that
Andrew> the local variables in the block were read-only copies of the
Andrew> locals in the enclosing scope rather than the same variables. I
Andrew> don't think it can be done portably.

Well, I would be satisfied with a solution that doesn't let you use
locals in your lambda expression.

Krishna Myneni

unread,
Apr 29, 2009, 8:02:10 AM4/29/09
to
Ed wrote:
> Krishna Myneni wrote:
>> Ed wrote:
>>> Doug Hoffman wrote:
>>>> Ed wrote:
>>>>
>>>>> The answer (which everyone already knows) is that Chuck saw no
>>>>> need for locals when forth was created, nor since. Given he's
>>>>> fastidious when it comes to performance it must say something.
>>>>>
>> ...
>>> Locals in forth are neither optional, nor harmless. It fundamentally
>>> alters the language. In fact it is another language - and a confusing
>>> and complicated one at that.
>>>
>>>
>>>
>> I have no horse in this race. Speaking from personal experience, the
>> one case (and only case, thus far) where I have encountered great
>> difficulty is in trying to rewrite Julian Noble's FTRAN formula
>> translation without the use of locals. This is because FTRAN defines
>> words that are recursive *and* use locals. In such a situation, one
>> cannot simply replace the use of locals with variables. If someone
>> knows of a clean solution for such a situation, with classic Forth
>> (i.e. no locals), I'd be very interested to see such a solution.
>
> The last version I found is v2.02.

Doug Hoffman has done a considerable amount of work to extend FTRAN.
His version is at

http://members.talkamerica.net/douglas...@talkamerica.net/

It was several years ago when I tried to make FTRAN work without
locals. I'd like to claim that I'm a decent enough Forth programmer to
have tried the relatively obvious change of using the return stack,
but my memory doesn't hold any proof of that. I'll have another look
at the code, and try your suggested change. Thanks.

Krishna

Josh Grams

unread,
Apr 29, 2009, 8:14:14 AM4/29/09
to
Samuel Tardieu wrote:
> Has anyone already implemented lambdas in Forth? Before reinventing the
> wheel, I'd like to see if it has been done already, preferably in a
> portable way. "[[ ... ]]" would define an unnamed word whose address
> would be put on the stack so that "execute" could call it. Of course,
> lambda expressions should also be nestable.

AFAIK it can't be done portably, but on some systems a :NONAME
definition wrapped in AHEAD ... THEN should work:

: [[ postpone ahead :noname ; immediate
: ]] postpone ; ] >r postpone then r> postpone literal ; immediate

Note that there is some precedent for using `]] ... [[` to
postpone a block of code, so you may want to pick other names.

--Josh

Roelf Toxopeus

unread,
Apr 29, 2009, 8:28:26 AM4/29/09
to
In article <87ocufpz...@willow.rfc1149.net>,
Samuel Tardieu <s...@rfc1149.net> wrote:


> Has anyone already implemented lambdas in Forth? Before reinventing the
> wheel, I'd like to see if it has been done already, preferably in a
> portable way. "[[ ... ]]" would define an unnamed word whose address
> would be put on the stack so that "execute" could call it. Of course,
> lambda expressions should also be nestable.

MacForth has:

:| --
Begins the definition of a phrase. Can only be used within a colon
definition. The phrase has its own set of local variables. A phrase
is terminated by |;. IMMEDIATE

|; -- token
Ends the definition of a Phrase started by :|. At run time,
encountering the phrase will cause execution to skip over the phrase
itself, leaving a token for the phrase on the top of the stack.
IMMEDIATE

Source not availlable, sorry.

Groet,

Roelf

Stephen Pelc

unread,
Apr 29, 2009, 9:31:15 AM4/29/09
to
On Wed, 29 Apr 2009 08:02:20 +0200, Andreas <a...@nospam.org> wrote:

>Could you please explain a bit what you mean with tokenising here?

Tokenising is just inspecting what was compiled for a word, and then
replaying it when the word is compiled. For the example:

: prod \ a b -- a*b
* ;
: sumprod \ x y u v -- a
prod -rot prod + ;
: test1 \ a b -- c
2dup 2* 2over swap 2- sumprod -rot
over swap dup sumprod +
5 xor ;
: test2 \ -- a
22 11 test1 ;
: test3
33 test1 ;

SUMPROD does not need to call PROD if it just replays what PROD
compiles. Similarly TEST1 can do the same with SUMPROD, which does
the same with PROD. You get benefit with a smart compiler because
it reduces the stack shuffling at word boundaries and gives more
optimisation opportunities, e.g. TEST2

see test2
TEST2
( 004BD8C0 8D6DFC ) LEA EBP, [EBP+-04]
( 004BD8C3 895D00 ) MOV [EBP], EBX
( 004BD8C6 BB18050000 ) MOV EBX, 00000518
( 004BD8CB C3 ) NEXT,


( 12 bytes, 4 instructions )

What has happened here is that the arguments 22 and 11 are both
literals, so the compiler has applied the operations at compile
time. Overall, the gains are worthwhile. Naturally, there are all
sorts of corner cases and exceptions that a tokeniser must recognise
and cope with.

Bernd Paysan

unread,
Apr 29, 2009, 10:49:22 AM4/29/09
to
Josh Grams wrote:
> Note that there is some precedent for using `]] ... [[` to
> postpone a block of code, so you may want to pick other names.

I use :[ ... ]: but :[ ... ]; would make sense as well. Lambda blocks are
pretty essential for MINOS.

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://www.jwdt.com/~paysan/

Anton Ertl

unread,
Apr 29, 2009, 3:40:07 PM4/29/09
to
Samuel Tardieu <s...@rfc1149.net> writes:
>In another thread (about locals), Marcel wrote:
>
> : connect PARAMS| u v x y | u v PROD x y PROD + ;
>
>This is the kind of situation where I miss Factor combinators:
>
> : connect ( u v x y -- n ) [ PROD ] 2bi@ + ;
>
>Here, "[ ... ]" introduces an unnamed executable block (a lambda
>expression), which is respectively applied to "u v" and then to "x
>y" through "2bi@".

In this case, there is no need for an anonymous definition, because
the definition is named anyway.

: 2bi@ { x1 x2 x3 x4 xt -- x5 x6 }
x1 x2 xt execute x3 x4 xt execute ;

: connect ['] prod 2bi@ + ;

>Another useful example is the "keep" combinator which preserves the data
>element located on the stack and uses it for a call:
>
> : do-something ( x -- f(x) x ) [ f ] keep ;

: keep ( x1 xt - x2 x1 )
over >r execute r> ;

>This is easy to do so in Factor because the stack is typed and can hold


>any kind of element, including an unnamed block of code.

This is easy to do in Forth, because the stack can hold any type of
element, including an execution token.

>Since it uses
>garbage collection, memory management of those lambda blocks is not an
>issue and they can even be dynamically built.

As long as you just need anonymous definitions, no memory management
is needed. Full-blown closures are a different issue.

- 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 2009: http://www.euroforth.org/ef09/

Marcel Hendrix

unread,
Apr 29, 2009, 5:55:59 PM4/29/09
to
steph...@mpeforth.com (Stephen Pelc) writes Re: Are locals evil?

> On Tue, 28 Apr 2009 18:34:14 +0200, m...@iae.nl (Marcel Hendrix) wrote:

[..]


>> FORTH> : PROD * ; ok
>> FORTH> : connect PARAMS| u v x y | u v PROD x y PROD + ; ok
>> FORTH> : test1 PARAMS| a b | a b 2* b a 2- connect a a b b connect + 5 XOR ; ok

> I would call that a way of avoiding using the stack! It's exactly what
> locals-haters complain about. However, as a demo of iForth it would be
> excellent.

I was just responding to the OP's concern:

| Andreas <a...@nospam.org> writes Re: Are locals evil?
| [..]


| Yes if you do not have anything that forces a call or similar it can
| work nice.

... by showing that calls and nested levels of locals are not *necessarily*
a problem.

I am just trying to inject some engineering common-sense into this
holy war.

> There's no doubt that if you put in enough effort, you can make
> locals code as fast as stack code. However, to do this, you throw
> away the ability of locals and local buffers (as MPE uses them)
> to be addressed. At least for OS interfacing, where locals are
> most valuable, I don't want to throw this facility away, and I
> certainly don't want to introduce yet another notation with
> another set of "twiddly bits" attached.

I agree. LOCALS| are not useful without the possibility of taking their
address; that's why I use the more limited PARAMS| form here (I have no
problem with "twiddly bits").

> What we've seen in this discussion is that, apart from OS interfacing
> (and that means buffers too), locals can save you notationally for
> thread-safe recursion.

A point that was not addressed yet it that you need locals to do parallel
programming. Not that many Forths offer this yet.

> What I have noticed over the last few years
> is that I personally am considerably reducing the number of locals I
> use in favour of factoring and commenting/documentation.

In the past few years I personally am considerably reducing
stack-based noise in favour of factoring and commenting /
documentation :-)

> As the results above show in both iForth and VFX, a tokeniser
> can be a very good thing. With the advent of tokenisers, heavy
> or extreme factoring can be done with no performance penalty.

Source inlining can do this too, but tokenizing has less "issues."

> This perhaps reduces the need for locals in high-performance
> code.

Locals don't belong in high-performance code. However, with a tokenizer
it can be hard to tell when a local is really a local.

-marcel

Helmar

unread,
Apr 29, 2009, 10:08:47 AM4/29/09
to
On Apr 23, 8:44 pm, DavidM <nos...@nowhere.com> wrote:
> Hi,
>
> What are the prevailing thoughts within the Forth community on the use of
> locals?
>
> Locals are:

(a)

At my opinion they introduce more evil than two keypresses per
VARIABLE are worth the shortcut.

-Helmar

Stephen Pelc

unread,
Apr 29, 2009, 6:51:28 PM4/29/09
to
On Wed, 29 Apr 2009 23:55:59 +0200, m...@iae.nl (Marcel Hendrix) wrote:

>I am just trying to inject some engineering common-sense into this
>holy war.

Thank you.

>> As the results above show in both iForth and VFX, a tokeniser
>> can be a very good thing. With the advent of tokenisers, heavy
>> or extreme factoring can be done with no performance penalty.
>
>Source inlining can do this too, but tokenizing has less "issues."

One penalty of being first is that sometimes you have to throw
things away. I have to say that I have been pleasantly surprised
by our tokeniser being simpler and smaller than the source inliner
it replaces. I like getting rid of "twiddly bits".

pliz

unread,
Apr 29, 2009, 2:48:41 PM4/29/09
to
Bernd Paysan wrote:
> I use :[ ... ]: but :[ ... ]; would make sense as well. Lambda blocks are
> pretty essential for MINOS.

These are really great not only in MINOS and I use them allot and miss
the feature in gforth.

Thanks!

--
Sergey

BruceMcF

unread,
Apr 29, 2009, 2:23:03 PM4/29/09
to
On Apr 29, 6:46 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:

Or local variables are out of scope within the lambda. After all, with
explicit pushing and popping of the frame, a local stackpad could
provide much the same functionality without the worries about scope.

BruceMcF

unread,
Apr 29, 2009, 11:56:55 AM4/29/09
to
On Apr 29, 6:46 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:

A local stackpad could be done portably, and since ls-pop for the
local stackpad frame is explicit, rather than tied to return from a
word, it could be used inside a lambda.

Ed

unread,
Apr 29, 2009, 10:39:55 PM4/29/09
to
Krishna Myneni wrote:
> Ed wrote:
> > Krishna Myneni wrote:
> >>> ...
> > ...

> It was several years ago when I tried to make FTRAN work without
> locals. I'd like to claim that I'm a decent enough Forth programmer to
> have tried the relatively obvious change of using the return stack,
> but my memory doesn't hold any proof of that. I'll have another look
> at the code, and try your suggested change. Thanks.

I made the relevant changes to v202 and tried several examples from
'ftrandoc.txt'. It appears to work fine (*).

The simple expedient of saving/restoring the 'locals' on the return
stack as shown should ensure that functions are re-entrant. Since
good forth code seeks to minimize the number of variables used
as temps, the overhead is likely to be minimal.

BTW it is possible to re-use the same 'locals' if one wishes. FTRAN
uses 'beg' 'end' 'op' for several functions. If one employs the save/restore
code as suggested for the recursive functions, then one need only define
the VALUES 'beg' 'end' 'op' once. (n.b. functions that use ?EXIT may
need adjusting.)

(*) FTRAN 202 has an ANS incompatibility. The function f->$
renders floats as '.3E1' instead of '0.3E1'. This will cause some
forths to complain when processing stuff like: f$" x=3"
It occurs irrespective of whether locals or values are used.

Krishna Myneni

unread,
Apr 29, 2009, 11:13:59 PM4/29/09
to
Ed wrote:
...

>>> try replacing with:
>>>
>>> 0 value end
>>> 0 value beg
>>> 0 value op
>>>
>>> : <expr> \ expr -> term | term & expr
>>> end >r beg >r op >r
>>> $pop to op to beg to end
>>> end beg [CHAR] + op_find ( ptr | false)
>>> ?DUP IF ( ptr) DUP c@ >R \ save op'
>>> \ $stack:
>>> ( ptr) end OVER 1+ R> $push \ expr' op'
>>> ( ptr) 1- beg op $push \ term op
>>> term
>>> RECURSE
>>> ELSE end beg op $push term \ term op
>>> THEN
>>> r> to op r> to beg r> to end
>>> ;
>>>
>>> I think it will work.
>>>
...
> I made the relevant changes to v202 and tried several examples from
> 'ftrandoc.txt'. It appears to work fine (*).
>

That's great! And the modification is simple and clean (understandable).

> The simple expedient of saving/restoring the 'locals' on the return
> stack as shown should ensure that functions are re-entrant. Since
> good forth code seeks to minimize the number of variables used
> as temps, the overhead is likely to be minimal.
>
> BTW it is possible to re-use the same 'locals' if one wishes. FTRAN
> uses 'beg' 'end' 'op' for several functions. If one employs the save/restore
> code as suggested for the recursive functions, then one need only define
> the VALUES 'beg' 'end' 'op' once. (n.b. functions that use ?EXIT may
> need adjusting.)

IMO, it is dangerous practice to reuse locals in the manner you
suggest. One would have to understand all of the references between
words that shared the same locals in order not to clobber values. This
is just too complicated in practice.

Indeed, one of the beautiful features of Forth is just that we can
reuse the names over and over again, without worry of incorrect
references, e.g.

0 value op
0 value beg
0 value end

: word1 to end to beg to op ... ;

0 value op
0 value beg
0 value end

: word2 to end to beg to op ... ;

etc.

Perhaps Forth programmers who have extensive experience with other
programming languages have an aversion to reusing names as in the
above example, because they are conditioned against such practices,
which are dangerous or illegal in the other languages. LOCALS may give
a false sense of added value in such a case.


>
> (*) FTRAN 202 has an ANS incompatibility. The function f->$
> renders floats as '.3E1' instead of '0.3E1'. This will cause some
> forths to complain when processing stuff like: f$" x=3"
> It occurs irrespective of whether locals or values are used.
>
>
>


Krishna

Ed

unread,
Apr 30, 2009, 12:14:51 AM4/30/09
to
Krishna Myneni wrote:
> Ed wrote:
> ...

> > BTW it is possible to re-use the same 'locals' if one wishes. FTRAN
> > uses 'beg' 'end' 'op' for several functions. If one employs the save/restore
> > code as suggested for the recursive functions, then one need only define
> > the VALUES 'beg' 'end' 'op' once. (n.b. functions that use ?EXIT may
> > need adjusting.)
>
> IMO, it is dangerous practice to reuse locals in the manner you
> suggest. One would have to understand all of the references between
> words that shared the same locals in order not to clobber values. This
> is just too complicated in practice.
> ...

Can't see how. Each definition which intends to use the 'local' saves
it before it's used e.g.

0 value u \ common 'local'

: func1 u >r ..... r> to u ;
: func2 u >r ..... r> to u ;
: func3 u >r ..... r> to u ;

It's not that different to how conventional locals work - except
they typically have more overhead.

Andrew Haley

unread,
Apr 30, 2009, 4:32:39 AM4/30/09
to
BruceMcF <agi...@netscape.net> wrote:
> On Apr 29, 6:46 am, Andrew Haley <andre...@littlepinkcloud.invalid>
> wrote:
> > Samuel Tardieu <s...@rfc1149.net> wrote:

> > > Has anyone already implemented lambdas in Forth? Before
> > > reinventing the wheel, I'd like to see if it has been done
> > > already, preferably in a portable way. "[[ ... ]]" would define
> > > an unnamed word whose address would be put on the stack so that
> > > "execute" could call it. Of course, lambda expressions should
> > > also be nestable.
> >
> > I've often wondered about that, but the use of locals would
> > complicate things. A considerable simplification would be that
> > the local variables in the block were read-only copies of the
> > locals in the enclosing scope rather than the same variables. I
> > don't think it can be done portably.

> A local stackpad could be done portably,

I don't think that helps. If we can't do lambdas of any kind
portably, of what use is a portable "local stackpad"?

> and since ls-pop for the local stackpad frame is explicit, rather
> than tied to return from a word, it could be used inside a lambda.

What is a local stackpad?

Andrew.

Samuel Tardieu

unread,
Apr 30, 2009, 5:48:50 AM4/30/09
to
>>>>> "Anton" == Anton Ertl <an...@mips.complang.tuwien.ac.at> writes:

Sam> Here, "[ ... ]" introduces an unnamed executable block (a lambda
Sam> expression), which is respectively applied to "u v" and then to "x y"
Sam> through "2bi@".

Anton> In this case, there is no need for an anonymous definition,
Anton> because the definition is named anyway.

Anton> : 2bi@ { x1 x2 x3 x4 xt -- x5 x6 }
Anton> x1 x2 xt execute x3 x4 xt execute ;
Anton> : connect ['] prod 2bi@ + ;

[...]

>> This is easy to do so in Factor because the stack is typed and can
>> hold any kind of element, including an unnamed block of code.

Anton> This is easy to do in Forth, because the stack can hold any type
Anton> of element, including an execution token.

I agree with everything you said, but my point was that I want to create
lambdas containing more than one word and write them inline in my code,
such as

: foo ( x1 x2 x3 x4 -- z ) [: prod 2* :] 2bi@ * ;

without creating a separate word for "prod 2*".

I've done that in rforth1 since, and it works fine, but I need to
optimize it some more so that no xt is ever manipulated (2bi@ is
expanded in line) because it targets 8 bits microcontrollers and
manipulating 16 bits addresses is costly.

Anton Ertl

unread,
Apr 30, 2009, 5:45:32 AM4/30/09
to
steph...@mpeforth.com (Stephen Pelc) writes:
>Just because a language provides a feature, you are not compelled to
>use it. In particular, MPE does not teach locals during introductory
>Forth courses. Good use of locals in Forth requires you to be a
>competent classical Forth programmer first.

In my experience with my students, that's not true. I have seen
students that recently started with Forth write nicely factored code
with locals; I have also seen students who did not use locals and
wrote long horrible definitions. And I have not really seen a
correlation between use of locals and bad factoring in them, even
though I try to teach them good factoring and warn them about locals.

Krishna Myneni

unread,
Apr 30, 2009, 8:44:55 AM4/30/09
to
I misunderstood your statement -- the example is much clearer. If you
do the above, yes, you can certainly reuse them. But, if there are
multiple exit points from a word, you will have to be careful to pop
the return stack and restore to value at each exit point. I prefer to
keep a set of values/variables for each word which needs them. The
only drawback in doing so, that I can see, is when memory (dictionary
space) is a tight constraint.

Another potentially useful benefit of defining a set of
values/variables to handle local quantities for each word is that they
could, in principle, be available for debugging. The problem, though,
is that there's doesn't seem to be a standard way to reference words
masked by redefinitions. For example,

0 value x

: word1 ( x -- ) TO x .... ;

0 value x

: word2 ( x -- ) TO x .... ;

If I want to debug word1, I cannot reference x (in a standard way)
without "forgetting" the re-definition of x. Maybe something like

'BEFORE WORD1 X

for returning the xt of X?

Krishna

BruceMcF

unread,
Apr 30, 2009, 9:16:17 AM4/30/09
to
On Apr 30, 4:32 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:

> What is a local stackpad?

I think I described the concept elsewhere in this rambling topic, its
a stackpad for a local variable frame. Someone listed all the
limitations of ordinary variables when used in a well-factored
recursive system, and it seemed a stackpad of frames with named slots
would address each of those limitations. This weekend I'm going to be
seeing about writing the words. They'd be something like:

ls-pad: foo
ls-var: x1
ls-var: y1
ls-var: x2
ls-var: y2
64 ls-depth;

to define the stackpad and its variables, and

... foo ls-push y1 ! x1 ! y2 ! x2 !
... x2 @ x1 @ -
... y2 @ y2 @ -
... RECURSE ... foo ls-pop ;

I expect its

: ls-pad: CREATE HERE 0 , 0 , 0 ;

: ls-var: ( sp-addr offset -- sp-addr offset' )
CREATE OVER , DUP , CELL+
DOES> 2@ @ + ;

: ls-2var: ( sp-addr offset -- sp-addr offset' )
CREATE OVER , DUP , CELL+ CELL+
DOES> 2@ @ + ;

... and will rummage through Jenny Brien's stackpad words this weekend
when I'm writing ls-depth; which builds the stackpad and ls-pop and ls-
push which adjusts the index into the stackpad.

Celime

unread,
Apr 30, 2009, 3:16:42 PM4/30/09
to

"BruceMcF" <agi...@netscape.net> a �crit dans le message de news:
3c649b3c-925a-4e4c...@v1g2000prd.googlegroups.com...

Just an approach to have dynamic/reentrant variable:
_______

10 stack var_stack \ reentrancy depth.

: VAR: ( "name" -- )
create
here var_stack push
0 ,
does>
@ allocate throw
var_stack push ;

: END-VAR ( -- )
var_stack pop ;

: RELEASE ( -- )
var_stack top
var_stack pop free throw ;

: DATA: ( size "name" -- )
create
var_stack top @ dup , +
var_stack top !
does> ( offset base -- addr )
@ var_stack top + ;

: VAR ( "name" -- )
cell data: ;

Elizabeth D Rather

unread,
Apr 30, 2009, 3:23:33 PM4/30/09
to
Anton Ertl wrote:
> steph...@mpeforth.com (Stephen Pelc) writes:
>> Just because a language provides a feature, you are not compelled to
>> use it. In particular, MPE does not teach locals during introductory
>> Forth courses. Good use of locals in Forth requires you to be a
>> competent classical Forth programmer first.
>
> In my experience with my students, that's not true. I have seen
> students that recently started with Forth write nicely factored code
> with locals; I have also seen students who did not use locals and
> wrote long horrible definitions. And I have not really seen a
> correlation between use of locals and bad factoring in them, even
> though I try to teach them good factoring and warn them about locals.
>
> - anton

Teaching students "good Forth" goes far beyond locals vs. no locals, of
course. And it isn't just a matter of factoring, either.

To learn "good Forth" one must develop a good sense for using the stack.
This is difficult to teach, since other languages do not require such
a skill.

The two biggest challenges in teaching newbies Forth is developing a
good working vocabulary (since Forth has so many more commands than most
languages) and developing good stack skills. Therefore, in an
introductory course I make a point of challenging students to learn to
use the stack effectively, via practice. Indeed, I don't present any
kind of data storage options at all (VARIABLEs, etc.) on the whole first
day, but give them a lot of problems that involve stack management,
postfix, etc.

On the second day, they meet VARIABLE, CREATE, ALLOT, and friends. And
instantly they eagerly define variables for everything, with much
fetching and storing. But quickly they learn (with my help) that this
is requiring more typing, more memory, more time, more everything, than
using the stack. So, we then have a productive discussion about when
variable *are* appropriate and helpful, and when they are not.

In theory, locals could have a place in this lesson, but I am convinced
they would merely serve to muddy the waters, and remain a crutch that
prevents the development of good stack skills and definition design.

It's like training wheels that never come off. I have long thought that
learning good stack management is like learning to ride a bicycle:
awkward and scary at first, but then it becomes natural and you can do
it without thinking. My objective in an introductory Forth course is to
reach that point as soon as possible. Locals would be an impediment in
this.

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."
==================================================

Ed

unread,
May 1, 2009, 12:07:01 AM5/1/09
to
Krishna Myneni wrote:
> > ...

> I misunderstood your statement -- the example is much clearer. If you
> do the above, yes, you can certainly reuse them. But, if there are
> multiple exit points from a word, you will have to be careful to pop
> the return stack and restore to value at each exit point.

Yes. That was the case with one definition in FTRAN. It had to be
converted to a single exit point before re-use could be employed.

> I prefer to
> keep a set of values/variables for each word which needs them. The
> only drawback in doing so, that I can see, is when memory (dictionary
> space) is a tight constraint.

I mention re-use as it's an option. Naturally the decision whether
to do so is at the discretion of the programmer. It's somewhat more
complicated to re-use.

> Another potentially useful benefit of defining a set of
> values/variables to handle local quantities for each word is that they
> could, in principle, be available for debugging. The problem, though,
> is that there's doesn't seem to be a standard way to reference words
> masked by redefinitions. For example,
>
>
> 0 value x
>
> : word1 ( x -- ) TO x .... ;
>
> 0 value x
>
> : word2 ( x -- ) TO x .... ;
>
> If I want to debug word1, I cannot reference x (in a standard way)
> without "forgetting" the re-definition of x. Maybe something like
>
> 'BEFORE WORD1 X
>
> for returning the xt of X?

The masking problem is not disimilar to that of standard
locals where their value can't readily be accessed either!

Easiest is to use unique variable names.

Andrew Haley

unread,
May 1, 2009, 3:47:50 AM5/1/09
to
BruceMcF <agi...@netscape.net> wrote:
> On Apr 30, 4:32 am, Andrew Haley <andre...@littlepinkcloud.invalid>
> wrote:
> > What is a local stackpad?

> I think I described the concept elsewhere in this rambling topic, its
> a stackpad for a local variable frame. Someone listed all the
> limitations of ordinary variables when used in a well-factored
> recursive system, and it seemed a stackpad of frames with named slots
> would address each of those limitations. This weekend I'm going to be
> seeing about writing the words. They'd be something like:

> ls-pad: foo
> ls-var: x1
> ls-var: y1
> ls-var: x2
> ls-var: y2
> 64 ls-depth;

> to define the stackpad and its variables, and

> ... foo ls-push y1 ! x1 ! y2 ! x2 !
> ... x2 @ x1 @ -
> ... y2 @ y2 @ -
> ... RECURSE ... foo ls-pop ;

I don't see how this can possibly help with lambdas, since you have no
way to know the depth of the local stackpad at the time the lambda
block gets executed. It's perfectly legal to return a lambda, after
all.

Andrew.

Anton Ertl

unread,
May 2, 2009, 11:57:50 AM5/2/09
to
Elizabeth D Rather <era...@forth.com> writes:

>Anton Ertl wrote:
>> I have seen
>> students that recently started with Forth write nicely factored code
>> with locals; I have also seen students who did not use locals and
>> wrote long horrible definitions. And I have not really seen a
>> correlation between use of locals and bad factoring in them, even
>> though I try to teach them good factoring and warn them about locals.
>>
>> - anton
>
>Teaching students "good Forth" goes far beyond locals vs. no locals, of
>course. And it isn't just a matter of factoring, either.
>
>To learn "good Forth" one must develop a good sense for using the stack.

Yes, if they use locals a lot, they probably won't learn "good Forth"
in this sense, because they don't need it. But then, this seems to be
a case of "l'art pour l'art", whereas factoring has additional
benefits, so if they learn only one thing in my course, they should
learn factoring rather than stack management.

Elizabeth D Rather

unread,
May 2, 2009, 2:46:54 PM5/2/09
to
Anton Ertl wrote:
> Elizabeth D Rather <era...@forth.com> writes:
>> Anton Ertl wrote:
>>> I have seen
>>> students that recently started with Forth write nicely factored code
>>> with locals; I have also seen students who did not use locals and
>>> wrote long horrible definitions. And I have not really seen a
>>> correlation between use of locals and bad factoring in them, even
>>> though I try to teach them good factoring and warn them about locals.
>>>
>>> - anton
>> Teaching students "good Forth" goes far beyond locals vs. no locals, of
>> course. And it isn't just a matter of factoring, either.
>>
>> To learn "good Forth" one must develop a good sense for using the stack.
>
> Yes, if they use locals a lot, they probably won't learn "good Forth"
> in this sense, because they don't need it. But then, this seems to be
> a case of "l'art pour l'art", whereas factoring has additional
> benefits, so if they learn only one thing in my course, they should
> learn factoring rather than stack management.

Stack management is a tactical skill; factoring is strategic. Both are
important for writing good code. I don't see this as an either/or
choice. And good stack management (as opposed to dependence on locals)
has extensive strategic benefits for performance, maintainability, etc.,
as Stephen has so eloquently pointed out.

I don't know how long your courses are, but I do like to think my
students can learn more than "only one thing".

BruceMcF

unread,
May 2, 2009, 6:56:10 PM5/2/09
to
On May 1, 3:47 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:

Why would you need to know the depth of the local stackpad at the time
the lambda block get executed? The stackpad keeps track of its own
depth.

Andrew Haley

unread,
May 5, 2009, 11:37:10 AM5/5/09
to

But how would you know when it was safe to do an ls-pop?

Consider something like this rather artificial example:

: foo ( x y - a) ls-push x1 ! x2 ! :[ x1 @ x2 @ foo ]: ;

At some point whatever you just ls-pushed has to be ls-popped. Is the
caller supposed to do that? Maybe it could be refactored to

: foo ( x y - a) ls-push x1 ! x2 !
:[ x1 @ x2 @ foo ls-pop ]: ;

but that's nasty. Apart from anything else you could only use the
closure once.

Andrew.

BruceMcF

unread,
May 5, 2009, 6:15:38 PM5/5/09
to
On May 5, 11:37 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:

> Consider something like this rather artificial example:
>
> : foo ( x y - a) ls-push x1 ! x2 ! :[ x1 @ x2 @ foo ]: ;
>
> At some point whatever you just ls-pushed has to be ls-popped. Is the caller supposed to do that?

*Of course* it should be popped by the word that pushed it.
And also, of course, you have to name which stackpad you
are using. Say its the ``bar'' local stackpad.

: foo ( x y - a)

bar ls-push x1 ! x2 ! :[ x1 @ x2 @ foo ]:
bar ls-pop ;

BTW, is that an infinite descent?

Andrew Haley

unread,
May 6, 2009, 7:27:32 AM5/6/09
to

But how is that supposed to work? By the time the closure is executed
the stackpad has already been popped.

> BTW, is that an infinite descent?

I'm sorry, the call to foo inside the closure was a mistake.

OK, I'll try again. Here's a better example, with foo's caller
included:


: foo ( x y - a)

bar ls-push x1 ! x2 ! :[ x1 @ x2 @ + ]:
bar ls-pop ;

1 2 foo execute .

I don't think this will print 3 but I think it should, because lambda
binds variables that appear in its body. In some circumstances this
won't matter, but IMO it's a bug.

[ This is the "upwards funarg problem" in which a closure, when
executed, refers to some state variables that have been deallocated.
http://en.wikipedia.org/wiki/Funarg_problem. As that Wikipedia
article notes, Pascal avoids the upwards funarg problem by only
allowing functions to be passed as arguements but not returned as
results. ]


This is the equivalent in Scheme of the Forth code. Foo is a function
that returns a function:

(define (foo x y) (lambda () (+ x y)))

Which we can then execute:

guile> (apply (foo 1 2) '())
3

More simply:

guile> ((foo 1 2))
3

Andrew.

BruceMcF

unread,
May 6, 2009, 1:55:20 PM5/6/09
to
On May 6, 7:27 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:

> I'm sorry, the call to foo inside the closure was a mistake.

If its not recursive, why do you need the local variables?

If its to address the problem of losing the local variable scope when
you still have the lambda ...

ls-pad: foo
ls-var: fb-x
ls-var: fb-y
ls-var: bar
ls-var: fb-done
16 ls-depth;

: init-foobar-alt1 ( x y -- )
foo ls-push x fb-x ! fb-y !
:[ x1 @ x2 @ + ]: bar !
:[ foo ls-pop ]: fb-done !
;

4 5 init-foobar-alt1
bar @ DUP execute .
20 fb-x ! execute .
fb-done @ execute

... but unless its recursive, you get the same with most any structure
package, including mini-oof.

Andrew Haley

unread,
May 7, 2009, 4:59:03 AM5/7/09
to
BruceMcF <agi...@netscape.net> wrote:
> On May 6, 7:27 am, Andrew Haley <andre...@littlepinkcloud.invalid>
> wrote:
> > I'm sorry, the call to foo inside the closure was a mistake.

> If its not recursive, why do you need the local variables?

In this particular case you don't, of course, it was just a simple
example of the way that lambda binds values that appear in
expressions.

> If its to address the problem of losing the local variable scope when
> you still have the lambda ...

Yes, that's exactly the problem.

> ls-pad: foo
> ls-var: fb-x
> ls-var: fb-y
> ls-var: bar
> ls-var: fb-done
> 16 ls-depth;

> : init-foobar-alt1 ( x y -- )
> foo ls-push x fb-x ! fb-y !
> :[ x1 @ x2 @ + ]: bar !
> :[ foo ls-pop ]: fb-done !
> ;

This is just what I suggested earlier on: the caller has to deallocate
the frame. That's why you can't, in general, implement lambda
expressions with a stackpad.

Andrew.

Gerry

unread,
May 8, 2009, 4:10:16 AM5/8/09
to
Josh Grams wrote:

> Samuel Tardieu wrote:
>> Has anyone already implemented lambdas in Forth? Before reinventing
>> the wheel, I'd like to see if it has been done already, preferably
>> in a portable way. "[[ ... ]]" would define an unnamed word whose
>> address would be put on the stack so that "execute" could call it.
>> Of course, lambda expressions should also be nestable.
>
> AFAIK it can't be done portably,

Doesn't this depend on how much effort is put into it, perhaps you
should add the word "easily". For example a new outer
interpreter/compiler could be written in ANS Forth that could handle
lambda blocks inside colon definitions etc.

Another approach might be to have an alternative definitions of : and
; that copy the bodies of the colon definition and lambda blocks into
separate buffers and then EVALUATEing the text in the buffers.
Incorporating locals into the scheme as discussed elsewhere would be
more difficult but feasible, I think.

> but on some systems a :NONAME
> definition wrapped in AHEAD ... THEN should work:
>
>> [[ postpone ahead :noname ; immediate
>> ]] postpone ; ] >r postpone then r> postpone literal ; immediate
>
> Note that there is some precedent for using `]] ... [[` to
> postpone a block of code, so you may want to pick other names.
>
> --Josh

Gerry


Andrew Haley

unread,
May 8, 2009, 5:47:05 AM5/8/09
to
Gerry <ge...@jackson9000.fsnet.co.uk> wrote:
> Josh Grams wrote:
> > Samuel Tardieu wrote:
> >> Has anyone already implemented lambdas in Forth? Before reinventing
> >> the wheel, I'd like to see if it has been done already, preferably
> >> in a portable way. "[[ ... ]]" would define an unnamed word whose
> >> address would be put on the stack so that "execute" could call it.
> >> Of course, lambda expressions should also be nestable.
> >
> > AFAIK it can't be done portably,

> Doesn't this depend on how much effort is put into it, perhaps you
> should add the word "easily". For example a new outer
> interpreter/compiler could be written in ANS Forth that could handle
> lambda blocks inside colon definitions etc.

I take your point.

> Another approach might be to have an alternative definitions of : and
> ; that copy the bodies of the colon definition and lambda blocks into
> separate buffers and then EVALUATEing the text in the buffers.
> Incorporating locals into the scheme as discussed elsewhere would be
> more difficult but feasible, I think.

Probably, yes.

Andrew.

BruceMcF

unread,
May 8, 2009, 2:18:26 PM5/8/09
to
On May 7, 4:59 am, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:

> Yes, that's exactly the problem.

Why is it a problem?

> This is just what I suggested earlier on: the caller has to deallocate
> the frame.  That's why you can't, in general, implement lambda
> expressions with a stackpad.

The stackpad is in general to implement recursive systems. A specific
lambda expression that functioned effectively as a factor of a
recursive system could use a local-stackpad. If its a functioning
recursive system, then the algorithm says where to push and where to
pop.

They are still a species of local variables, they are just a species
of local variable that gives explicit control of scoping.

Gerry

unread,
May 17, 2009, 6:39:48 AM5/17/09
to
On 8 May, 10:47, Andrew Haley <andre...@littlepinkcloud.invalid>
wrote:

> Gerry <ge...@jackson9000.fsnet.co.uk> wrote:
> > Josh Grams wrote:
> > > Samuel Tardieu wrote:
> > >> Has anyone already implemented lambdas in Forth? Before reinventing
> > >> the wheel, I'd like to see if it has been done already, preferably
> > >> in a portable way. "[[ ... ]]" would define an unnamed word whose
> > >> address would be put on the stack so that "execute" could call it.
> > >> Of course, lambda expressions should also be nestable.
>
> > > AFAIK it can't be done portably,

[...]

> > Another approach might be to have an alternative definitions of : and
> > ; that copy the bodies of the colon definition and lambda blocks into
> > separate buffers and then EVALUATEing the text in the buffers.
> > Incorporating locals into the scheme as discussed elsewhere would be
> > more difficult but feasible, I think.
>
> Probably, yes.
>
> Andrew.

I was thinking about my suggestion again and thought it would be
fun to attempt an implementation that is ANS compliant. With the
use of a library file to manage text buffers and mini-oof it was
reasonably straightforward. Its very experimental I wouldn't say
it's the most efficient solution and I'd appreciate any comments
on whether it provides a useful abstraction or is just an
academic exercise, and would welcome any suggestions for
improvements to functionality, usability, syntax etc.

It allows definitions such as:

:n fact 1 max [: dup 1- ?dup if recurse * then ;] exec . n;
7 fact 5040 ok

Several lambda blocks can be included in one definition, and
they can be nested indefinitely e.g.

:n ex2
[: cr ." First, " ;]
[: ." second "
[: ." and third" ;]
;]
n;

ex2 swap exec exec exec
First, second and third ok

"Local" variables can be declared using {< and >} and shared
between lambdas. {< ... >} can be used several times and occur
anywhere. As with ANS locals thay are automatically loaded from
the stack but are variables instead of values e.g.

:n ex4 {< a b >}
cr ." a, b = " dup a @ . ." , " b @ .
[: >r r@ a @ r@ b @ + {< c >} ." and c = " r> c @ . ;]
n;

3 4 ex4 exec
a, b = 3 , 4 and c = 7 ok

It's available at http://www.qlikz.org/forth/exp/exp.html. See
the file demo.fth for some notes.

I think it is ANS compliant, it works with Gforth, VFX Forth and
SwiftForth and mostly with Win32 Forth (where the factorial
example fails because Win32 Forth can't correctly handle RECURSE
inside a :NONAME definition - at least not in version 6.12)

Gerry

Marcel Hendrix

unread,
May 17, 2009, 7:31:15 AM5/17/09
to
Gerry <ge...@jackson9000.fsnet.co.uk> writes Re: Factor combinators in Forth and lambda blocks
[..]

> I think it is ANS compliant, it works with Gforth, VFX Forth and
> SwiftForth and mostly with Win32 Forth (where the factorial
> example fails because Win32 Forth can't correctly handle RECURSE
> inside a :NONAME definition - at least not in version 6.12)

The actual output on iForth 3.03 is appended.
What about the redefinition messages for a and b?

-marcel

-- ------------------------------------
FORTH> CR in demo.fth
Loading demo.fth...
Loading extended mini oof ...
Extended mini oof loaded.
Data: ---
System: ---
Float: ---Loading Sections.fth

Redefining here
Redefining allot
Redefining align
Redefining c,
Redefining ,
Redefining unused
Redefining showSections.fth loaded.
Data: ---
System: ---
Float: ---Loading lambda.fth...
lambda.fth loaded.
Data: ---
System: ---
Float: ---
Hello world ... and goodbye

5040 should be displayed: 5040

First, second and third

a, b = 1 , 2

Redefining a
Redefining b


a, b = 3 , 4 and c = 7

100 101 102

5 6 103 7 104

positive
zero
negative

demo.fth completed.
Data: ---
System: ---
Float: --- ok
FORTH>

Gerry

unread,
May 17, 2009, 8:44:52 AM5/17/09
to
Marcel Hendrix wrote:
> Gerry <ge...@jackson9000.fsnet.co.uk> writes Re: Factor combinators
> in Forth and lambda blocks [..]
>> I think it is ANS compliant, it works with Gforth, VFX Forth and
>> SwiftForth and mostly with Win32 Forth (where the factorial
>> example fails because Win32 Forth can't correctly handle RECURSE
>> inside a :NONAME definition - at least not in version 6.12)
>
> The actual output on iForth 3.03 is appended.
> What about the redefinition messages for a and b?
>
>

Yes, ignoring the warnings, it seems to work correctly with iForth.
The redefinition messages are because those variables are redefined. I
haven't yet put such variables in separate wordlists so they are still
globally available - I'll put that on the todo list. As I said it's
all still rather experimental

Gerry

0 new messages