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

ColorForth - another dead end?

847 views
Skip to first unread message

bor...@gmail.com

unread,
May 24, 2015, 3:22:28 PM5/24/15
to
Hello everybody,

I am Greg. This is my first post here.

I was searching the web about ColorForth and I saw a lot of activity around it some good years ago and then lately almost nothing. Lots of people who put effort into it seem to have completely abandoned it lately.

So my question is why? Did people investigate it and then found out it doesn't give you as much for the buck as initially thought?

My Forth expertise is at the Starting Forth level (reading it a second time). I was thinking to try to figure out ColorForth after that. Even on this list, I see people showing interest in it couple of years back, but almost nothing about it in later years.

I have read that Chuck admitted "sourceless" programming was a dead end and he completely abandoned it. Is ColorForth another dead-end too?

hughag...@gmail.com

unread,
May 24, 2015, 5:00:37 PM5/24/15
to
I don't know what Charles Moore may have been referring to in regard to "sourceless programming" --- that sounds like what they do in Visual Basic.

I don't really know enough about ColorForth to comment on it --- all of what Charles Moore does is pretty far out and funky, and not very practical --- I don't really pay much attention to it.

If you want to learn ANS-Forth, you can start with my novice package:
http://www.forth.org/novice.html

None of the books from Forth Inc., including "Starting Forth," describe how to implement structs. I didn't even know what structs were until I learned C, and then I brought the idea over to Forth (see FIELD in the novice-package). For any kind of actual programming in Forth, you are going to need the novice-package or something very similar --- reading Forth Inc. books will never take you beyond writing baby programs.

bor...@gmail.com

unread,
May 24, 2015, 7:18:30 PM5/24/15
to
His sourceless from what I could understand was of very different kind than VB :) Oversimplified: Write/edit your programs directly in binary, even assembly was too much...

Thanks for the link. It answers my question after reading Starting Forth once. All cool but how about some data structures and more serious programming?

hughag...@gmail.com

unread,
May 24, 2015, 7:45:35 PM5/24/15
to
On Sunday, May 24, 2015 at 4:18:30 PM UTC-7, bor...@gmail.com wrote:
> His sourceless from what I could understand was of very different kind than VB :) Oversimplified: Write/edit your programs directly in binary, even assembly was too much...

That reminds me of those monitor programs for the 6502. I think this was the Apple-II that I'm remembering. It was an assembler in the sense that the programmer entered assembly-language instructions, but there was no source-code. The instructions got assembled directly into memory, and what the programmer was looking at was a disassembly of memory rather than a source-code file. Backwards branches were easy because you could see the code already written and know what the address of your destination was. Forward branches were trickier --- you had to put in a dummy value and then go back and fill it in when you knew your destination address. There was a command for moving a block of memory ahead, so you could insert code, but if you did this all of your branches got messed up.

Writing a program using a monitor was a painful process. People who did this would typically write their program with pencil-and-paper, then study the heck out of it mentally, then type it into the monitor program and expect it to run correctly. The monitor allowed single-stepping through programs, and it would display register values as you went, so it was possible to debug like this.

The monitor was mostly used for testing short snippets of code --- mostly for twiddling the bits on an I/O port to see what happens. It is actually much easier to use a Forth system for this kind of testing, but the monitor programs were a first step in the direction of interactive programming.

MS-DOS had a DEBUG program that was essentially a monitor --- I don't know if it is still available --- maybe if you point-and-click enough in that control-panel stuff, you eventually find yourself in DEBUG mode.

Elizabeth D. Rather

unread,
May 24, 2015, 8:50:56 PM5/24/15
to
Unfortunately, Starting Forth presents a very simplified view of the
state of Forth 30 years ago, which even more unrepresentative of Forth
today than K&R is of the current state of C programming (K&R was at
least aimed at professional programmers). If you are interested in Forth
I highly recommend some more recent and more technical books on the
language, of which there are several. My book, the Forth Programmer's
Handbook, is available from Amazon as well as a free pdf included with
the evaluation version of FORTH, Inc.'s SwiftForth (windows, Linux, OSX)
and SwiftX (interactive cross-compiler for popular microcontrollers) in
addition to extensive documentation of these respective implementations.
Both SwiftForth and SwiftX have been used in major software projects:
SwiftX, for example, runs communication multiplexors that manage much of
the electric power grid in North America.

Forth takes a unique approach to data structures. It provides some
simple ones, but more importantly provides a mechanism for defining
application-specific data structures. In other words, instead of having
to express your application data in some pre-defined kind of structure,
there's a very simple way of defining exactly what you need that behaves
exactly how you need it to. This mechanism, using the words CREATE and
DOES>, lets you in effect design a new class of words with a specified
compile-time behavior and run-time behavior. Examples have included
automatically index circular tables of coefficients (every time you
invoke a reference to a table you get the next element), data "objects"
that actually read a value from an I/O port and scale it appropriately,
multi-dimensional arrays, arrays and tables that range-check index
parameters, objects that "live" in a file or in flash, and many more. In
your search for matrices, you've found one example; believe me, that's
just the beginning!

As far as colorFORTH is concerned, it represents a direction that Chuck
Moore has been pursuing for some years now that is quite divergent from
mainstream Forth. Although it embodies some interesting ideas, it has
not really caught on among programmers using Forth professionally.

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

hughag...@gmail.com

unread,
May 24, 2015, 9:12:13 PM5/24/15
to
As I said, none of the Forth Inc. books describe how to implement a struct, which is the foundation of all data-structures. I have never seen any evidence to indicate that Elizabeth Rather knows what a struct is.

CREATE DOES> also has serious problems --- I don't use it in the novice-package.

Howerd

unread,
May 25, 2015, 12:51:55 AM5/25/15
to
Hi Greg,

Welcome to clf :-)

> Is ColorForth another dead-end too?
No, definitely not.

I happen to be working on my distro of colorForth this morning when I read your post (its a bank holiday here today) :-)
This is only a back-burner project for me, so in elapsed time its taking forever, hence the lack of updates...

GreenArrays supply their ArrayForth dialect of colorForth which runs either native or under Windows - you can download it from here : http://www.greenarraychips.com/home/support/download-02b.html

Chuck has used, and as far as I know is still using, colorForth/arrayForth to write OKAD which he uses to develop his Forth chips.
OKAD is a Domain Specific Language which is an alternative to the usual CAD development environments.

> Did people investigate it and then found out it doesn't give you as much for > the buck as initially thought?
Speaking for myself, no.
Back in 2001 it was easy to find a PC or laptop with a built in floppy drive. Today a programming language that only runs from a floppy disk is not taken seriously - computer science has more in common with the fashion industry these days than science (thanks to Stephen Pelc for pointing this out to me :-).

My back-burner colorForth project is to make my distro run from a USB drive.
This is extremely challenging, and not really that much fun, because it is battling a menagerie of complicated beasts : Windows, FAT32, MBRs, BPBs etc.
But I am doing it because I think colorForth is worth it...

Best regards, and thanks for your interest,
Howerd



Hannu Vuolasaho

unread,
May 25, 2015, 3:06:28 AM5/25/15
to
On 25.05.2015 03:50, Elizabeth D. Rather wrote:

>
> Unfortunately, Starting Forth presents a very simplified view of the
> state of Forth 30 years ago, which even more unrepresentative of Forth
> today than K&R is of the current state of C programming (K&R was at
> least aimed at professional programmers). If you are interested in Forth
> I highly recommend some more recent and more technical books on the
> language, of which there are several. My book, the Forth Programmer's
> Handbook, is available from Amazon as well as a free pdf included with
> the evaluation version of FORTH, Inc.'s SwiftForth (windows, Linux, OSX)
> and SwiftX (interactive cross-compiler for popular microcontrollers) in
> addition to extensive documentation of these respective implementations.
> Both SwiftForth and SwiftX have been used in major software projects:
> SwiftX, for example, runs communication multiplexors that manage much of
> the electric power grid in North America.
>

I liked Brodie's Starting and Thinking Forth books. A while ago I read
it through and compared its ideas to jonesforth. They work nicely
together. Thinking Forth gave some thoughts to consider while using
other languages as well. I also found your Forth programmers handbook
very useful.

However, even I don't find myself total newbie any more, I end up asking
quite a lot of questions which newbie would ask. And when I find answer,
it is always the simplest one which I didn't even consider.

I would like to propose that on some course you record all sessions and
write a book where you solve those questions your students asked. And if
course subject can be set some direction, have Arduino or some other
common MCU development environment and write something more complicated
than normal led blinker and control software on PC for it.

And for Hugh there should be structs, linked list and maybe some tree
build in a forth way.

