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

namespace /was: Simple named structures

1 view
Skip to first unread message

Michael L.Gassanenko

unread,
Sep 2, 2002, 3:24:05 AM9/2/02
to
Namespaces must be separate from structures themselves!

Probably, someone will find a way to simplify this.
I personally dislike the use of ['] NOOP .


PUSH-CURRENT and POP-CURRENT should be a separate issue.
They almost eliminate the need to use the ?ET-CURRENT words.

(Should I call them LET-CURRENT and RET-CURRENT to keep
the tradition of having long names that differ by a single
character like GET-CURRENT and SET-CURRENT ? :-> )

Another issue is the word :{ that is non-immediate while
.( is immediate.

I like the idea of unwinding the search order via repeated
PLEASE" }" (yes, there should be PLEASE" ..." instead
of S" ..." EVALUATE ), but I do not really like the
auxiliary word list _ns_grows .

The word ns_closingbrace: has a colon in its name to allow
"find-in-files" find the "ns_closingbrace: }" string when it is
asked to find ": }".

And just look at the phrase
POSTPONE .{ 1 S" ' } >BODY ! }" EVALUATE
, don't you just love the use of special characters?
They are so numerous and so meaningful! :-)))))

----

\ Namespaces by M.L.Gassanenko
\ after "Simple named structures" by David N. Williams

\ This is an ANS Forth program potentially requiring a lot of
\ resources such as dictionaries and search order stack space

\ -------------------------------------------------------------------
\ : >ORDER ( wid -- ) >R GET-ORDER R> SWAP 1+ SET-ORDER ;

\ -------------------------------------------------------------------
\ the compilation word list stack (CWLS)

8 CELLS CONSTANT /CWLS
CREATE _CWLSP0 /CWLS ALLOT

0 VALUE CWLSP@
: CWLSP! TO CWLSP@ ;
: ?CWLSP ( addr -- addr )
DUP _CWLSP0 DUP /CWLS + WITHIN 0=
ABORT" compilation word list stack (CWLS) pointer out of range"
;
: !!CWLS ( -- ) \ reset-cwls
_CWLSP0 /CWLS + CWLSP!
;
!!CWLS

( You may wish to perform !!CWLS after ABORT , or even add )
( !!CWLS FORTH-WORDLIST SET-CURRENT to the action of ABORT )
( if you find it reasonable and possible)

\ -------------------------------------------------------------------

: PUSH-CURRENT ( wid -- )
GET-CURRENT CWLSP@ CELL- ?CWLSP CWLSP! CWLSP@ ! SET-CURRENT
;
: POP-CURRENT ( -- )
CWLSP@ @ CWLSP@ CELL+ CWLSP! SET-CURRENT
;

\ -------------------------------------------------------------------
\ auxiliaries

\ an auxiliary word list
WORDLIST CONSTANT _ns_grows
_ns_grows PUSH-CURRENT
: } POP-CURRENT PREVIOUS S" }" EVALUATE ;
POP-CURRENT

\ namespace id value
$57ACE ( from 'space' ) CONSTANT _nsid
: ?ns _nsid XOR ABORT" no namespace specified" ;

\ -------------------------------------------------------------------
\ braces

