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

Locals with a broader scope

109 views
Skip to first unread message

Brad Eckert

unread,
Feb 16, 2013, 1:40:38 PM2/16/13
to
Hi All,

I think locals should have scope over a group of words, not a single word. The last word in the scope can be assumed to set up the locals frame and then take it down at the end. Does anyone have a syntax to do this?

-Brad

Brad Eckert

unread,
Feb 16, 2013, 4:50:11 PM2/16/13
to
On Saturday, February 16, 2013 11:40:38 AM UTC-7, Brad Eckert wrote:
> Does anyone have a syntax to do this?
>
Let me propose one:

LOCAL MyVars{
VAR First
VAR Second

: BAR ( -- ) First Second + . ;
: FOO ( n1 n2 -- ) MyVars{ First Second } BAR ;

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

The rationale is to eliminate statically bound local variables. While it's true that these cost little on a PC, in an MCU RAM is more expensive than ROM by a factor of 10:1 (in die area) and is often the scarcer resource.

The other thing is to promote reentrancy, since you give that up as soon as you start using statically bound local variables such as:

VARIABLE X
: FOO ... X @ ... ;
: BAR ... X ! ... ;
VARIABLE X \ old X's scope is terminated

There's a lot of discussion about local variables here, and the consensus seems to be that they aren't very useful within the scope of a single word. SwiftX doesn't even have locals. However, this proposed syntax adds only two words: LOCAL and VAR. It's also nestable.

I think the syntax can be implemented with little or no carnal knowledge, as explained below. I may implement it later, unless someone beats me to it.

(

LOCAL MyVars{ defines a wordlist and puts it in the search order.

VAR adds a variable name to the MyVars{ wordlist.

First compiles code to fetch from the top of the frame stack.
Second compiles code to fetch from next on the frame stack.

TOVAR is aliased the MyVars{ wordlist as TO. Since this wordlist
is visible until MyVars{ executes inside of FOO, this TO takes
precedence over the system's TO. If it doesn't find the local
variable name, it executes the system TO. EXIT and ; are also
aliased, so that they will destroy the stack frame when needed.
This ; version also removes MyVars from the search order.

MyVars{ compiles code to create a stack frame and marks the current
word as the one to destroy the frame at exit. It loads VARs with
either zeros or stack items depending on what's between the braces.

As each local name between the braces is encountered, its ID is pushed
onto the control stack. The closing brace compiles code, using IDs
pulled from the control stack, to pop data off the stack and store it
to the appropriate offset in the frame stack.

MyVars{ throws an error if you try to invoke it twice.
)

Bernd Paysan

unread,
Feb 16, 2013, 8:00:59 PM2/16/13
to
The only thing that is maybe somewhat close to your idea is some simple
early-binding OOP system, where you have instance variables, and all the
methods (which are just words, because it's early bound) can easily access
them. That's the only place I know where a group of words have common
variables that are somewhat "local" to that group.

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

Anton Ertl

unread,
Feb 17, 2013, 8:24:35 AM2/17/13
to
Brad Eckert <hwf...@gmail.com> writes:
>There's a lot of discussion about local variables here, and the consensus s=
>eems to be that they aren't very useful within the scope of a single word. =

Why do you think that there is such a consensus? Many Forth systems
have locals with a single word as scope, and none have locals with
more than one word as scope, which directly contradicts your claimed
consensus. Certainly within the Forth-94 and Forth-200x committees
the consensus was that locals (within a word) are useful enough to
justify standardizing it as an optional feature.

Concerning your proposal, maybe it will take the Forth world by storm.
Or maybe those who hate locals will hate it, too; and the others may
or may not like it.

- 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 2013: http://www.euroforth.org/ef13/

Andrew Haley

unread,
Feb 17, 2013, 10:47:21 AM2/17/13
to
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
> Brad Eckert <hwf...@gmail.com> writes:

>>There's a lot of discussion about local variables here, and the
>>consensus seems to be that they aren't very useful within the scope
>>of a single word.
>
> Why do you think that there is such a consensus? Many Forth systems
> have locals with a single word as scope, and none have locals with
> more than one word as scope, which directly contradicts your claimed
> consensus. Certainly within the Forth-94 and Forth-200x committees
> the consensus was that locals (within a word) are useful enough to
> justify standardizing it as an optional feature.
>
> Concerning your proposal, maybe it will take the Forth world by
> storm. Or maybe those who hate locals will hate it, too; and the
> others may or may not like it.

We seem to be avoiding answering any question about the utility of
such a thing. I suppose it's somewhat analogous to nested procedure
scopes in Algol, but the inner procedures can't be called from
outside. It strikes me as more like dynamic scoping in Lisp, which is
rather horrible, and I much prefer Scheme's lexical scoping.

Andrew.

Doug Hoffman

unread,
Feb 17, 2013, 4:51:28 PM2/17/13
to
On 2/16/13 1:40 PM, Brad Eckert wrote:
> I think locals should have scope over a group of words, not a single word. The last word in the scope can be assumed to set up the locals frame and then take it down at the end. Does anyone have a syntax to do this?

Michael Hore implemented this in Mops back in the 1990s. You may want
to look it up. I can't recall ever needing/using that feature. Doesn't
mean it's not worthwhile though. The current iMops port may still have
it, not sure. Macintosh only.

-Doug

A. K.

unread,
Feb 18, 2013, 1:58:48 AM2/18/13
to
The FSL uses private / public sections of definitions a lot. Of course a
private section can contain variables that are invisible (perhaps
headerless) from the public area.

Elizabeth D. Rather

unread,
Feb 18, 2013, 2:34:34 AM2/18/13
to
On 2/16/13 11:50 AM, Brad Eckert wrote:
> On Saturday, February 16, 2013 11:40:38 AM UTC-7, Brad Eckert wrote:
>> Does anyone have a syntax to do this?
>>
> Let me propose one:
>
> LOCAL MyVars{
> VAR First
> VAR Second
>
> : BAR ( -- ) First Second + . ;
> : FOO ( n1 n2 -- ) MyVars{ First Second } BAR ;
>
> -----------------------------------------
>
> The rationale is to eliminate statically bound local variables. While it's true that these cost little on a PC, in an MCU RAM is more expensive than ROM by a factor of 10:1 (in die area) and is often the scarcer resource.
>
> The other thing is to promote reentrancy, since you give that up as soon as you start using statically bound local variables such as:
>
> VARIABLE X
> : FOO ... X @ ... ;
> : BAR ... X ! ... ;
> VARIABLE X \ old X's scope is terminated
>
> There's a lot of discussion about local variables here, and the consensus seems to be that they aren't very useful within the scope of a single word. SwiftX doesn't even have locals. However, this proposed syntax adds only two words: LOCAL and VAR. It's also nestable.

Truly, I don't see the point of all this paranoia about reentrancy,
particularly in systems without a multitasker. VARIABLE was *designed*
for things that would be used in multiple definitions. I remember the
horror of (*gasp*) global variables back in the 1960's in Fortran. But,
frankly, in 30+ years of programming in Forth I never found them a
problem. I think this is all about mythical dragons.

Of course, most of the time I don't like local variables anyway, let
along "neighborhood" variables.

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

Andrew Haley

unread,
Feb 18, 2013, 4:29:35 AM2/18/13
to
Elizabeth D. Rather <era...@forth.com> wrote:
>
> Truly, I don't see the point of all this paranoia about reentrancy,
> particularly in systems without a multitasker. VARIABLE was
> *designed* for things that would be used in multiple definitions. I
> remember the horror of (*gasp*) global variables back in the 1960's
> in Fortran. But, frankly, in 30+ years of programming in Forth I
> never found them a problem. I think this is all about mythical
> dragons.

Well, I know what you mean, kinda sorta, but the world has changed.
Processors with more than one core are common now, even in many
embedded designs. To program such computers effectively really
requires multi-tasking and re-eentrant coding. That standard Forth
still doesn't address this is a shortcoming.

Andrew.

Albert van der Horst

unread,
Feb 18, 2013, 7:05:50 AM2/18/13
to
In article <__idnTtoCNkWRLzMn...@supernews.com>,
Elizabeth D. Rather <era...@forth.com> wrote:
I couldn't agree more. May I add, in the context of parallelism:
parallel computers need separate copies of a program anyway.

>
>Of course, most of the time I don't like local variables anyway, let
>along "neighborhood" variables.

VARIABLE's that are present in a wordlist, and invisible if you don't
link in the wordlist, are quite okay IMO.

>
>Cheers,
>Elizabeth
>

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

Anton Ertl

unread,
Feb 18, 2013, 8:40:52 AM2/18/13
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>We seem to be avoiding answering any question about the utility of
>such a thing.

Has such a question been posed? I don't think so. Anyway, let's
answer it:

One of the arguments against locals is that you cannot just grab a
subsequence in a Forth word and factor it into a separate word, unlike
straight-line Forth code that only uses the data stack (return stack
and control flow also restrict this kind of factoring, but I don't see
that argument applied to these featres). With locals across several
words ypu could do such factoring with code that uses locals.

> I suppose it's somewhat analogous to nested procedure
>scopes in Algol, but the inner procedures can't be called from
>outside.

I don't think it can be called in Algol (60) or Pascal, and the way
the extension is described, it could be done in Forth with this
extension, but would produce unpredictable results.

It would probably be better to have a syntax where the inner words
would not be visible outside. E.g., something like

: foo {: First Second -- :}
l: bar ( -- ) first second + . ;
bar ;

where L: is a word for defining a colon definition inside a colon
definition. There would probably be restructions on the definition
and use of locals, and on whether you can tick or postpone BAR to make
the implementation simpler. Even a simple implementation would be
good enough for the factoring justiication. If you lift restrictions,
you are into full closures relatively soon.

>It strikes me as more like dynamic scoping in Lisp, which is
>rather horrible, and I much prefer Scheme's lexical scoping.

I don't see any particular relation to dynamic scoping. My guess is
that in the usage patterns that the OP has in mind, there woiuld be no
difference between static and dynamic scoping.

Anton Ertl

unread,
Feb 18, 2013, 9:39:00 AM2/18/13
to
"Elizabeth D. Rather" <era...@forth.com> writes:
>Truly, I don't see the point of all this paranoia about reentrancy,
>particularly in systems without a multitasker. VARIABLE was *designed*
>for things that would be used in multiple definitions. I remember the
>horror of (*gasp*) global variables back in the 1960's in Fortran. But,
>frankly, in 30+ years of programming in Forth I never found them a
>problem. I think this is all about mythical dragons.

I have had problems with variables, and even without multitasking.

However, I think that the OP wanted to make maximum use of the little
RAM he had by reusing it when the not-quite-locals are dead and don't
need any RAM. The stack-based regime of locals does this quite well,
he just does not want to be restricted to use them only within single
colon definitions.

>Of course, most of the time I don't like local variables anyway, let
>along "neighborhood" variables.

Strike!

Bernd Paysan

unread,
Feb 18, 2013, 11:29:46 AM2/18/13
to
Andrew Haley wrote:
> Well, I know what you mean, kinda sorta, but the world has changed.
> Processors with more than one core are common now, even in many
> embedded designs. To program such computers effectively really
> requires multi-tasking and re-eentrant coding. That standard Forth
> still doesn't address this is a shortcoming.

Standard Forth has no multitasking wordset. There is some common practise,
and for task-specific variables, we use USER <name>.

I tend to use current-object OOP for this purpose. The current object is in
a user variable or register (depends on what is available), and points to a
structure; polymorphic methods aren't needed for that; the access is similar
to normal variables (could also be locals with auto-fetch and to).

We should accept that any scope bigger than a single word in Forth is
indeterminated, so it should be a (potentially) long-living object that
contains those information.

Brad Eckert

unread,
Feb 18, 2013, 12:04:31 PM2/18/13
to
On Monday, February 18, 2013 7:39:00 AM UTC-7, Anton Ertl wrote:
>
> However, I think that the OP wanted to make maximum use of the little
> RAM he had by reusing it when the not-quite-locals are dead and don't
> need any RAM. The stack-based regime of locals does this quite well,
> he just does not want to be restricted to use them only within single
> colon definitions.
>
The idea of code reuse was brought up, so I think the not-quite-locals should be treated as variables, accessed by @ and ! instead of TO. You can use classic variables, or you can put a line of code at the top declaring them temporary variables.

Rick Hohensee, before he ran for President of the USA (he didn't win), promoted a third stack. Maybe this is something like that, but the stack grows in frames instead of cells.

Rather than provide a tool for new code, the syntax should be a tool for reducing RAM use in old code. So, let me propose three words for this: LOCAL+, LOCAL- and USE-LOCAL.

LOCAL+ puts a special version of VARIABLE at the top of the search order. This causes code to access variables in the frame stack instead of static addresses in data space.

LOCAL- gives you back your normal VARIABLE by restoring the old search order.

USE-LOCAL is used in the word that kicks off all this stuff. It sets up the frame and causes ; to take down the frame and forget the names of the variables.

If somebody hates the presence of these three words in your code, they can simply define them as NOOPs. They still provide visual cues as to the intended scope of variables.

Any suggestions for better names for these three?

Percy

unread,
Feb 19, 2013, 5:33:40 AM2/19/13
to
>>> I think the not-quite-locals should be treated as variables, accessed by @ and ! instead of TO. You can use classic variables, or you can put a line of code at the top declaring them temporary variables.

Can someone comment on why locals are VALUES rather than VARIABLES anyway? It seems an easy way to introduce coding mistakes to have two different, (incompatible and asymmetrical) ways of accessing variables in the same piece of code.

a @ TO b
b a !

Just curious generally with (global)varilables how appreciated are VALUES in any case over and above VARIABLES?

Anton Ertl

unread,
Feb 19, 2013, 6:25:32 AM2/19/13
to
Percy <percival...@gmail.com> writes:
>>>> I think the not-quite-locals should be treated as variables, accessed by @ and ! instead of TO. You can use classic variables, or you can put a line of code at the top declaring them temporary variables.
>
>Can someone comment on why locals are VALUES rather than VARIABLES anyway?

One reason is that a VALUE cannot be accessed outside the scope of the
name, while the address produced by a VARIABLE can live forever.
E.g., Gforth has variable-flavoured locals as well as value-flavoured
ones, so you can write:

: foo ( -- addr ) 3 { w^ x } x ; \ a variable-flavoured local X
: bar foo 5 { y } @ ; \ a value-flavoured local Y
bar .

This prints 5, although one would expect 3 (X is initialized to 3 and
never changed, and the @ accesses X.

Another reason is that we usually don't need to take the address of a
local. Even though Gforth has had variable-flavoured locals for 18
years, I have almost never used them.

> It seems an easy way to introduce coding mistakes to have two different, (incompatible and asymmetrical) ways of accessing variables in the same piece of code.
>
>a @ TO b
>b a !

There is certainly that, but that has rarely been a problem in
practice, and IIRC never with locals.

Brad Eckert

unread,
Feb 19, 2013, 12:20:23 PM2/19/13
to
On Saturday, February 16, 2013 11:40:38 AM UTC-7, Brad Eckert wrote:
> Hi All,
>
>
>
> I think locals should have scope over a group of words, not a single word. The last word in the scope can be assumed to set up the locals frame and then take it down at the end. Does anyone have a syntax to do this?
>

I whittled it down to SCOPE: and SCOPE;, providing some extra modularity in the process. The following code is a sample implementation followed by a usage example.

\ Localized scoping mechanism

\ With "local" variables implemented as variables in a temporary
\ frame on a frame stack. The benefits of this are:
\ 1. Information hiding
\ 2. Reduced RAM waste via reclamation of temporary storage
\ 3. Simpler reentrancy

0 [if]
SCOPE: ( <name> -- )
Begins a private wordlist.
SCOPE; ( -- )
Restores the search order and current wordlist.

When compiling, <name> compiles code to manage a stack frame for
local variables. Otherwise, <name> restores the scope to its
previous state and search order, to facilitate debugging.

[then]

\ frame stack run time

VARIABLE FPTR
1024 BUFFER: FRAMESTACK

: DO-REFRAME ( n -- ) FPTR +! ;
: FPTR[N] ( n -- a ) FPTR @ SWAP - ;
: /FPTR ( -- ) FRAMESTACK FPTR ! ; /FPTR

\ frame stack compile time

: RE-FRAME ( offset -- )
ALIGNED POSTPONE LITERAL POSTPONE DO-REFRAME
;

VARIABLE THIS-SCOPE \ -> current scope
VARIABLE SCOPED \ flag: frame needs to be handled

\ Allocate space in the frame for data. Note that VARIABLEs are not
\ automatically initialized to zero, as classic VARIABLEs often are.

: _LOCALBUF ( <name> n -- ) \ create item and allocate space
THIS-SCOPE @ DUP 0= ABORT" Scope does not exist"
@ SWAP
THIS-SCOPE @ +!
CREATE , DOES> @
STATE @ IF
POSTPONE LITERAL POSTPONE FPTR[N]
ELSE FPTR[N]
THEN
;
: _UNFRAME ( -- ) \ remove the locals frame
SCOPED @ IF
THIS-SCOPE @ ?DUP IF \ is there a frame?
@ NEGATE RE-FRAME \ compile code to take it down.
THEN THEN
;
: UN_SCOPE ( -- ) \ after ; some cleanup...
SCOPED @ IF PREVIOUS PREVIOUS 0 SCOPED ! THEN
;
WORDLIST CONSTANT SCOPELEX \ special lexicon for scoping
SCOPELEX +ORDER DEFINITIONS
: VARIABLE ( <name> -- ) 1 CELLS _LOCALBUF ;
: BUFFER: ( <name> n -- ) _LOCALBUF ;
: EXIT ( cs -- ) _UNFRAME POSTPONE EXIT ; IMMEDIATE
: ; ( cs -- ) _UNFRAME POSTPONE ; UN_SCOPE ; IMMEDIATE
PREVIOUS DEFINITIONS

: SCOPE: ( <name> -- ) \ create a new scope
WORDLIST SCOPELEX +ORDER DUP +ORDER
CREATE IMMEDIATE
HERE THIS-SCOPE ! 0 , , \ offset wid
DOES>
DUP THIS-SCOPE ! SCOPELEX +ORDER
DUP CELL+ @ +ORDER
STATE @ IF
@ RE-FRAME TRUE SCOPED !
ELSE DROP THEN
;
: SCOPE; ( -- )
PREVIOUS PREVIOUS DEFINITIONS
0 THIS-SCOPE !
;

\ test drive
\ -------------------------------------------------------------------

SCOPE: ROOTS

VARIABLE A
VARIABLE B
VARIABLE C

: DETERMINANT ( -- n ) \ b^2 - 4ac
B @ DUP * A @ C @ * 4 * - ;

: ROOT ( n1 -- n2 ) 2/ ; \ okay, we fake the square root

SCOPE;

: ROOT1 ( a b c -- n )
ROOTS C ! B ! A !
B @ NEGATE DETERMINANT ROOT + A @ 2/ ;

ROOTS \ let's add another variable for this version
VARIABLE D
SCOPE;

: ROOT2 ( a b c -- n )
ROOTS C ! B ! A ! 8 D !
B @ NEGATE DETERMINANT ROOT - A @ 2/ D @ + ;

\ As a bonus, WORDS only lists what's in ROOTS

Andrew Haley

unread,
Feb 19, 2013, 12:42:29 PM2/19/13
to
Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
> Percy <percival...@gmail.com> writes:

>>>>> I think the not-quite-locals should be treated as variables,
>>>>> accessed by @ and ! instead of TO. You can use classic
>>>>> variables, or you can put a line of code at the top declaring
>>>>> them temporary variables.
>>
>>Can someone comment on why locals are VALUES rather than VARIABLES anyway?

They may be registers.

> One reason is that a VALUE cannot be accessed outside the scope of the
> name, while the address produced by a VARIABLE can live forever.
> E.g., Gforth has variable-flavoured locals as well as value-flavoured
> ones, so you can write:
>
> : foo ( -- addr ) 3 { w^ x } x ; \ a variable-flavoured local X
> : bar foo 5 { y } @ ; \ a value-flavoured local Y
> bar .
>
> This prints 5, although one would expect 3 (X is initialized to 3 and
> never changed, and the @ accesses X.
>
> Another reason is that we usually don't need to take the address of a
> local. Even though Gforth has had variable-flavoured locals for 18
> years, I have almost never used them.

Indeed.

Andrew.

Brad Eckert

unread,
Feb 22, 2013, 11:27:59 AM2/22/13
to
On Saturday, February 16, 2013 11:40:38 AM UTC-7, Brad Eckert wrote:
VARIABLE FPTR
1024 BUFFER: FRAMESTACK
: +FRAME ( n -- ) CELLS FPTR +! ;
: /FRAME ( -- ) FRAMESTACK FPTR ! ; /FRAME
: NLOC: ( n -- ) CREATE , ( -- a ) DOES> @ FPTR @ SWAP - ;
: NS: ( n -- ) 0 ?DO I NEGATE CELLS NLOC: LOOP ;
10 NS: N1 N2 N3 N4 N5 N6 N7 N8 N9 N10

: BAR N3 @ . ;
: FOO 3 +FRAME ... BAR ... -3 +FRAME ;

This is a lot more Forth-like. It's a better place to put temporary state (that's not appropriate for the stack) than static variables. Also, an optimizer can compile smaller code: a small offset rather than a large data address.
0 new messages