But I have impression, you don't teach nor write that much any more.

Best regards,
Hannu Vuolasaho

Mark Wills

unread,
May 25, 2015, 4:50:08 AM5/25/15
to
ColorForth is really neat, however, the major barrier for most people
is the *extremely* un-user-friendly user interface. I tried it and got
nowhere with it. Gave up in frustration. For a long time it was Dvorak
input only, IIRC. Only later, as a concession to "normal" people was
the ability to use a normal keyboard added (I may have got that wrong).

There is a version which runs from Windows available from Green Arrays
but it still uses the awful user interface. The user interface should
be scrapped IMO and replaced with something more friendly. It doesn't
have to be graphics/windows based. DOS style character mode would be
just fine - as long as it displays colo(u)r.

Welcome to CLF.

Howerd

unread,
May 25, 2015, 5:11:05 AM5/25/15
to
Hi Mark,

> the major barrier for most people
> is the *extremely* un-user-friendly user interface.
I agree that the colorForth 24-key interface is an acquired taste - GreenArray's arrayForth defaults to a relatively normal ASCII mode -
but I would not call it un-user-friendly, just different.
In terms of the recent Eurovision song contest, its more Montenegro or Belgium than Sweden or Russia, if you get what I mean ;-)

Best regards,
Howerd




Albert van der Horst

unread,
May 25, 2015, 7:17:15 AM5/25/15
to
In article <935bf6d1-e59e-4a9b...@googlegroups.com>,
Howerd <how...@yahoo.co.uk> wrote:
<SNIP>
>
>Chuck has used, and as far as I know is still using,
>colorForth/arrayForth to write OKAD which he uses to develop his Forth
>chips.
>OKAD is a Domain Specific Language which is an alternative to the usual
>CAD development environments.

I understood that OKAD got lost when Chuck's laptop broke down that
was the only one to boot the OKAD floppies?

<SNIP>

>Best regards, and thanks for your interest,
>Howerd
>
>
>
--
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,
May 25, 2015, 10:20:55 AM5/25/15
to
bor...@gmail.com writes:
>I have read that Chuck admitted "sourceless" programming was a dead end and=
> he completely abandoned it. Is ColorForth another dead-end too?

I think that Chuck Moore sees it as a stage on the way to arrayForth
(and whatever comes after that). Sourceless was a dead end for him,
because he went back to using source code.

And it seems to be that those people who are particularly interested
in what Chuck Moore is doing are now looking into the Greenarrays
chips and arrayForth, that's why there is less buzz about colorForth.

I don't think many of the interested people have used colorForth for
production purposes, and the same will probably happen with
arrayForth.

- 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 2015: http://www.mpeforth.com/euroforth2015/euroforth2015.htm

Jason Damisch

unread,
May 25, 2015, 2:11:15 PM5/25/15
to
On Sunday, May 24, 2015 at 5:50:56 PM UTC-7, Elizabeth D. Rather wrote:

> arrays and tables that range-check index parameters

Or, for that matter arrays and tables that DON'T
range-check index parameters, for those of you
who need that extra bit of speed, or for those
of you who like to live on the wild side. :^)

Jason

rickman

unread,
May 25, 2015, 2:22:44 PM5/25/15
to
I recently used a table without range checking even during debug because
I could guaranty that the index could not be out of range. Range
checking is not always required in an array.

--

Rick

Elizabeth D. Rather

unread,
May 25, 2015, 8:57:27 PM5/25/15
to
Absolutely. And in applications where you *do* want to do range
checking, you may not always want to do the same thing. In some cases,
you want to give an error message, in others you want to clip or
substitute for the errant value or take some completely different action.

The programmer should have full control.

bor...@gmail.com

unread,
May 25, 2015, 11:42:53 PM5/25/15
to
I like what I "hear" in here. I am looking forward to getting a better grasp of what Forth is.
I remember when I had to switch from C to Java, the frustration of being so constraint and with so little control over things. It felt like I lost my freedom and also lost power over the computer (but not having to worry about memory allocation was something that I began to appreciate after a while).

After decades of programming in strong typed, convoluted syntax languages, I feel like I am getting tired of so much syntax, can't take it any longer. There must be something simpler/nicer than having to keep track of parens, parameters, etc. Although I am not sure if Forth actually just replaces one thing with another - now the drudge is shifted to keeping track of the stack instead. We shall see...

Thank you all for the nice pointers and welcome.

onewh...@gmail.com

unread,
May 28, 2015, 4:00:30 PM5/28/15
to
Could you elaborate on this? How is the concept of a C struct not a subset of the functionality provided by CREATE DOES>? Or are you referring to the syntax of being able to refer to parts of a struct by name (this.that)?

What are the serious problems with CREATE DOES> that you mention? I am still quite a novice Forther, so perhaps coming from C to Forth is keeping me from seeing what you are talking about.

hughag...@gmail.com

unread,
May 28, 2015, 9:55:27 PM5/28/15
to
I'm referring to the feature of obtaining the field address from the struct address --- see FIELD in the novice package (http://www.forth.org/novice.html).

> What are the serious problems with CREATE DOES> that you mention? I am still quite a novice Forther, so perhaps coming from C to Forth is keeping me from seeing what you are talking about.

There are three major problems with CREATE DOES> in Forth:

1.) There is only one action associated with the word. This can be worked around with >BODY but the result is some pretty awkward source-code.

2.) Data is being fetched out of memory at run-time by the DOES> code which is inefficient in the majority of the cases in which this data is known at compile-time and is immutable; it would be much more efficient that this data could be compiled as literal.

3.) The language and the compiler are over-complicated because CREATE is overloaded to be used for two unrelated purposes. In my own cross-compiler, I defined CREATE like this:
: create here constant ;
I also had <BUILDS that defined a word that had to be fixed up by DOES> (if <BUILDS didn't have a corresponding DOES> then that was an error).

This is discussed here:
https://groups.google.com/forum/#!searchin/comp.lang.forth/hugh$20use$20create$20does/comp.lang.forth/TTvONOrHvI4/X63CXcZYaPgJ

In here, regarding the #2 objection above, Stephen Pelc describes how CREATE DOES> in VFX is able to compile code with the immutable data as literals rather than fetch it from memory at run-time. He wouldn't provide the source-code for his example however! Finally he did provide it, and it wasn't ANS-Forth --- VFX has a work-around for the bug in ANS-Forth design (some directives that the programmer inserts into his code to indicate that data is immutable), but this is highly non-standard --- by comparison, my :NAME workaround for the same problem is ANS-Forth compliant, so I have more loyalty to ANS-Forth than Stephen Pelc does, but I also have more honesty in describing its problems.

Howerd

unread,
May 29, 2015, 3:49:36 AM5/29/15
to
[snip]
>
> Could you elaborate on this? How is the concept of a C struct not a subset of the functionality provided by CREATE DOES>? Or are you referring to the syntax of being able to refer to parts of a struct by name (this.that)?
>
> What are the serious problems with CREATE DOES> that you mention? I am still quite a novice Forther, so perhaps coming from C to Forth is keeping me from seeing what you are talking about.

Hi,

Something like C structs can be implemented using CREATE ... DOES> , with a slightly different syntax.

I found some code in my Win32Forth folder, under ePost, ( so its probably from Jos van der Ven ) that does this - I've posted it here : www.inventio.co.uk/STRUCT.F

IIRC Stephen Pelc has powerful C-like struct support in VFX, and these are very useful when interfacing to Windows etc.

Hugh Aguilar's Novice package provides this functionality :

: field ( offset size -- new-offset ) \ stream: name
create
over , +
does> ( struct-adr base-adr -- field-adr )
@ + ;

I like this simple definition, which I think does the same thing :

: struct ( a c -- a' ) over CONSTANT + ;

I snipped Hugh's comment about "> CREATE DOES> also has serious problems" because it is not relevant to structs, and another line because it is rude.
I will let Hugh explain this.

Best regards,
Howerd

Raimond Dragomir

unread,
May 29, 2015, 10:56:05 AM5/29/15
to
> IIRC Stephen Pelc has powerful C-like struct support in VFX, and these are very useful when interfacing to Windows etc.

C structs are powerful, the fields are associated with the object. In forth
you cannot have this, fields are global. Forth structs are not so powerful.

Maybe I'm missing something here and VFX found a way to implement C structs?

>
> Hugh Aguilar's Novice package provides this functionality :
>
> : field ( offset size -- new-offset ) \ stream: name
> create
> over , +
> does> ( struct-adr base-adr -- field-adr )
> @ + ;
>
This is a classical example of inefficiency (like also the CONSTANT example implemented with create does>). The field word will do @ + at RUNTIME even if the offsets are well known at compile time, and this is a very common situation!.

There is a solution to this though. First, you need to delay literal compiling
in order to have a chance to do constant folding (or any other mechanism)
Second you need a smart + which should be immediate and perform a + if there
are at least two literals pending, or compile the + otherwise;
And third, you need to make the defined word immediate.
In this situation, when the field word is encountered, it is executed at compile time (it is immediate). It performs @ fetching the offset value - ok, the offset is always known at compile time. Then it performs the +. + sees at least one literal on the stack - the offset just fetched. If it sees at least one more literal (supposed to be based address) it adds them at compile time, leaving the computed address on the stack. Otherwise it compiles the + (this will trigger compiling first the offset as a literal).
Simple :)

Anton Ertl

unread,
May 29, 2015, 12:07:07 PM5/29/15
to
Raimond Dragomir <raimond....@gmail.com> writes:
[Someone:]
>> : field ( offset size -- new-offset ) \ stream: name =20
>> create =20
>> over , +
>> does> ( struct-adr base-adr -- field-adr )
>> @ + ;
>>=20
>This is a classical example of inefficiency (like also the CONSTANT example=
> implemented with create does>). The field word will do @ + at RUNTIME even=
> if the offsets are well known at compile time, and this is a very common s=
>ituation!.
>
>There is a solution to this though. First, you need to delay literal compil=
>ing
>in order to have a chance to do constant folding (or any other mechanism)
>Second you need a smart + which should be immediate and perform a + if ther=
>e
>are at least two literals pending, or compile the + otherwise;
>And third, you need to make the defined word immediate.
>In this situation, when the field word is encountered, it is executed at co=
>mpile time (it is immediate). It performs @ fetching the offset value - ok,=
> the offset is always known at compile time. Then it performs the +. + sees=
> at least one literal on the stack - the offset just fetched. If it sees at=
> least one more literal (supposed to be based address) it adds them at comp=
>ile time, leaving the computed address on the stack. Otherwise it compiles =
>the + (this will trigger compiling first the offset as a literal).
>Simple :)