\ defines closing brace
: ns_closingbrace: ( "name" -- ) ( Child: -- )
CREATE IMMEDIATE 0 ,
DOES> @ PREVIOUS IF S" }" EVALUATE THEN
;
\ opens access to name space entries
: .{ ( x1 x2 -- )
?ns 2@ DUP ['] NOOP <> IF EXECUTE RECURSE ELSE DROP THEN >ORDER
; IMMEDIATE

\ new definitions will go to the namespace specified by ( x1 x2 )
: :{ ( x1 x2 -- )
2DUP POSTPONE .{
DROP CELL+ @ PUSH-CURRENT _ns_grows >ORDER
;

\ -------------------------------------------------------------------
\ name space declaration words

: _do-namespace DOES> _nsid ;

: NAMESPACE ( "name" -- x1 x2 ) ( Child: -- x1 x2 )
WORDLIST
CREATE IMMEDIATE _do-namespace
HERE _nsid ROT ['] NOOP , ,
2DUP :{ S" ns_closingbrace: } }" EVALUATE
;
: EXTENDS ( x1 x2 "namespace-name" -- x1 x2 )
2DUP ?ns
DUP @ ['] NOOP XOR ABORT" already extends some name space"
' SWAP !
2DUP POSTPONE .{ 1 S" ' } >BODY ! }" EVALUATE
;

\ -------------------------------------------------------------------
\ Examples

\ The field declaration word after Guido Draheim's idea
: SFIELD CREATE DUP , DOES> @ + ;

NAMESPACE Point
:{
0
SFIELD x CELL+
SFIELD y CELL+
} CONSTANT /Point

Point :{
: print ( addr -- ) DUP ." x=" x @ . ." y=" y @ . ;
}

NAMESPACE ColoredPoint EXTENDS Point
:{
/Point
SFIELD color CELL+

: print DUP print ." color=" color @ . ;

} CONSTANT /ColoredPoint

CREATE p /ColoredPoint ALLOT
: foo ColoredPoint .{ 1 p x ! 2 p y ! 3 p color ! } ;
: bar ColoredPoint .{ p print } ;
: bar0 Point .{ p print } ;

NAMESPACE DeclaredButEmpty :{ }


(( a sample session

bar0
x=0 y=0 ok[Dec]

bar
x=0 y=0 color=0 ok[Dec]

foo
ok[Dec]

bar0
x=1 y=2 ok[Dec]

bar
x=1 y=2 color=3 ok[Dec]

ColoredPoint :{ ORDER }
68844264 _ns_grows 68844712 ColoredPoint 68844560 Point
68826028 FORTH ( FORTH ) 68826028 FORTH ( FORTH ) ;
68844712 ColoredPoint ok[Dec]

))

Michael L.Gassanenko

unread,
Sep 2, 2002, 6:10:25 AM9/2/02
to
"Michael L.Gassanenko" wrote:
>
> Probably, someone will find a way to simplify this.


I miss two (or one of two) features to make name spaces simpler:

1. Pre-ANS Forths often supported word list inheritance.

WL1: [pointer-to-1st-nfa] [1] [space] .... ( more "threads" )
\______________________________/
pseudo-header

^
|
|

[pointer-to-pseudo-header] [len] [name] ....
^
|
.....
|
[pointer-to-next-header] [len] [name] ....
^
|
|
WL2: [pointer-to-1st-nfa] [1] [space] .... ( more "threads" )
\______________________________/
pseudo-header

In this example, after examining all WL2 words, we switch to WL1 words.


2. I want .{ to check that there's a valid wid (word list id).

If I could check that a value is a valid wid, I could
do something like

( parent-wid) >R
PLEASE" : __establish"
R> LITERAL
PLEASE" >ORDER __establish ( from the parent word list );"

and let .{ ( wid -- ) execute __establish from the word list wid.
I see at least two variations of this approach (each word list
has __establish and not each one has __establish), but this is details.

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

The main idea is:
a word list is already a container, so we do not need a record with wid
in it.

Instead of ( addr ) 2@ ... IF EXECUTE >ORDER ELSE ... THEN >ORDER
we could have
S" __establish" ROT SEARCH-WORDLIST 0= ABORT" huh?" EXECUTE
\ : __establish __establish-from-parent its-wid >ORDER
or
DUP S" __establish" ROT SEARCH-WORDLIST IF EXECUTE THEN >ORDER
\ : __establish __establish-from-parent-if-any parent-wid >ORDER ;

But I need a way to know that there's a valid wid.

Jenny Brien

unread,
Sep 2, 2002, 4:17:41 PM9/2/02
to
On Mon, 02 Sep 2002 11:24:05 +0400, "Michael L.Gassanenko"
<m_l...@yahoo.com> wrote:

>Namespaces must be separate from structures themselves!
>

Agreed!

>Probably, someone will find a way to simplify this.

I'll try, but my wordset is a little different :-)

CONTEXT: NAME{
declares the present search order an immediate named namespace

NAMESPACE: NAME{
as context:, but adds a new wordlist first

name{ adds itself to the search order

} removes it

Examples:

ONLY FORTH-WORDLIST DEBUG-WORDLIST 2 SET-ORDER CONTEXT: TEST{

test{ namespace: NEW{ }

new{ FLOAD source.f

\ Add definitions to NEW{ wordspace
\ Search new definitions, debug-wordlist, forth-wordlist
} \ Restore search order

\ Within source.f

: foo ... ;
: bar ... test{ foo } ... ;
\ compiles foo from test{ namespace

\ Namespaces by M.L.Gassanenko revised by J.T. Brien


\ after "Simple named structures" by David N. Williams
>
>\ This is an ANS Forth program potentially requiring a lot of
>\ resources such as dictionaries and search order stack space

\ This is an ANS Forth program requiring the SEARCH-ORDER
\ Extension Wordset

\ The Search Order must be balanced between name{ and }

>\ -------------------------------------------------------------------
\ : >ORDER ( wid -- ) >R GET-ORDER R> SWAP 1+ SET-ORDER ;
>
>\ -------------------------------------------------------------------
>\ the compilation word list stack (CWLS)

\ also the count-of-word-lists-stack
>
8 2* CELLS CONSTANT /CWLS


CREATE _CWLSP0 /CWLS ALLOT
>
0 VALUE CWLSP@
: CWLSP! TO CWLSP@ ;
: ?CWLSP ( addr -- addr )
DUP _CWLSP0 DUP /CWLS + WITHIN 0=

ABORT" context stack (CWLS) pointer out of range"


;
: !!CWLS ( -- ) \ reset-cwls
_CWLSP0 /CWLS + CWLSP!
;
!!CWLS

: PUSH-CWLS ( n wid -- ) CWLSP@ 2 CELLS -
?CWLSP CWLSP! CWLSP@ 2! ;
: POP-CWLS ( -- n wid ) CWLSP@ 2@ CWLSP@ 2 CELLS + CWLSP! ;
: ONLY !!CWLS ONLY ;


: +CONTEXT ( wid1 ... widn1 wid2 .... widn2 n2 n1 --)
\ present search order is wid1...widn1 n1
\ add wid2 ...widn2 n2 to it
OVER GET-CURRENT PUSH-CWLS
+ SET-ORDER DEFINITIONS ;

: } \ remove that many wordlists
POP-CWLS SET-CURRENT 0 DO PREVIOUS LOOP ;


\ -------------------------------------------------------------------
\ auxiliaries

: N! \ x1 ... xn n addr -- ; store counted array of n cells at addr
OVER 1+ 0 DO TUCK ! CELL+ LOOP DROP ;

: N@ \ addr -- x1 ... xn n ; fetch counted array of cells
DUP @ 1+ TUCK CELLS + SWAP 0 DO
DUP @ SWAP 1 CELLS - LOOP DROP ;

\ name space declaration words

WORDLIST CONSTANT NAMESPACES

: CREATION \ wid ++ ; CREATE a word on this wordlist
GET-CURRENT SWAP SET-CURRENT CREATE SET-CURRENT ;


: CONTEXT: NAMESPACES CREATION
>R GET-ORDER DUP 1+ CELLS ALLOT R> N!
DOES> >R GET-ORDER R> SWAP >R N@ R> +CONTEXT ;

: NAMESPACE: WORDLIST >ORDER CONTEXT: ;


NAMESPACES FORTH-WORDLIST 2 SET-ORDER CONTEXT: +NAMESPACES{


>\ -------------------------------------------------------------------
>\ Examples
>

+NAMESPACES{

>\ The field declaration word after Guido Draheim's idea
>: SFIELD CREATE DUP , DOES> @ + ;
>
>NAMESPACE Point

\ You may like to group all namespace declarations together

NAMESPACE: POINT{
Point{ Namespace: COLOREDPOINT{
\ etc.
}


>:{
> 0
> SFIELD x CELL+
> SFIELD y CELL+
>} CONSTANT /Point

>
>Point :{
> : print ( addr -- ) DUP ." x=" x @ . ." y=" y @ . ;
>}
>

Point{
0
SFIELD x CELL+
SFIELD y CELL+

: print ( addr -- ) DUP ." x=" x @ . ." y=" y @ . ;

} CONSTANT /Point

>NAMESPACE ColoredPoint EXTENDS Point
>:{
> /Point
> SFIELD color CELL+
>
> : print DUP print ." color=" color @ . ;
>
>} CONSTANT /ColoredPoint
>

Coloredpoint{
/Point
SFIELD color CELL+

: print DUP print ." color=" color @ . ;

} CONSTANT /ColoredPoint

>CREATE p /ColoredPoint ALLOT
>: foo ColoredPoint .{ 1 p x ! 2 p y ! 3 p color ! } ;
>: bar ColoredPoint .{ p print } ;
>: bar0 Point .{ p print } ;

CREATE p /ColoredPoint ALLOT
: foo ColoredPoint{ 1 p x ! 2 p y ! 3 p color ! } ;
: bar ColoredPoint{ p print } ;
: bar0 Point{ p print } ;

>(( a sample session
>
>bar0
>x=0 y=0 ok[Dec]
>
>bar
>x=0 y=0 color=0 ok[Dec]
>
>foo
> ok[Dec]
>
> bar0
>x=1 y=2 ok[Dec]
>
> bar
>x=1 y=2 color=3 ok[Dec]
>
>ColoredPoint :{ ORDER }
>68844264 _ns_grows 68844712 ColoredPoint 68844560 Point
>68826028 FORTH ( FORTH ) 68826028 FORTH ( FORTH ) ;
>68844712 ColoredPoint ok[Dec]

ColoredPoint{ ORDER }

ColoredPoint Point Forth Namespaces
ColoredPoint

Jenny Brien
http://www.fig-uk.org
Home of the Fig UK website

Michael L.Gassanenko

unread,
Sep 3, 2002, 10:30:23 AM9/3/02
to
Jenny Brien wrote:
[...]

> \ name space declaration words
>
> WORDLIST CONSTANT NAMESPACES
>
> : CREATION \ wid ++ ; CREATE a word on this wordlist
> GET-CURRENT SWAP SET-CURRENT CREATE SET-CURRENT ;
>
> : CONTEXT: NAMESPACES CREATION
> >R GET-ORDER DUP 1+ CELLS ALLOT R> N!
^^^^^^^^^

This way the saved search order will include FORTH-WORDLIST
as well as the structure name spaces.

Michael L.Gassanenko

unread,
Sep 3, 2002, 3:26:00 PM9/3/02
to

Now, I implemented that.

=====================================================================
=== design notes ====================================================

PUSH-CURRENT and POP-CURRENT should be there in the standard.
They are not there, but they are easy to define, at least, if
we assume that only one task can compile.
PUSH-CURRENT and POP-CURRENT replace the ugly pattern
GET-CURRENT ( >R ) wl SET-CURENT
...
( R> ) SET-CURRENT


>ORDER ORDER> ORDER@ are also an extension of the standard Forth.
Such an extension that your system most likely already has it ot
its functional analog, and system-dependent definitions of these
words will run significantly faster than equivalent standard code.

I have defined only two auxiliary constants: the one that may be
placed onto the search order stack, and the one that is placed
only onto the data stack to indicate that the value below it
is a valid wordlist-id. In fact, I could use the same value for
both purposes, but I do not think it would be good.

Namespaces are immediate words ( -- x1 x2 ). In fact, they are
immediate 2CONSTANTs, x1 is a wid, and x2 is always _nsid, that
is, $57ACE. ( 57ACE is what you get from 'space' when you try
to replace letters by more or less similar hex digits.)

I have to move } to the main Forth dictionary.

I dislike attaching { to names of name spaces.
The reason is that the braces will not always be balanced.
That is, too often will be unbalanced.

What names are better: NAMESPACE and +NAMESPACE or BASIC and DERIVED ?

***

BASIC Point


:{
0
SFIELD x CELL+
SFIELD y CELL+
} CONSTANT /Point
Point :{
: print ( addr -- ) DUP ." x=" x @ . ." y=" y @ . ;
}

Point DERIVED ColoredPoint
:{
/Point
SFIELD color CELL+

: print DUP print ." color=" color @ . ;

} CONSTANT /ColoredPoint

***vs.****

NAMESPACE Point
:{
0
SFIELD x CELL+
SFIELD y CELL+
} CONSTANT /Point

Point :{
: print ( addr -- ) DUP ." x=" x @ . ." y=" y @ . ;
}

Point +NAMESPACE ColoredPoint
:{
/Point
SFIELD color CELL+

: print DUP print ." color=" color @ . ;

} CONSTANT /ColoredPoint

***

Probably, BASIC and DERIVED are better than NAMESPACE / +NAMESPACE .

Each derived name space has a method PARENT. I works as the name
of the parent class (aka superclass).

For example, ColoredPoint .{ PARENT } is the same as Point .

I intentionally had } match both .{ and :{ . The reason is that
it is too easy to confuse them, and such mistake would be very
difficult to mention.


=====================================================================
=== source code =====================================================
\ File: ns.fth == ns.2b.fth

\ Namespaces by Michael L. Gassanenko


\ after "Simple named structures" by David N. Williams

\ version 3

\ This is an ANS Forth program requiring the SEARCH-ORDER
\ Word Set and potentially requiring a lot of
\ resources such as word lists (one per name space)
\ and search order stack space (ancestor name space word lists
\ are also placed onto the search order stack)

\ -------------------------------------------------------------------
\ : >ORDER ( wid -- ) >R GET-ORDER R> SWAP 1+ SET-ORDER ;

\ : ORDER> ( -- wid ) GET-ORDER SWAP >R 1- SET-ORDER R> ;
\ : ORDER@ ( -- wid ) ORDER> DUP >ORDER ;

\ -------------------------------------------------------------------
\ the compilation word list stack (CWLS)

$10 CELLS CONSTANT /CWLS
CREATE _CWLSP0 /CWLS ALLOT

0 VALUE CWLSP@
: CWLSP! TO CWLSP@ ;
: ?CWLSP ( addr -- addr )
DUP _CWLSP0 DUP /CWLS + WITHIN 0=
ABORT" compilation word list stack (CWLS) pointer out of range"
;
: !!CWLS ( -- ) \ reset-cwls
_CWLSP0 /CWLS + CWLSP!
;
!!CWLS

( You may wish to perform !!CWLS after ABORT , or even add )
( !!CWLS FORTH-WORDLIST SET-CURRENT to the action of ABORT )
( if you find it reasonable and possible)

\ -------------------------------------------------------------------

: PUSH-CURRENT ( wid -- )
GET-CURRENT CWLSP@ CELL- ?CWLSP CWLSP! CWLSP@ ! SET-CURRENT
;
: POP-CURRENT ( -- )
CWLSP@ @ CWLSP@ CELL+ CWLSP! SET-CURRENT
;

\ -------------------------------------------------------------------
\ auxiliaries

\ an auxiliary word list, empty
WORDLIST CONSTANT _ns_grows

\ namespace id value
$57ACE ( from 'space' ) CONSTANT _nsid
: ?ns _nsid XOR ABORT" no namespace specified" ;

\ -------------------------------------------------------------------
\ braces

\ opens access to name space entries


: .{ ( x1 x2 -- )

?ns DUP S" PARENT" ROT SEARCH-WORDLIST IF EXECUTE RECURSE THEN >ORDER
; IMMEDIATE

\ new definitions will go to the namespace specified by ( x1 x2 )
: :{ ( x1 x2 -- )

2DUP POSTPONE .{ DROP PUSH-CURRENT _ns_grows >ORDER
;
\ removes name space word lists from the search order stack
: }
ORDER@ _ns_grows = IF PREVIOUS POP-CURRENT THEN
BEGIN
S" PARENT" ORDER> SEARCH-WORDLIST
WHILE
DROP
REPEAT
; IMMEDIATE

\ defines a name space
: BASIC ( "name" -- x1 x2 )
WORDLIST _nsid 2DUP 2CONSTANT IMMEDIATE
;
\ defines a name space as an extension of the specified name space
: DERIVED ( x1 x2 "name" -- x3 x4 )
DUP ?ns
BASIC OVER PUSH-CURRENT
2SWAP S" 2CONSTANT PARENT IMMEDIATE" EVALUATE
POP-CURRENT
;


\ -------------------------------------------------------------------
\ Examples

\ The field declaration word after Guido Draheim's idea
: SFIELD CREATE DUP , DOES> @ + ;

BASIC Point


:{
0
SFIELD x CELL+
SFIELD y CELL+
} CONSTANT /Point

Point :{
: print ( addr -- ) DUP ." x=" x @ . ." y=" y @ . ;
}

Point DERIVED ColoredPoint
:{
/Point
SFIELD color CELL+

: print DUP print ." color=" color @ . ;

} CONSTANT /ColoredPoint

CREATE p /ColoredPoint ALLOT
: foo ColoredPoint .{ 1 p x ! 2 p y ! 3 p color ! } ;
: bar ColoredPoint .{ p print } ;
: bar0 Point .{ p print } ;

: bar1 ColoredPoint .{ PARENT } .{ p print } ; \ same as bar0

\ just declaration
BASIC DeclaredButEmpty :{ }

\ a different style

BASIC mystruc1 :{
0
SFIELD q CELL+
SFIELD w CELL+
CONSTANT /size
}
mystruc1 DERIVED mystruc2 :{
/size
SFIELD r CELL+
SFIELD t CELL+
CONSTANT /size
}

(( a sample session

bar0
x=0 y=0 ok[Dec]

bar1
x=0 y=0 ok[Dec]

bar
x=0 y=0 color=0 ok[Dec]

foo
ok[Dec]

bar0
x=1 y=2 ok[Dec]

bar1
x=1 y=2 ok[Dec]

bar
x=1 y=2 color=3 ok[Dec]

ColoredPoint :{ ORDER }
68844264 _ns_grows 68844628 ColoredPoint 68844496 Point 68826028 FORTH ( FORT
H ) 68826028 FORTH ( FORTH ) ; 68844628 ColoredPoint ok[Dec]

ColoredPoint .{ ORDER }
68844628 ColoredPoint 68844496 Point 68826028 FORTH ( FORTH ) 68826028 FORTH
( FORTH ) ; 68826028 FORTH ( FORTH ) ok[Dec]

Point .{ WORDS }
print y x ok[Dec]

ColoredPoint .{ WORDS }
print color PARENT ok[Dec]

ColoredPoint .{ PARENT } .{ WORDS }
print y x ok[Dec]

ORDER
68826028 FORTH ( FORTH ) 68826028 FORTH ( FORTH ) ; 68826028 FORTH ( FORTH )
ok[Dec]

mystruc2 .{ /size . } mystruc1 .{ /size . }
16 8 ok[Dec]

))

=====================================================================


regards, mlg
--

Jenny Brien

unread,
Sep 4, 2002, 3:09:22 AM9/4/02
to
On Mon, 02 Sep 2002 20:17:41 GMT, jen...@figuk.plus.com (Jenny Brien)
wrote:

>On Mon, 02 Sep 2002 11:24:05 +0400, "Michael L.Gassanenko"
><m_l...@yahoo.com> wrote:
>
>>Namespaces must be separate from structures themselves!
>>
>Agreed!
>
>>Probably, someone will find a way to simplify this.
>
>I'll try, but my wordset is a little different :-)
>

Perhaps a few more words of explaination are in order

> CONTEXT: NAME{
> declares the present search order an immediate named namespace
>
> NAMESPACE: NAME{
>as context:, but adds a new wordlist first

CONTEXT: is a way of building a namespace out of existing
vocabularies. It might be best to create base contexts of one member,
thus:

ONLY FORTH CONTEXT: FORTH{ etc.

From now on there is a single and consistent way of handling
wordlists. For each wordlist in the search order, ORDER should display
the name of the context: or namespace: which has that wordlist as its
first member. If there is more than one, display the one with the
fewest members

The equivalent of:

VOCABULARY VOCN
VOC1 ALSO VOC2 ALSO ... VOCN

is voc1{ voc2{ .... namespace: vocn{ ONLY
vocn{

Note that ONLY has the effect of closing all open namespaces.
Also, namespace declarations can (should?) be grouped together.
Namespaces which share a context: also share any words which may be
added to that context: later.

>new{ FLOAD source.f
>
> \ Add definitions to NEW{ wordspace
> \ Search new definitions, debug-wordlist, forth-wordlist
>} \ Restore search order
>

This sort of syntax makes it easier to declare namespaces outside
source files. By changing the declaration, the same file might produce
different output without conditional compilation. I haven't
investigated the implications of this yet.

>\ Within source.f
>
> : foo ... ;
> : bar ... test{ foo } ... ;
> \ compiles foo from test{ namespace
>

Test{ may be any known namespace. Since they are all defined on the
one wordlist, it should be possible for a source file to check for
their presence.
>
>
The Problem of DEFINITIONS

What should namespaces do about the compilation wordlist?

1. Nothing. Ignore it entirely.

2. The compilation wordlist is always the top wordlist in the top
namespace.

3. Don't set it implicitly, but always restore it on exit.

Any option will work for name{...} within a definition, though 2 could
cause surprises in a few odd circumstances.

2 works nicely for a few phrases like name{ words }

1 and 3 require the use of DEFINITIONS when adding definitions to a
namespace. I would see that as a plus.

name{ DEFINITIONS

does exactly what you might think. Restoring the previous compilation
wordlist on exit might seem a good idea, but it gives trouble when you
really, truly *do* want it to be something else. With option 1 you
can do:

name{ DEFINITIONS }

with option 2 name{ GET-CURRENT } SET-CURRENT
but with 3 name{ DEFINITIONS GET-CURRENT } SET-CURRENT

DEFINITIONS is a self-commenting word, and should always be used
explicitly. name{ DEFINITIONS } is also better than ...SET-CURRENT
DEFINITIONS for returning to definitions in a known namespace.

I'm now tending towards option 1. It also simplifies the code even
more:

>>\ the compilation word list stack (CWLS)
> \ also the count-of-word-lists-stack
>>

is now only the count-of-wordlists stack

> : +CONTEXT ( wid1 ... widn1 wid2 .... widn2 n2 n1 --)
> \ present search order is wid1...widn1 n1
> \ add wid2 ...widn2 n2 to it
> OVER GET-CURRENT PUSH-CWLS
> + SET-ORDER DEFINITIONS ;
>

: +CONTEXT OVER PUSH-CWLS + SET-ORDER ;

> : } \ remove that many wordlists
> POP-CWLS SET-CURRENT 0 DO PREVIOUS LOOP ;

: } CWLS@ @ IF
POP-CWLS 0 DO PREVIOUS LOOP THEN ;
>

> : CONTEXT: NAMESPACES CREATION

should of course be: : CONTEXT: NAMESPACES CREATION IMMEDIATE
could include whatever implementation-dependent stuff you need to
write ORDER

>NAMESPACES FORTH-WORDLIST 2 SET-ORDER CONTEXT: +NAMESPACES{
>

NAMESPACES 1 SET-ORDER CONTEXT: NAMESPACES{

: ONLY ONLY !!CWLS NAMESPACES{
0 CWLS@ ! ; \ make namespaces permanent

: ;struct ( u -- ) aligned s" constant sizeof" evaluate ;

>Point{
> 0
> SFIELD x CELL+
> SFIELD y CELL+
>
> : print ( addr -- ) DUP ." x=" x @ . ." y=" y @ . ;
> } CONSTANT /Point
>


Point{ DEFINITIONS


0
SFIELD x CELL+
SFIELD y CELL+

: print ( addr -- ) DUP ." x=" x @ . ." y=" y @ . ;

;struct }

ColoredPoint{ DEFINITIONS
sizeof
1 cells field: COLOR
etc.

Doesn't that look better ;-)

Jenny Brien

unread,
Sep 4, 2002, 7:25:13 AM9/4/02
to
On Tue, 03 Sep 2002 23:26:00 +0400, "Michael L.Gassanenko"
<m_l...@yahoo.com> wrote:

>
>Now, I implemented that.
>
>=====================================================================
>=== design notes ====================================================
>
>PUSH-CURRENT and POP-CURRENT should be there in the standard.
>They are not there, but they are easy to define, at least, if
>we assume that only one task can compile.
>PUSH-CURRENT and POP-CURRENT replace the ugly pattern
>GET-CURRENT ( >R ) wl SET-CURENT
>...
>( R> ) SET-CURRENT
>

I'm not so sure. You only need a dedicated stack of you have more than
one to restore, and by that time you code is begining to get complex
- can you remember what DEFINITIONS you are returning to? But if
you've got them, by all means use them.


>
>I dislike attaching { to names of name spaces.
>The reason is that the braces will not always be balanced.
>That is, too often will be unbalanced.
>

They need only be unmatched when they are defined. The problem is
that x{ ... } has two possible states - it either pushes the
compilation wordlist or it doesn't. If that distinction doesn't have
to be made then it's simpler to let namespaces push themselves onto
the search order. If namespaces only affect the search order then ONLY
is a good way of clearing up dangling }s.

I can't think of an example where

namespace{ do_something_with_it } is not sensible

Well, namespace{ DEFINITIONS } might overload the search order if it's
a large namespace. In practice, though, you would probably do:

ONLY namespace{ DEFINITIONS }
namespace_to_search{ ...


>What names are better: NAMESPACE and +NAMESPACE or BASIC and DERIVED ?
>

For what you're doing, BASIC and DERIVED

I would define the same thing:

ONLY namespace: POINT{
point{ namespace: COLOREDPOINT{
}

Which is more verbose, but also allows a namespace to be built from
any existing namespaces in any order, without having to name
intermediate "generations"

Jenny Brien

unread,
Sep 4, 2002, 7:28:40 AM9/4/02
to
On Tue, 03 Sep 2002 18:30:23 +0400, "Michael L.Gassanenko"
<m_l...@yahoo.com> wrote:

>Jenny Brien wrote:
>[...]
>> \ name space declaration words
>>
>> WORDLIST CONSTANT NAMESPACES
>>
>> : CREATION \ wid ++ ; CREATE a word on this wordlist
>> GET-CURRENT SWAP SET-CURRENT CREATE SET-CURRENT ;
>>
>> : CONTEXT: NAMESPACES CREATION
>> >R GET-ORDER DUP 1+ CELLS ALLOT R> N!
> ^^^^^^^^^
>
>This way the saved search order will include FORTH-WORDLIST
>as well as the structure name spaces.
>

That's intentional. Namespaces are meant to be a general replacement
for vocabularies, not just for structures.

It would be general practice to start a namespace declaration with
ONLY so that you don't inadvertently include something.

ONLY NAMESPACE: PARENT{

parent{ namespace: CHILD1{
namespace: CHILD2{
}

child1{ \ search order child1{ parent{
namespace: GRANDCHILD1{
}

CONTEXT: will likely not be much used, except for converting existing
vocabularies into namespaces.

It seems good practice to use ONLY often and then define the namespace
explicitly. In particular, I think you might expect INCLUDEs to set
their own search order. I long ago defined LOAD to do ONLY ALSO FORTH
DEFINITIONS and found it saved me a lot of grief.

If namespaces have no effect on the compilation wordlist then:

name{ DEFINITIONS }

adds new definitions to that namespace but removes it from the search
order.

Possible source file layout:

\ Implementation: ( *Private.fs )
INCLUDE xxx
ONLY ( required namespaces) namespace: *private{
*private{ DEFINITIONS
... etc.
}

\ Interface: ( *Public.fs)
INCLUDE *Private.fs
ONLY namespace: *PUBLIC{

*PUBLIC{ DEFINITIONS }

*private{
... etc.

Michael L.Gassanenko

unread,
Sep 4, 2002, 12:21:47 PM9/4/02
to
Jenny Brien wrote:
> It would be general practice to start a namespace declaration with
> ONLY so that you don't inadvertently include something.
>
> ONLY NAMESPACE: PARENT{

What word list NAMESPACE: must be defined in?

: 16.6.2.1965 ONLY SEARCH EXT
: ( -- )
: Set the search order to the implementation-defined minimum search order.
: The minimum search order shall include the words FORTH-WORDLIST and
: SET-ORDER.


And you will have to end your definitions before getting FORTH-WORDLIST into
the search order.

That is, the namespace hierarchy declaration *has to* be
separate from namespace member declarations.

Michael L.Gassanenko

unread,
Sep 4, 2002, 1:22:52 PM9/4/02
to
Jenny Brien wrote:
> The Problem of DEFINITIONS
>
> What should namespaces do about the compilation wordlist?
>
> 1. Nothing. Ignore it entirely.
>
> 2. The compilation wordlist is always the top wordlist in the top
> namespace.
>
> 3. Don't set it implicitly, but always restore it on exit.

There's something in 3.

That is, one can do POP-CURRENT in each } and thus get rid of :{ :
: :{ [COMPILE] .{ DEFINITIONS ;

BASIC Point
.{ DEFINITIONS


0
SFIELD x CELL+
SFIELD y CELL+

} CONSTANT /Point

Point DERIVED ColoredPoint
.{ DEFINITIONS
/Point
SFIELD color CELL+
} CONSTANT /ColoredPoint

------

As to Point .{ vs. Point{ , I prefer the first because I can do things like

ColoredPoint .{ PARENT } .{ print }

BASIC Circle
:{
0
SFIELD center /Point +
SFIELD radius CELL+
: *Center S" center Point" EVALUATE ; IMMEDIATE
} CONSTANT /Circle

CREATE z /Circle ALLOT
: *Z S" z Circle" EVALUATE ; IMMEDIATE
: foo *Z .{ center } .{ DUP x . y . } ;

\ The C analog of foo is
\ void foo(){ printf("%i %i",z.center.x,z.center.y); }

| my system is case-sensitive, but yours is probably not,
\ therefore *Z instead of Z and *Center instead of Center

---------

The above is an explicit analog of the PRELUDE/FINALE concept
by Manfred Mahlow.

Each word is associated with an immediate word that the interpreter
performs when the word in encountered. (To be more precise, two words:
PRELUDE before and FINALE after. To me, only one is really needed, but
maybe I miss some details. Probably, only one is needed, but it
must be sometimes PRELUDE and sometimes FINALE.)

Classes push word lists onto the search order stack, methods pop
them from there. The scope is limited to one word (IIRC).

You can find it in the EF'98 papers by Klaus Schleisiek and Manfred Mahlow.

I wrote "explicit analog" because the Mahlow's approach does the thing
implicitly.

---------

Now I am thinking about typed words like
: Z S" z Circle" EVALUATE ; IMMEDIATE

NB:

z is equivalent to Z .{ }

: TYPED ( offset x1 x2 -- offset )
CREATE IMMEDIATE , , DUP ,
DOES> DUP >R
2 CELLS + @ STATE @ IF POSTPONE LITERAL POSTPONE + ELSE + THEN
R> 2@
;

BASIC Circle :{
0
Point TYPED Center /Point +
SFIELD radius CELL+
} CONSTANT /Circle

\ No CREATE-TYPED so far
CREATE z /Circle ALLOT
: Z S" z Circle" EVALUATE ; IMMEDIATE

Z .{ Circle } .{ x } -- z.cicle.x
Z .{ Circle } .{ } -- z.cicle
Z .{ } -- z


Maybe, PRELUDE/FINALE *is* adequate. Even for my syntax.

Jenny Brien

unread,
Sep 4, 2002, 4:40:11 PM9/4/02
to

NAMESPACE: and CONTEXT: have to be namespaces DEFINITIONS

NAMESPACES is the wordlist where all namespaces are defined, just as
all vocabularies in F83 are defined in the ROOT vocabulary.

NAMESPACES sits at the bottom of the search order (ONLY is redefined
to place it there). It doesn't form part of the search order copied by
CONTEXT: so there is always only one NAMESPACES in the search order.

I'm sorry that the code I'm posting doesn't reflect this. I'm working
it out as I go along, partly in response to your helpful questions.

Maybe I should take time off to reflect and then post a finished and
tested version if anyone is still interested.

Michael L.Gassanenko

unread,
Sep 6, 2002, 3:12:41 AM9/6/02
to
Jenny Brien wrote:
>
> I can't think of an example where
>
> namespace{ do_something_with_it } is not sensible
>

ColoredPoint .{ PARENT } .{ print }

where PARENT is a synonym of ColoredPoint's parent class, Point.

BASIC Square :{
0
SFIELD UpperLeft /Point +
SFIELD LowerRight /Point +

: UPPER-LEFT PLEASE" UpperLeft Point" ; IMMEDIATE
: LOWER-RIGHT PLEASE" LowerRight Point" ; IMMEDIATE
} CONSTANT /Square

((
As to locals,
{ a } declares and initializes a
{ a | b } declares a and b, initializes a
{ | b } declares b
{ n | [ n CELLS ] arr } declares and initializes n; allocates n CELLS
on the return stack, declares arr and initializes it with
the address of allocated memory block.

))

: foo
{ | [ /Square ] s } \ LOCAL: s /Square RALLOC TO s
s Square .{ LOWER-RIGHT } .{ x } .....
;

BTW, it may be meaningful to introduce typing, so that typed S
would work as PLEASE" s Square".
This way, it would be

: foo
{ | [ /Square ] s : Square } \ LOCAL: _s /Square RALLOC TO _s
\ : s PLEASE" _s Square" ;
s .{ LOWER-RIGHT } .{ DUP x @ . y @ . }
s .{ } /Square ERASE
;

David N. Williams

unread,
Sep 24, 2002, 5:11:25 PM9/24/02
to
I've pretty much digested Michael's and Jenny's very interesting
ideas on independent namespaces suitable for extension.

Here's an attempt at a fusion--at least it uses a lot of ideas
from both.

I'm totally convinced by Michael's nomenclature for the order stack:
>ORDER, ORDER>, and ORDER@.

Like Jenny (if I understood her correctly) I have no objection
his compilation word list stack, but haven't understood the need
for it here.

Michael's lament about word list inheritance and pointers struck
a chord; linking is part of the extension scheme here.

I do use trailing "{"'s in namespace names, but with a syntax
that's always balanced.

I like Jenny's use of explicit DEFINITION's for adding to
namespaces, but do it implicitly when defining namespaces.
Otherwise the scheme is her alternative 3, which Michael seemed
to prefer.

The Problem of DEFINITIONS

What should namespaces do about the compilation wordlist?

[...]

3. Don't set it implicitly, but always restore it on exit.

-- David

-----------------------------------------------------------------
( Title: Namespaces
File: namespace.fs
Version: 0.2.0
Adaptor: David N. Williams
License: TBA
Last revision: September 24, 2002

This code is heavily based on that of Michael Gassanenko and
Jenny Brien in the c.l.f. threads "namespace /was: Simple named
structures" and "Simple named structures", as well as that of
DNW in the latter thread.

The implementation has a system-dependence on the nonoccurrence
of zero as a node address.
)


\ *** GENERAL USE

[UNDEFINED] >order [IF]
: >order ( wid -- ) >r get-order r> swap 1+ set-order ;
[THEN]

[UNDEFINED] 2cells+ [IF]
: 2cells+ ( n -- n+2cells ) 2 cells + ;
[THEN]

: (order: postpone ( ; immediate

: field: ( offset size -- offset+size )
create over , +
DOES> ( struc -- struc+offset ) @ + ;


\ *** NAMESPACE NODE STRUCTURE
(
All namespaces have a single-linked node structure instance,
called "self", with unnamed fields:

parent namespace node address
namespace wid
compilation wid saved on entry

The defining factor NAMESPACE: initializes the fields.

A namespace can have only one direct parent, but may be the
direct parent of any number of children. An ancestral chain
from child [self] to parent to grandparent, etc., is a "family".
The search order for a family is understood to start with the
child. In order stack comments, "family" means "family wid's".
)


\ *** NAMESPACE FACTORS

: push-family ( child -- ) (order: -- family )
0 ( terminator) >r
( child)
BEGIN ( node) dup >r @ ( parent) dup 0= UNTIL ( 0) drop
BEGIN r> ( node) dup
WHILE cell+ @ ( wid) >order
REPEAT ( 0 ) drop ;

: drop-family ( child -- ) ( order: family -- )
BEGIN
previous ( node) @ ( parent) dup 0=
UNTIL ( 0) drop ;

: close-namespace ( -- ) (order: family -- ) \ restores comp.wid
s" self" evaluate
( self) dup 2cells+ @ set-current
( self) drop-family ;

: namespace: ( "name" comp.wid self.wid parent|0 -- self )
(
Initialize the "self" namespace node and leave its address.
Define a word that saves the current compilation wid for
restoration when the namespace is closed, and pushes all parent
wid's and self.wid onto the search order so that the self word
list will be searched first, then the parent, etc.
)
create here ( self) >r
( parent) , ( self.wid) , ( comp.wid) , r> ( self)
DOES> ( -- ) (order: -- family ) \ saves comp.wid
( self) get-current over 2cells+ !
( self) push-family ;


\ *** VOC NAMESPACES
(
We say "voc" because "vocabulary" is too loaded. These name
spaces are about the simplest class. They have only two
built-in methods, a value SELF which returns the self node, and
and the immediate close method, called "}".
)

: (voc:) ( "name" parent -- ) (order: -- self.wid ) \ saves comp-wid
\ does ( -- ) (order: -- family ) \ saves comp.wid
get-current ( parent comp.wid) swap
wordlist ( self.wid) dup >r swap
( comp.wid self.wid parent) namespace: ( self) immediate
r> ( self.wid) >order definitions
( self) s" value self" evaluate
s" : } close-namespace ; immediate" evaluate ;

: voc: ( "name" -- ) (order: -- self.wid ) \ saves comp-wid
\ does ( -- ) (order: -- self.wid ) \saves comp-wid
0 (voc:) ;

: voc-ext: ( "name" -- ) \ saves comp-wid
(order: parent.family -- parent.family self.wid )
\ does: ( -- ) (order: -- family ) \ saves comp-wid
s" self" evaluate (voc:) ;

: };voc ( -- ) (order: self.wid -- ) \ restores comp-wid
s" self" evaluate
( self) 2cells+ @ set-current previous ;


\ *** SAMPLE SYNTAX

voc: point1{
0
1 cells field: x
1 cells field: y
constant /point
};voc

point1{ voc-ext: coloredpoint1{
/point
1 cells field: color
constant /coloredpoint
};voc }


\ *** STRUCTURE NAMESPACES

: struct: ( "name" -- 0 ) (order: -- self.wid ) \ saves comp.wid
\ does ( -- ) (order: -- self.wid ) \ saves comp.wid
voc: 0 ;

: };struct ( size -- ) (order: self.wid -- ) \ restores comp.wid
s" constant /struct" evaluate };voc ;

: struct-ext: ( "name" -- /base.struct ) \ saves comp.wid
(order: parent.family -- parent.family self.wid )
\ does ( -- ) (order: -- family ) \ saves comp.wid
voc-ext: s" /struct" evaluate ;


\ *** SAMPLE SYNTAX

struct: point2{
1 cells field: x
1 cells field: y
};struct

point2{ struct-ext: coloredpoint2{
1 cells field: color
};struct }

0 new messages