Not simple, and pretty wrong. The fields defined by the word above are
not defined as immediate, and if you define them as immediate, they would
not do the required thing.

The problem with the definition above is that the body of the field
can be changed later with >BODY !, so the best a compiler can do is to
inline the DOES> part as

<addr> @ +

A simple, but somewhat unusual way to avoid this problem is to define
this as

: +FIELD ( n1 n2 "<spaces>name" -- n3 )
over >r +
: r> postpone literal postpone + postpone ;
;

(+FIELD is the Forth-2012 name of this word).

Let's compare the compiled code:

4 4 field f1 \ with the FIELD above
4 4 +field f2
create x 8 allot
: foo1 x f1 @ + ;
: foo2 x f2 @ + ;

with VFX Forth 4.71:
see foo1
FOO1
( 080C09E0 8B1560090C08 ) MOV EDX, [080C0960]
( 080C09E6 039AB0090C08 ) ADD EBX, [EDX+080C09B0]
( 080C09EC C3 ) NEXT,
( 13 bytes, 3 instructions )
ok
see foo2
FOO2
( 080C0A10 031DB4090C08 ) ADD EBX, [080C09B4]
( 080C0A16 C3 ) NEXT,
( 7 bytes, 2 instructions )

Raimond Dragomir

unread,
May 29, 2015, 1:03:17 PM5/29/15
to
I think you don't understand. The scheme that I described works in my system
like a charm. Here it is my sources (sorry it is a forth dialect):

\ optimized macro words with constant folding
[ state @ 0> ] def compiling?
\ EVAL-XT-CF ( n -- ) constant folding level
[ depth u>= compiling? and if compile, else execute then ] def eval-xt-cf
[ -1 eval-xt-cf ] def eval-xt \ no constant folding
[ 2 eval-xt-cf ] def eval-xt-cf1 \ constant folding 1 level
[ 3 eval-xt-cf ] def eval-xt-cf2 \ constant folding 2 levels
[ 4 eval-xt-cf ] def eval-xt-cf3 \ constant folding 3 levels

[ ' drop eval-xt-cf1 ] idef drop
[ ' nip eval-xt-cf2 ] idef nip
[ ' swap eval-xt-cf2 ] idef swap
[ ' rot eval-xt-cf3 ] idef rot
[ ' and eval-xt-cf2 ] idef and
[ ' or eval-xt-cf2 ] idef or
[ ' xor eval-xt-cf2 ] idef xor
[ ' - eval-xt-cf2 ] idef -
[ ' / eval-xt-cf2 ] idef /

\ do not compile 0 +
[ depth 2 < compiling? and if
depth 1 < if
' + compile,
else \ depth is 1
dup if \ and x is not 0
' + compile,
else drop then
then
else + then
] idef +

\ do not compile 1 *
[ depth 2 < compiling? and if
depth 1 < if
' * compile,
else \ depth is 1
dup 1 <> if \ and x is not 1
' * compile,
else drop then
then
else * then
] idef *

\ FIELD ( "name" offset size -- offset+size ) name: ( x -- x+offset )
[ [ @ compile + ] ibuild over , + ] def field

Some explanations:
[ ] compiles anonymous code (I name them quotes). Can be nested. Top level
quote leaves it's address on the stack at compile time, nested quotes leave
their address on the stack at runtime.

def makes a dictionary entry
idef makes an immediate dictionary entry
buid builds a building word :) something like create does
ibuild builds an immediate building word.
state is in fact the nesting level of quotes, otherwise is like standard forth state.
Another important thing which is internal and cannot be seen is that
all literals are delayed in compiling (they stay on the data stack until
either they are used by smart words like +, - etc, or are "flushed"
on the compiled code by a normal word).

Raimond Dragomir

unread,
May 29, 2015, 1:15:36 PM5/29/15
to
compile is used to compile immediate words if that is not clear.
In the field definition, + is immediate so it is compiled by compile

hughag...@gmail.com

unread,
May 29, 2015, 10:19:37 PM5/29/15
to
On Friday, May 29, 2015 at 7:56:05 AM UTC-7, Raimond Dragomir wrote:
> > IIRC Stephen Pelc has powerful C-like struct support in VFX, and these are very useful when interfacing to Windows etc.
>
> C structs are powerful, the fields are associated with the object. In forth
> you cannot have this, fields are global. Forth structs are not so powerful.
>
> Maybe I'm missing something here and VFX found a way to implement C structs?

I doubt it that VFX or any other Forth implements C structs --- it is pretty much impossible in Forth because there is no way to know what data-type a pointer --- it might be possible to declare a data-type for a parameter and have a statically typed language, but you might as well just use C rather than Forth as rpn-C is pretty much what you are going to end up with.

> > Hugh Aguilar's Novice package provides this functionality :
> >
> > : field ( offset size -- new-offset ) \ stream: name
> > create
> > over , +
> > does> ( struct-adr base-adr -- field-adr )
> > @ + ;
> >
> This is a classical example of inefficiency (like also the CONSTANT example implemented with create does>). The field word will do @ + at RUNTIME even if the offsets are well known at compile time, and this is a very common situation!.

Yes, that is exactly the inefficiency problem that I described --- I don't know why we are going over this same point again and again --- I feel like Sisyphus, eternally pushing that stone up the hill only to have it roll down again...

> There is a solution to this though. First, you need to delay literal compiling
> in order to have a chance to do constant folding (or any other mechanism)
> Second you need a smart + which should be immediate and perform a + if there
> are at least two literals pending, or compile the + otherwise;
> And third, you need to make the defined word immediate.
> In this situation, when the field word is encountered, it is executed at compile time (it is immediate). It performs @ fetching the offset value - ok, the offset is always known at compile time. Then it performs the +. + sees at least one literal on the stack - the offset just fetched. If it sees at least one more literal (supposed to be based address) it adds them at compile time, leaving the computed address on the stack. Otherwise it compiles the + (this will trigger compiling first the offset as a literal).
> Simple :)

Nope, not correct.

I have the answer in my novice package (since 2009).

hughag...@gmail.com

unread,
May 29, 2015, 10:28:46 PM5/29/15
to
On Friday, May 29, 2015 at 9:07:07 AM UTC-7, Anton Ertl wrote:
> Raimond Dragomir <raimond....@gmail.com> writes:
> >Simple :)
>
> Not simple, and pretty wrong. The fields defined by the word above are
> not defined as immediate, and if you define them as immediate, they would
> not do the required thing.
>
> The problem with the definition above is that the body of the field
> can be changed later with >BODY !, so the best a compiler can do is to
> inline the DOES> part as
>
> <addr> @ +
>
> A simple, but somewhat unusual way to avoid this problem is to define
> this as
>
> : +FIELD ( n1 n2 "<spaces>name" -- n3 )
> over >r +
> : r> postpone literal postpone + postpone ;
> ;
>
> (+FIELD is the Forth-2012 name of this word).

Nope, still not correct (you're not special-casing the first field, so you are compiling code to add zero).

I have the answer in my novice package (since 2009).

BTW: I think it is quite humorous that you awkwardly work around the bug in ANS-Forth in which the control-flow stack is the same as the data-stack (your use of >R and R> above) --- but you refuse to just fix the problem in Forth-200x --- you aren't going to fix the problem until Leon Wagner gives you permission.

hughag...@gmail.com

unread,
May 29, 2015, 10:46:38 PM5/29/15
to
On Monday, May 25, 2015 at 5:57:27 PM UTC-7, Elizabeth D. Rather wrote:
> On 5/25/15 8:22 AM, rickman wrote:
> > On 5/25/2015 2:11 PM, Jason Damisch wrote:
> >> On Sunday, May 24, 2015 at 5:50:56 PM UTC-7, Elizabeth D. Rather wrote:
> >>
> >>> arrays and tables that range-check index parameters
> >>
> >> Or, for that matter arrays and tables that DON'T
> >> range-check index parameters, for those of you
> >> who need that extra bit of speed, or for those
> >> of you who like to live on the wild side. :^)
> >
> > I recently used a table without range checking even during debug because
> > I could guaranty that the index could not be out of range. Range
> > checking is not always required in an array.

Just use my arrays in the novice-package --- range-checking can be turned on or off as needed.

Also, I don't believe that you could guarantee that the index would not be out of range when you were still debugging --- that is what "debugging" means, that there might be bugs. Lots of bold programmers feel confident that their program is going to work the first time, but few are so bold as to "guarantee" this, because past experience indicates that this is almost never true.

> Absolutely. And in applications where you *do* want to do range
> checking, you may not always want to do the same thing. In some cases,
> you want to give an error message, in others you want to clip or
> substitute for the errant value or take some completely different action.

This is just more of Elizabeth Rather's lifelong effort to convince every Forther that every program has to be written entirely from scratch and that general-purpose data-structures can never be used.

This is total baloney. It is always an error to give an out-of-range index to an array. In the rare cases in which you want to clip or substitute an index (I have never seen this 30 years), you would write a wrapper for your array, but you would still be required to provide a valid index to the array. This does not at all imply that every data-structure has to be written from scratch every time, and that general-purpose data-structures can never be used.

> The programmer should have full control.

This is meaningless drivel --- similar to a politician saying: "I say that the people should be free!" (implying that the other candidate wants them to be enslaved).

You are always spouting meaningless drivel --- typical salesperson...

Rod Pemberton

unread,
May 30, 2015, 12:03:04 AM5/30/15
to
On Fri, 29 May 2015 22:46:36 -0400, <hughag...@gmail.com> wrote:

> It is always an error to give an out-of-range index to an array.

Data? Yes.
Address? No.

There are some rare but valid uses for address pointers computed
from an array address and an out-of-range index, at least, for C.
Of course, accessing data there is always invalid.


Rod Pemberton
--
If fewer guns reduced murders, how does one explain
Moscow, Chicago, New York, and South Africa?

Rod Pemberton

unread,
May 30, 2015, 12:14:36 AM5/30/15
to
On Fri, 29 May 2015 10:56:04 -0400, Raimond Dragomir
<raimond....@gmail.com> wrote:

>> IIRC Stephen Pelc has powerful C-like struct support in VFX,
>> and these are very useful when interfacing to Windows etc.
>
> C structs are powerful,

...

> C structs are powerful, the fields are associated with the object.

You must specify the struct name and field in C to access the field.
That's true with both of the component selection operators in C:
'.' and '->'

So, what do you mean by "the fields are associated with the object?"

> In forth you cannot have this, fields are global.
> Forth structs are not so powerful.

In C, every data type, struct, union, maps onto an array of bytes.

So, in Forth, you're just accessing structs at the array level,
without the compiler computing offsets for you.

Raimond Dragomir

unread,
May 30, 2015, 1:22:28 AM5/30/15
to
> > C structs are powerful, the fields are associated with the object.
>
> You must specify the struct name and field in C to access the field.
> That's true with both of the component selection operators in C:
> '.' and '->'
>
> So, what do you mean by "the fields are associated with the object?"

No you don't specify the struct name, you specify the object name which happens to have the type of that struct.

struct mystruct1 { int x; int y; }
struct mystruct2 { int y; int x; }
struct mystruct1 obj1;
struct mystruct2 obj2;
obj1.x
obj2.x

Tell me how can you do that in Forth. The big problem is that first x has
offset 0 and second x has offset of sizeof(int). Still, C has no problem in
seeing this.

As Hugh says, in Forth it's just impossible. Probably you have to do this:

0 cell field mystruct1.x
cell field mystruct1.y
constant mystruct1
0 cell field mystruct2.y
cell field mystruct2.x
constant mystruct2
mystruct1 var obj1
mystruct2 var obj2

obj1 mystruct1.x @
obj2 mystruct2.x @

Not very fancy, more verbose and error prone.

This is a price that Forth has to pay for it's simplicity.

Raimond Dragomir

unread,
May 30, 2015, 1:30:20 AM5/30/15
to
See above post, it's entirely correct.
I admit, you have the answer for ANS forth.
My system is not ANS maybe not forth at all - but I may say it's 90% forth
though - enough for me :D

hughag...@gmail.com

unread,
May 30, 2015, 1:55:37 AM5/30/15
to
On Friday, May 29, 2015 at 7:56:05 AM UTC-7, Raimond Dragomir wrote:
> Second you need a smart + which should be immediate and perform a + if there
> are at least two literals pending, or compile the + otherwise;

This is the part I saw as being incorrect, and for the same reason that Anton Ertl was incorrect --- you are not considering the case in which one parameter is not a literal, but the other is the literal zero (no addition needed) --- you are only considering the case in which both parameters are literals and they can be folded together into a single literal (do the addition at compile-time).

Maybe I'm misinterpreting your description though --- I didn't actually look at your code, but I only looked at this description.

Raimond Dragomir

unread,
May 30, 2015, 3:54:44 AM5/30/15
to
I admit that I missed something here in the description, although I
explained the internal literal folding mechanism to some degree:

The literals are not compiled directly, they are "delayed". This simply
means that a literal is just left on the data stack when is encountered
in the source. This leaves the possibility for immediate "smart" words
to do something, constant folding for example. This works with another
mechanism: a normal compilation of any word will "flush" all values on the
data stack first, in fifo order. Probably this was not so clear.

So, in our example: a "smart" + will just execute the + at compile time if
there are at least two data stack items. Otherwise, the + will be compiled.
This compilation of the + will trigger flushing the existing literals
on the data stack (in this case at most one). This is internal, and cannot
be seen in the sources.

A "smarter" + can compile a "literal +" optimized sequence if there is only
one literal pending. Or it can not compile a 0 + at all, see my source for
this case.

Speacking of it, I have the special case of 0 + and 1 *. 0 + is so common
for struct field, 1 * is for byte sized arrays.

Here is my version of your 1array, 2array and 3array:

\ arrays syntax:
\ dim1 size 1array "name"
\ dim2 dim1 size 2array "name"
\ dim3 dim2 dim1 size 3array "name"
qlib-temp-wordlist set-current
qlib-temp-wordlist forth-wordlist qlib-wordlist 3 set-order

0 cell field ary->base
cell field ary->size
cell field ary->dim1
cell field ary->dim2
drop

[ ary->base @ ] def <ary-base> ( a -- base )
[ ary->size @ ] def <ary-size> ( a -- size )
[ ary->dim1 @ ] def <ary-dim1> ( a -- dim1 )
[ ary->dim2 @ ] def <ary-dim2> ( a -- dim2 )

qlib-wordlist set-current

\ 1ARRAY ( "name" dim size -- )
[ [| pfa | \ runtime: ix1 [pfa]
pfa <ary-size> compile * \ ix1*size
pfa <ary-base> compile + \ base + size*ix1
] ibuild \ dim1 size
ramhere , \ base address
dup , \ size
* allot
] def 1array

\ 2ARRAY ( "name" dim2 dim1 size -- )
[| size |
[| pfa | \ runtime: ix2 ix1 [pfa]
pfa <ary-size> compile * \ ix2 ix1*size
pfa <ary-base> compile + \ ix2 ix1*size+base
compile swap \ ix1*size ix2
pfa <ary-size>
pfa <ary-dim1> compile * compile *
compile + \ base + size*ix1 + dim1*size*ix2
] ibuild \ dim2 dim1 [size]
ramhere , \ base address
size , \ size
dup , size * \ dim1
* allot
] def 2array

\ 3ARRAY ( "name" dim3 dim2 dim1 size -- )
[| size |
[| pfa | \ runtime: ix3 ix2 ix1 [pfa]
pfa <ary-size> compile * \ ix3 ix2 ix1*size
pfa <ary-base> compile + \ ix3 ix2 ix1*size+base
compile swap \ ix3 ix1*size+base ix2
pfa <ary-size>
pfa <ary-dim1> compile * compile *
compile + \ ix3 ix1*size+ix2*size*dim1
compile swap \ ix1*size+ix2*size*dim1 ix3
pfa <ary-size>
pfa <ary-dim1>
pfa <ary-dim2> compile * compile * compile *
compile + \ base + size*ix1 + dim1*size*ix2 + ix3*size*dim1*dim2
] ibuild \ dim3 dim2 dim1 [size]
ramhere , \ base address
size , \ size
dup , size * to size \ dim1
dup , size * \ dim2
* allot
] def 3array

\ we don't need qlib-temp wordlist anymore
forth-wordlist qlib-wordlist 2 set-order


Some notes:
[| ... | is for locals. So, in the 3array definition for example,
size is local to the 3array quote, and pfa is a local to the building
quote. These are stacked initialized locals, in correct order.
I also have [| ... 0 ... | notation where the "0" is not zero but a
delimiter for zero initialized locals.
As a comparation:
{ x y z | a b c -- ... }
[| x y z 0 a b c | \ emmebeded -- comments not supported


And a test of an array of structs:

variable x \ this is used to "simulate" a non-constant array index

0 cell field .x
cell field .y
cell field .z
cell field .color
constant pixel

\ 3ARRAY test
4 4 4 pixel 3array screen

[ 1 0 0 x @ screen .x !
2 0 0 x @ screen .y !
3 0 0 x @ screen .z !
4 0 0 x @ screen .color !
] def 000!

[ 5 3 3 3 screen .x !
6 3 3 3 screen .y !
7 3 3 3 screen .z !
8 3 3 3 screen .color !
] def 333!

[ 0 0 0 screen .x @ .
0 0 0 screen .y @ .
0 0 0 screen .z @ .
0 0 0 screen .color @ .
] def 000@

[ 3 3 3 screen .x @ .
3 3 3 screen .y @ .
3 3 3 screen .z @ .
3 3 3 screen .color @ .
] def 333@

000! 333! 000@ 333@ cr


Alex McDonald

unread,
May 30, 2015, 4:27:45 AM5/30/15
to
on 30/05/2015 06:22:27, Raimond Dragomir wrote:
> Tell me how can you do that in Forth. The big problem is that first x
> has offset 0 and second x has offset of sizeof(int). Still, C has no
> problem in seeing this.
>
> As Hugh says, in Forth it's just impossible.

In Forth it's always possible. Consider using a wordlist as an object
container; then X in one can be distinct from the X in another. This is
how the NEON/MOPS object systems, an example of which is in Win32Forth,
provides scope for its private variables.

Raimond Dragomir

unread,
May 30, 2015, 5:05:52 AM5/30/15
to
I don't known what NEON/MOPS is. Give me some examples in some commonly
used forths, Win32forth, gforth, VFX. Structures to use by a forth programmer
in a forth application.
As I said, maybe I'm behind regarding the latest technologies in forth.

All I have seen for gforth and win32forth were classical examples with
global field scopes and naming convention by appending the struct name
to the fields. This works fine for me but the whole point was how to
make the fields associated with the object.

Alex McDonald

unread,
May 30, 2015, 5:21:24 AM5/30/15
to

Raimond Dragomir

unread,
May 30, 2015, 7:08:47 AM5/30/15
to
You cannot convince me like this.
Let me give you another example:

struct mystruct
field x
field y
endstruct

mystruct obj1
variable x

: foo obj1 x @ x @ + ;

Do you think the above foo is working?
Suppose mystruct created an wordlist for the fields, and the fields are
put in this wordlist.
obj1 may put the mystruct wordlist on top of the search order.
Who is taking it back from the search order?
The second x has this problem. Who is x? the variable or the x field?


This in C should be something like return obj1.x + x;

How can you do that in Forth?
Not to say that if you must pass object pointers on the data stack, you loose
any type information that a clever implementation may carry.

I say that in Forth it's impossible because this behaviour is strong
related to a typing system. And Forth is an untyped language.




Anton Ertl

unread,
May 30, 2015, 8:36:48 AM5/30/15
to
hughag...@gmail.com writes:
>On Friday, May 29, 2015 at 9:07:07 AM UTC-7, Anton Ertl wrote:
>> A simple, but somewhat unusual way to avoid this problem is to define
>> this as
>>=20
>> : +FIELD ( n1 n2 "<spaces>name" -- n3 )
>> over >r +=20
>> : r> postpone literal postpone + postpone ;
>> ;
>>=20
>> (+FIELD is the Forth-2012 name of this word).
>
>Nope, still not correct (you're not special-casing the first field, so you =
>are compiling code to add zero).

On VFX Forth 4.71:
0 1 cells +field f3
see f3
F3
( 080BF340 C3 ) NEXT,
( 1 bytes, 1 instructions )

But of course, if you don't want to rely on the sophistication of the
Forth system, you can special-case the n1=0 case.

hughag...@gmail.com

unread,
May 30, 2015, 10:43:47 AM5/30/15
to
I don't recommend polymorphism in Forth --- if this is what you want, then just program in C++ or some such language (Forth isn't for every program or for every programmer).

In my novice package I have inheritance --- this is the only aspect of OOP that I consider worthwhile for Forth.

> Let me give you another example:
>
> struct mystruct
> field x
> field y
> endstruct
>
> mystruct obj1
> variable x
>
> : foo obj1 x @ x @ + ;
>
> Do you think the above foo is working?
> Suppose mystruct created an wordlist for the fields, and the fields are
> put in this wordlist.
> obj1 may put the mystruct wordlist on top of the search order.
> Who is taking it back from the search order?
> The second x has this problem. Who is x? the variable or the x field?
>
>
> This in C should be something like return obj1.x + x;
>
> How can you do that in Forth?
> Not to say that if you must pass object pointers on the data stack, you loose
> any type information that a clever implementation may carry.
>
> I say that in Forth it's impossible because this behaviour is strong
> related to a typing system. And Forth is an untyped language.

Well, this is mostly a naming-convention issue.

For one thing, I recommend the dot prefix for field names. In the novice-package style, you could have this (my example is a child of LIST whereas your example didn't have a parent function):

list \ name of parent class you are inheriting from, or 0 if there is no parent class
field .x
field .y
constant point \ name of this class

: init-point ( x y node -- node )
init-list >r \ the >R of the node is my convention (don't use stack jugglers)
r@ .y !
r@ .x !
r> ;

: new-point ( x y -- node )
point alloc
init-point ;

variable x

: foo ( obj1 -- adjusted-x )
.x @ x @ + ;

If you use this naming convention, you can avoid name clashes between field names and global variables etc.. The only problem remaining is if you have several structs with the same field names. This doesn't usually happen, as most programs don't have very many different data types, and what they do have are all in the same inheritance chain. If they are in the same inheritance chain then they are going to clash anyway --- I don't remember how C++ resolves field name clashes between a child class and a parent class --- this is really just something to be avoided!

If you have so many classes of data that you can't avoid field name clashes, then you can use this naming convention:

list \ name of parent class you are inheriting from, or 0 if there is no parent class
field point.x
field point.y
constant point \ name of this class

: init-point ( x y node -- node )
init-list >r \ the >R of the node is my convention
r@ point.y !
r@ point.x !
r> ;

: new-point ( x y -- node )
point alloc
init-point ;

variable x

: foo ( obj1 -- adjusted-x )
point.x @ x @ + ;

This should give you all of the capability that you would have in C --- the source-code becomes somewhat bloated though --- I only recommend this naming convention in gigantic complicated programs in which the simple naming convention is inadequate.

Getting back to the subject of inheritance, our POINT struct inherited the fields of the LIST struct, so all of the LIST method functions (such as EACH and FIND-NODE etc.) will work with a list of POINT structs. It is possible to define child structs of POINT too. Using the simple naming-convention, we have:

point
field .r
field .area
constant circle

: init-circle ( radius x y node -- node )
init-point >r
dup r@ .r !
dup * 355 113 */ r@ .area !
r> ;

: new-circle ( radius x y -- node )
circle alloc
init-circle ;

Raimond Dragomir

unread,
May 30, 2015, 12:42:38 PM5/30/15
to
> I don't recommend polymorphism in Forth --- if this is what you want, then just program in C++ or some such language (Forth isn't for every program or for every programmer).
>
Hugh, I'm using the same structs as you do (in fact there's only the word FIELD)
This is so simple and elegant that I really don't understand why it was not standardized years before (in the tentative 20xy standard there is an
obfuscated version of structures IMO).

I only responded here to a post whith "powerfull C like structs in VFX".
I pointed out that the forth structs are not so powerfull like the C ones.
This is just a fact. Every language has pluses and minuses.
And it seems that it is not me who is trying hard to make the forth
look like C. Alex McDonald gave a lot of links here.

Stephen Pelc

unread,
May 30, 2015, 1:20:19 PM5/30/15
to
On Fri, 29 May 2015 00:49:34 -0700 (PDT), Howerd <how...@yahoo.co.uk>
wrote:

>IIRC Stephen Pelc has powerful C-like struct support in VFX, and these
>are very useful when interfacing to Windows etc.

There are plenty in VFX ranging from classical Forth-style structures
as now standardised to intelligent structures with a dot parser and
methods (see ClassVFX) to a C++ style OOP package (see CIAO - C
Inspired Active Objects).

ClassVFX was written by a client for a huge app. CIAO was written
by a member of MPE staff.

We are currently supplying five or six OOP packages. They all
have their places. Unfortunately, there is little desire for
common practice in Forth OOP anomg the Forth community. I
suspect that most OOP packages are very little used except
for GUI programming.

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

hughag...@gmail.com

unread,
May 30, 2015, 1:25:52 PM5/30/15
to
On Saturday, May 30, 2015 at 9:42:38 AM UTC-7, Raimond Dragomir wrote:
> > I don't recommend polymorphism in Forth --- if this is what you want, then just program in C++ or some such language (Forth isn't for every program or for every programmer).
> >
> Hugh, I'm using the same structs as you do (in fact there's only the word FIELD)

What do STRUCT and ENDSTRUCT do? I have never seen those before. We need to have the size stored somewhere, which is what my CONSTANT does.

> This is so simple and elegant that I really don't understand why it was not standardized years before (in the tentative 20xy standard there is an
> obfuscated version of structures IMO).

The FIELD word has been in use since the 1980s --- now Forth-200x has changed the name to +FIELD for some unknown reason (afaik, it is Stephen Pelc's version that was written differently from my FIELD in the novice package but does the same thing).

We have used { to declare locals since the 1980s, but now Forth-200x changed the name to {: because SwiftForth uses { for multi-line comments. Presumably FIELD was changed to +FIELD because SwiftForth uses FIELD for some obscure purpose --- maybe Elizabeth Rather wrote an application program that enumerates a farmer's bean fields and this is why FIELD can't be standardized for struct field definitions --- no; that is impossible: Elizabeth Rather has never written a program in her life...

Rod Pemberton

unread,
May 30, 2015, 3:34:38 PM5/30/15
to
On Sat, 30 May 2015 01:22:27 -0400, Raimond Dragomir
<raimond....@gmail.com> wrote:

>> > C structs are powerful, the fields are associated with the object.
>>
>> You must specify the struct name and field in C to access the field.
>> That's true with both of the component selection operators in C:
>> '.' and '->'
>>
>> So, what do you mean by "the fields are associated with the object?"
>
> No you don't specify the struct name, you specify the object name which
> happens to have the type of that struct.
>

I understand what you're saying.

FYI, I refer to mystruct1, mystruct2 as the type of the struct, whereas
obj1, obj2 are the names of the structs.

> struct mystruct1 { int x; int y; }
> struct mystruct2 { int y; int x; }
> struct mystruct1 obj1;
> struct mystruct2 obj2;
> obj1.x
> obj2.x
>
> Tell me how can you do that in Forth.

You're familiar with the offsetof() macro for C, yes?

I.e., every C compiler must have one or it's equivalent.
It's usually coded similarly to this:

#define offsetof(s,e) ((int)((char *)&((s *)0)->e-(char *)0))

That casts NULL, represented syntactically as '0' here, to a
pointer to the start of 's' which is used to index 'e'. The
address of s->e is taken which is relative to NULL and subtracts
NULL the start of the struct to provide the offset of 'e'
relative to the start of the struct.

AIUI, Forth usually creates a bunch of custom words for each
array for each offset. Those are like offsetof() which have
hardcoded offset value for 'e'. In C, all objects are mapped
onto an array of bytes. So, we can use arrays for structs
in Forth, like C, and build up C like functionality from there.

E.g., these take an address for the start of the struct:

: OBJ1 ( a -- a+n ) 0 CELLS + ;
: OBJ2 ( a -- a+n ) 1 CELLS + ;

CREATE MYSTRUCT1 2 CELLS ALLOT
CREATE MYSTRUCT2 2 CELLS ALLOT

MYSTRUCT1 OBJ1 @
MYSTRUCT1 OBJ2 @
MYSTRUCT2 OBJ1 @
MYSTRUCT2 OBJ2 @

Of course, you could put the @ in offset definitions:

: OBJ1 ( a -- i ) 0 CELLS + @ ;
: OBJ2 ( a -- i ) 1 CELLS + @ ;

CREATE MYSTRUCT1 2 CELLS ALLOT
CREATE MYSTRUCT2 2 CELLS ALLOT

MYSTRUCT1 OBJ1
MYSTRUCT1 OBJ2
MYSTRUCT2 OBJ1
MYSTRUCT2 OBJ2

Of course, you can define those to be their own words:

: MYSTRUCTS1.OBJ1 MYSTRUCTS1 OBJ1 ;
: MYSTRUCTS1.OBJ2 MYSTRUCTS1 OBJ2 ;
: MYSTRUCTS2.OBJ1 MYSTRUCTS2 OBJ1 ;
: MYSTRUCTS2.OBJ2 MYSTRUCTS2 OBJ2 ;

MYSTRUCTS1.OBJ1
MYSTRUCTS1.OBJ2
MYSTRUCTS2.OBJ1
MYSTRUCTS2.OBJ2

Creating a more generic version in Forth might go something
like:

: OBJ1 0 ;
: OBJ2 1 ;
: OFFSETOF ( a n -- i ) CELLS + @ ;

MYSTRUCTS1 OBJ1 OFFSETOF
MYSTRUCTS1 OBJ2 OFFSETOF
MYSTRUCTS2 OBJ1 OFFSETOF
MYSTRUCTS2 OBJ2 OFFSETOF

Or, if we rename OFFSETOF to '->' to be more C like:

: -> ( a n -- i ) CELLS + @ ;

MYSTRUCTS1 OBJ1 ->
MYSTRUCTS1 OBJ2 ->
MYSTRUCTS2 OBJ1 ->
MYSTRUCTS2 OBJ2 ->

Of course, those only work for CELL sized objects. You'd
need to simulate C's sizeof() functionality in Forth to fix
that. Forth doesn't have a typesystem, so that information
must be hardcoded by you ...

E.g.,

: OBJ1 0 1 ; \ cell size offset 0
: OBJ2 1 1 ; \ cell size offset 1

\ let's do some CHAR's too ...

: OBJC1 1 0 ; \ char size offset of 1
: OBJC2 3 0 ; \ char size offset of 3

The second value is a flag to indicate CELL sized object.

: -> ( a n x -- i ) IF CELLS THEN + @ ;

Of course, that doesn't know if the size of the object
to be fetched is a CELL or a CHAR, and so fetches a CELL
which we probably don't want for a byte sized object,
assuming it's a CHAR. Technically, Forth doesn't have
type information, but it has two data types: CELL and CHAR.
CELL serves as a large integer and as address pointers.
Strings are passed as addresses. So, we can assume if
not CELL then CHAR.

: -> ( a n x -- i ) IF CELLS + @ ELSE + C@ THEN ;


In full,

: -> ( a n x -- i ) IF CELLS + @ ELSE + C@ THEN ;

CREATE MYSTRUCT1 2 CELLS ALLOT
CREATE MYSTRUCT2 2 CELLS ALLOT

: OBJ1 0 1 ; \ cell size offset 0
: OBJ2 1 1 ; \ cell size offset 1

: OBJC1 1 0 ; \ byte size offset of 1
: OBJC3 3 0 ; \ byte size offset of 3

: MYSTRUCTS1.OBJ1 MYSTRUCTS1 OBJ1 -> ;
: MYSTRUCTS1.OBJ2 MYSTRUCTS1 OBJ2 -> ;
: MYSTRUCTS2.OBJ1 MYSTRUCTS2 OBJ1 -> ;
: MYSTRUCTS2.OBJ2 MYSTRUCTS2 OBJ2 -> ;

: MYSTRUCTS1.OBJC1 MYSTRUCTS1 OBJC1 -> ; \ char
: MYSTRUCTS1.OBJC3 MYSTRUCTS1 OBJC3 -> ; \ char
: MYSTRUCTS2.OBJC1 MYSTRUCTS2 OBJC1 -> ; \ char
: MYSTRUCTS2.OBJC3 MYSTRUCTS2 OBJC3 -> ; \ char

MYSTRUCTS1.OBJ1
MYSTRUCTS1.OBJ2
MYSTRUCTS2.OBJ1
MYSTRUCTS2.OBJ2

MYSTRUCTS1.OBJC1
MYSTRUCTS1.OBJC3
MYSTRUCTS2.OBJC1
MYSTRUCTS2.OBJC3

If you throw CREATE .. DOES> into the mix, you might be
able to automate the process of creating all or many of
those pre-liminary definitions. Hopefully, that's easy
to do for someone here who is skilled in Forth.

I.e., you could implement structs in Forth much like
rudimentary arrays with only two possible types for
each item, either CELL or CHAR . This is what they
are in C but with some sizeof() and offsetof()
information used by the compiler and additional types
thrown in to the mix.

http://www.forth.org/svfig/Len/arrays.htm
http://www.forth.com/starting-forth/sf8/sf8.html

> This is a price that Forth has to pay for it's simplicity.

Agreed.

As to whatever was going on in the rest of the thread with
Hugh, I haven't really read that.

Raimond Dragomir

unread,
May 31, 2015, 1:36:46 AM5/31/15
to
sâmbătă, 30 mai 2015, 20:25:52 UTC+3, hughag...@gmail.com a scris:
> On Saturday, May 30, 2015 at 9:42:38 AM UTC-7, Raimond Dragomir wrote:
> > > I don't recommend polymorphism in Forth --- if this is what you want, then just program in C++ or some such language (Forth isn't for every program or for every programmer).
> > >
> > Hugh, I'm using the same structs as you do (in fact there's only the word FIELD)
>
> What do STRUCT and ENDSTRUCT do? I have never seen those before. We need to have the size stored somewhere, which is what my CONSTANT does.
>

This was some pseudo code in trying to "implement" Alex's idea of using
wordlists for storing field names. STRUCT was necessary for creating
the wordlist in which the following fields would be put. ENDSTRUCT was
necessary to terminate the struct/field definitions. As I pointed out,
there is a big problem though, if the struct object word put its wordlist
on top of the search order (to make the fields visible) who is supposed to
take it back from the search order? And I gave an example of a variable x
which happen to have the same name as the struct's field x. In that scenario
obj1 x @ works as expected, because obj1 bring the wordlist that has x
defined as the field for the obj1's structure, but the second x @ doesn't
work, because the struct's wordlist is still on top of the search order
and shaddows the plain variable x.

There might be a possibility here: that the wordlist to be taken out by
the field word. This also is not working all the times: what if you want
only the object address? in this case you don't use a field after the object
name and oops, the wordlist is still remaining on the top of the search order...

No, I don't use such words. I used plain FIELD and terminate the struct
sometimes with constant but often with just a drop because I need only
the offsets to an existing object (like dictionary entry). Here is for
example my WORDS implemented in high level forth, along with the dictionary
offsets:

\ dictionary offsets
0 cell field dict->link
cell field dict->addr
cell field dict->end
cell field dict->file
cell field dict->line
cell field dict->wid
cell field dict->type
cell field dict->len
cell field dict->name
drop
1 constant DF_NORMAL \ reserved code for SEARCH
2 constant DF_IMMED \ dictionary flag immediate bit
4 constant DF_ROM \ dictionary flag ROM bit
8 constant DF_RAM \ dictionary flag RAM bit
16 constant DF_DEFER \ dictionary flag DEFER bit
DF_ROM DF_RAM or constant DF_DATA

\ WID. ( wid -- ) display wid header
[ cr ." *** WID " . ." ***" cr ] def wid.
\ NAME. ( nt -- ) display word name
[ dup dict->name @ swap dict->len @ type space ] def name.

[ get-order \ widn ... wid1 n
[| wid | wid wid.
[ ( nt ) name. true ] wid traverse-wordlist
] times
] def words ( -- )

[ get-order \ widn ... wid1 n
[| wid | wid wid.
[| nt |
nt dict->type @ DF_IMMED and if nt name. then
true
] wid traverse-wordlist
] times
] def iwords ( -- ) \ display only immediate words

Alex McDonald

unread,
May 31, 2015, 4:11:24 AM5/31/15
to
on 30/05/2015 12:08:47, Raimond Dragomir wrote:
I can't do your research or thinking for you either.

> Let me give you another example:
>
> struct mystruct
> field x
> field y
> endstruct
>
> mystruct obj1
> variable x
>
>: foo obj1 x @ x @ + ;
>
> Do you think the above foo is working?
> Suppose mystruct created an wordlist for the fields, and the fields
> are put in this wordlist.
> obj1 may put the mystruct wordlist on top of the search order.
> Who is taking it back from the search order?
> The second x has this problem. Who is x? the variable or the x field?
>
>
> This in C should be something like return obj1.x + x;
>
> How can you do that in Forth?
> Not to say that if you must pass object pointers on the data stack,
> you loo se
> any type information that a clever implementation may carry.
>
> I say that in Forth it's impossible because this behaviour is strong
> related to a typing system. And Forth is an untyped language.

The behaviour is related to no more than what structures and objects
derived from them do; either at compile time, run time or both. Typing
has nothing to do with it.

struct point
field x
field y
end-struct
point x
x :[ 3 x ! 2 y ! ]:
x :[ x @ y @ ]:

X is the structure based on POINT, :[ places POINT's wordlist in the
search order, X and Y do what the field X and field Y for POINT
structures do -- applied to the structure X -- and :] removes POINT's
wordlist from the search order. Yes, it's messy since I have done no more
than illustrate a solution, but you should get the idea.

(An aside. With recognizers we could have for example MYPOINT::X (early
binding) or MYPOINT ::X (late binding) and a much simpler parse.)

Albert van der Horst

unread,
May 31, 2015, 11:17:55 AM5/31/15
to
In article <5569ef4a....@news.eternal-september.org>,
Stephen Pelc <ste...@mpeforth.com> wrote:
>On Fri, 29 May 2015 00:49:34 -0700 (PDT), Howerd <how...@yahoo.co.uk>
>wrote:
>
>>IIRC Stephen Pelc has powerful C-like struct support in VFX, and these
>>are very useful when interfacing to Windows etc.
>
>There are plenty in VFX ranging from classical Forth-style structures
>as now standardised to intelligent structures with a dot parser and
>methods (see ClassVFX) to a C++ style OOP package (see CIAO - C
>Inspired Active Objects).
>
>ClassVFX was written by a client for a huge app. CIAO was written
>by a member of MPE staff.
>
>We are currently supplying five or six OOP packages. They all
>have their places. Unfortunately, there is little desire for
>common practice in Forth OOP anomg the Forth community. I
>suspect that most OOP packages are very little used except
>for GUI programming.

Well. I've found my one screen OOP indispensible for non-trivial programs,
like my assemblers, and the manx musical score program.
I've used that oo in 50 of the 400 Euler project problems I've solved.
Interestingly in problem 514 I had just one class with just one
object. This could have been replaced by just a bunch of variables,
and regular colon definitions. Apparently the OO thinking helps me
to keep the data straight, such as forcing relationship between fields.

I've done some GUI stuff, but never in Forth.

>
>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
--
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

humptydumpty

unread,
May 31, 2015, 2:31:41 PM5/31/15
to
Hi!

That is how I would do it in forth. It has reflection and could
be modified to have extensions for structure (excerpt from command-line):

$ gforth -e "include struct.fs"

\ Structure with reflection. To do: extensions.

: make-show-words
CREATE get-current , DOES> @ wordlist-words ;

warnings OFF
: field ( offs size -- offs+size )
over >R
: R> ?dup
IF
S>D <# [CHAR] + hold BL hold #S #>
postpone SLITERAL postpone EVALUATE
THEN
postpone ; IMMEDIATE +
;
: struct
get-current wordlist dup
CREATE , base @ , IMMEDIATE set-current 0 ( old-wid 0 )
DOES>
Base @ >R dup cell+ @ Base !
@ >order parse-name ['] evaluate
CATCH
previous R> Base !
THROW
;
: end-struct ( old-wid size -- )
S" CONSTANT SIZEOF" evaluate
S" make-show-words WORDS" evaluate
set-current
;
warnings ON

-1 [IF] sh cat struct.fs
struct POS
cell field X
cell field Y
end-struct
." POS constituents: " POS WORDS
VARIABLE X 1 X !
CREATE Ob POS SIZEOF allot
99 Ob POS X !
101 Ob POS Y !
: testX Ob POS X ? X ? ;
: testY [ Ob POS Y ]L ? X ? ;
see testX see testY
cr testX cr testY
cr .s cr bye
[THEN]

POS constituents:
WORDS SIZEOF Y X
: testX
Ob ? X ? ;
: testY
34389371344 ? X ? ;
99 1
101 1
<0>
$

Could C version have reflection?

Have a nice day,
humptudumpty

hughag...@gmail.com

unread,
May 31, 2015, 7:38:23 PM5/31/15
to
On Saturday, May 30, 2015 at 10:36:46 PM UTC-7, Raimond Dragomir wrote:
> sâmbătă, 30 mai 2015, 20:25:52 UTC+3, hughag...@gmail.com a scris:
> > What do STRUCT and ENDSTRUCT do? I have never seen those before. We need to have the size stored somewhere, which is what my CONSTANT does.
>
> This was some pseudo code in trying to "implement" Alex's idea of using
> wordlists for storing field names. STRUCT was necessary for creating
> the wordlist in which the following fields would be put. ENDSTRUCT was
> necessary to terminate the struct/field definitions. As I pointed out,
> there is a big problem though, if the struct object word put its wordlist
> on top of the search order (to make the fields visible) who is supposed to
> take it back from the search order?

In the Oberon-2 language, we had WITH blocks:
http://en.wikipedia.org/wiki/Oberon-2_(programming_language)#WITH_statement
In a Forth OOP system, I suppose something similar would be needed. The result is ugly bloated code.

As I said before, if people want OOP they should just program in an OOP language such as C++ or Object Pascal (very similar to Oberon-2) or some such thing.

For the most part, I think of Forth as being a micro-controller language --- trying to contort Forth to compete with desktop-computer programming languages is a waste of time.

Anton Ertl

unread,
Jun 1, 2015, 9:37:30 AM6/1/15
to
humptydumpty <oua...@gmail.com> writes:
>: field ( offs size -- offs+size )
> over >R
> : R> ?dup
> IF
> S>D <# [CHAR] + hold BL hold #S #>
> postpone SLITERAL postpone EVALUATE
> THEN
> postpone ; IMMEDIATE +
>;

A very nice example of the dangers of EVALUATE-based macros.

decimal
9 cells 1 cells field x drop
hex 0 x 9 cells = .

prints 0. The following implementation is both correct and simpler
(and optimizes the 0 offset case):

: +FIELD {: n1 n2 -- n3 :}
: n1 if
n1 postpone literal postpone +
else
immediate
then
postpone ; n1 n2 + ;
Message has been deleted

humptydumpty

unread,
Jun 1, 2015, 11:20:23 AM6/1/15
to
Hi!

My correction: please substitute 'reflection' with 'inspection'
in my post above.

Thanks,
humptydumpty

humptydumpty

unread,
Jun 1, 2015, 12:07:08 PM6/1/15
to
luni, 1 iunie 2015, 16:37:30 UTC+3, Anton Ertl a scris:
Hi!

'field' word must be used inside the scope of the word
created by 'struct'. Package should be used as a whole, not by parts.

As a negative aspect, 'field+' could be used only at compile-time.

I deleted previous post because of poor chosen words for message.
I'm sorry for that.

Have a nice day,
humptydumpty

humptydumpty

unread,
Jun 2, 2015, 2:31:52 AM6/2/15
to
On Monday, June 1, 2015 at 4:37:30 PM UTC+3, Anton Ertl wrote:
Hi!

They do different things (excerpt from command-line):
---
$ gforth -e "include plusfieldtest.fs"
redefined +field with +FIELD
: +FIELD { n1 n2 -- n3 }
: n1 if
n1 postpone literal postpone +
else
immediate
then
postpone ; n1 n2 + ;

sh cat plusfieldtest.fs

0
cell +field X
cell +field Y
constant /POS

CREATE Ob 99 , 101 ,

: testX Ob X ? ;
: testY [ Ob Y ]L ? ;
: 2testY Ob Y ? ;

see testX see testY see 2testY
cr testX testY 2testY

cr .s cr bye

: testX
Ob ? ;
: testY
34389370120 ? ;
: 2testY
Ob Y ? ;
99 101 101
<0>
$
$ gforth -e "include mystructtest.fs"

include struct.fs
sh cat mystructtest.fs
4 Base ! \ Just a test for independence of Base content
struct POS
cell field X
cell field Y
end-struct
DECIMAL

CREATE Ob POS SIZEOF allot

99 Ob POS X !
101 Ob POS Y !

: testX Ob POS X ? ;
: testY [ Ob POS Y ]L ? ;
: 2testY Ob POS Y ? ;

see testX see testY see 2testY
cr testX testY 2testY

cr .s cr bye

: testX
Ob ? ;
: testY
34389371624 ? ;
: 2testY
Ob 8 + ? ;
99 101 101
<0>
$
---

in '+field' version 'see 2testY' shows:
: 2testY
Ob Y ? ;

in my struct version 'see 2testY' shows:
: 2testY
Ob 8 + ? ;

and also show independence of 'Base' content.

Anton Ertl

unread,
Jun 2, 2015, 6:42:31 AM6/2/15
to
humptydumpty <oua...@gmail.com> writes:
>in '+field' version 'see 2testY' shows:
>: 2testY
> Ob Y ? ;
>
>in my struct version 'see 2testY' shows:
>: 2testY
> Ob 8 + ? ;

And SEE Y shows

: Y
8 + ; ok

The behaviour is the same, but admittedly the run-time is slower on
Forth systems that don't inline automatically.

>and also show independence of 'Base' content.

Yes, I took a closer look at your STRUCT and the usage patterns, and
found that you have integrated a workaround for the BASE problem. An
alternative would be to use a number prefix to make the string BASE
independent.

What is still missing is a workaround that guarantees that the right
"+" will be found. Counterexample for the current implementation:

struct POS
cell field X
cell field Y
end-struct

: + cr ." funny +" cr ;

CREATE Ob POS SIZEOF allot
Ob POS Y .s

After fixing this the result is certainly an interesting solution to
the field (and method?) name overloading resulution problem in the
context of the current standard (you would need to get rid of some
Gforthisms, but that should be possible). The interesting part is in
STRUCT and would work also with the +FIELD I defined (but, as seen
above, there is a difference in inlining).

That problem has led to defining words for STATE-smart words in Bernd
Paysan's OOF and AFAIK other programs. Other proposed solutions to
the problem go outside the standard: preludes and the dot-parser (the
latter implemented with recognizers). I think it's cleaner than a
STATE-smart approach.

What you cannot do with it directly is ticking and postponing POS Y,
but you can define

: pos-y POS Y ;

and tick or postpone that. However, why not just define POS-Y without
overloading right from the start? Always writing POS Y instead of
POS-Y is not an advantage.

One possible advantage is in the context of inheritance: If you have a
class A with field X and class B and C inherit field X from A, you
don't want to refer to the field with A-X (because that would make
reorganizing the class hierarchy hard); referring to the field with
A X or B X or C X would be possible with a variation of your
technique, and would restrict class reorganizations only as necessary.

humptydumpty

unread,
Jun 2, 2015, 4:07:58 PM6/2/15
to
marți, 2 iunie 2015, 13:42:31 UTC+3, Anton Ertl a scris:
Hi!

A cure for improbable but possible redefinition of '+'
could be:

---
\ Add on top of source
VOCABULARY UNTAINTED
get-current ALSO UNTAINTED DEFINITIONS
' + alias +
set-current PREVIOUS

\ Redefine 'struct' as:
: struct
get-current wordlist
dup CREATE , base @ , IMMEDIATE set-current 0 ( old-wid 0 )
( Now compile fields in structure-wordlist )
DOES>
Base @ >R
dup cell+ @ Base !
@ >order ALSO UNTAINTED
parse-name ['] evaluate
CATCH
PREVIOUS previous R> Base !
THROW
;
---

About syntax, this way I read 'Ob POS Y':
From address 'Ob' using recipe 'POS' get address of meaning 'Y'.

That that I could use other recipe for address 'Ob' is another story.

If I extend 'POS' structure with field 'COLOR', and alias old structure
with name 'PIXEL' I could have a sort of inheritance..

I think that shortly I'll post a new version of structure-lexicon.
0 new messages