[comp.lang.forth] Random comments

aj-mberg@dasys1.UUCP (Micha Berger) (08/01/89)

First, my appologies of starting the "real programmer" thread. It was
written tongue-in-cheek, and fit in with the general tone of
talk.religion.computers at the time.

As someone new (less than 1 month, only have one working program - life)
to FORTH, 2 things really bug me. Why is it that we have 2!, 2DUP, 2CONSTANT,
but D. ? It seems inconsistant. You can't use 2 as a prefix across the board
(2+ and 2* are taken) but why not use D? I also mind that DO loops up to,
not including the limit - it's not intuitive.

I appreciate all the sugestions and responses to my last post. I'm writing
words to define a "parameter list" without the rest of the definition. It
should let me implement a vectored execution scheme without wasting alot of
space on headers. Any comments??

-- 
					Micha Berger

"Always should [the child of] Adam have awe of G-d in secret and in public,
admit the truth, and speak truth in his heart." 

sdh@wind.bellcore.com (Stephen D Hawley) (08/03/89)

In article <10425@dasys1.UUCP> aj-mberg@dasys1.UUCP (Micha Berger) writes:
> I also mind that DO loops up to,
>not including the limit - it's not intuitive.

Depends on what your definition of intuitive is.  :')

Consider the pascal loop:
	for x := 1 to 20 do ... ;

This runs x from 1 to 20 inclusive, just what you expect.
But what about the c loop:
	for (x=0; x < 20; x++) ... ;

This also iterates 20 times, but goes from 0 to 19.
I find this more intuitive.  Really.  I've made more boundary errors with
pascal than with any other language (iterate once too many or once too few).
I think this is because of the tendency to start at 1 in pascal.  Most of the
programs I've seen in pascal do this (as well as declaring arrays as [1..n]).

Fine.  So what does this have to do with forth?  Well, not much really,
except that 'intuitive' is subjective, not universal.

Steve Hawley
sdh@flash.bellcore.com
"Up is where you hang your hat."
	--Jim Blandy, computer scientist

toma@tekgvs.LABS.TEK.COM (Tom Almy) (08/03/89)

In article <10425@dasys1.UUCP> aj-mberg@dasys1.UUCP (Micha Berger) writes:
>As someone new (less than 1 month, only have one working program - life)
>to FORTH, 2 things really bug me. Why is it that we have 2!, 2DUP, 2CONSTANT,
>but D. ? It seems inconsistant. You can't use 2 as a prefix across the board
>(2+ and 2* are taken) but why not use D? 

The prefix "D" refers to double integer (typically 32 bit in a 16 bit FORTH
implementation), while the prefix "2" refers to a pair of integers.  A double
integer is a subclass of a pair of integers -- as a practical example, a pair
of integers can be used to express a ratio used in scaling with */:
	2VARIABLE Ratio
	: setRatio   ( numerator denominator -- )  Ratio 2! ;
	: scaleValue  ( value -- scaledValue )  Ratio 2@ */ ;

In this application, use of D! and D@ would be confusing.  

There is a practical reason to have both D@ and 2@ (etc).  LMI UR/FORTH 386
implements both operations, and they are not the same!  The 83 standard 
defines 2@ such that the lower address integer becomes top of stack, and the
next integer becomes second on stack.  In the 80386 (and other Intel 
architectures), the most significant portions of numbers are stored at the
highest addresses.  This means that using double integers will store into
memory wrong, causing problems with the OS interface or interfacing with
other language programs.  D@ and D! access memory in Intel standard order.

I also mind that DO loops up to,
>not including the limit - it's not intuitive.

Every new standard seems to have a new way of handling DO loops (I don't
know if the ANSI standard will be different).  It may not be very intuitive,
but the reason is that indexing is 0 based, so that loops typically have
an initial value of 0; to loop n times you execute "n 0 DO".

Tom Almy
toma@tekgvs.labs.tek.com
I have a commercial connection with Laboratory Microsystems.

ZMLEB@SCFVM.BITNET (Lee Brotzman) (08/03/89)

>
>First, my appologies of starting the "real programmer" thread. It was
>written tongue-in-cheek, and fit in with the general tone of
>talk.religion.computers at the time.

   Apology accepted.  At least it generated a good side-effect -- more
traffic in a very slow newsgroup!

>
>As someone new (less than 1 month, only have one working program - life)
>to FORTH, 2 things really bug me. Why is it that we have 2!, 2DUP, 2CONSTANT,
>but D. ? It seems inconsistant. You can't use 2 as a prefix across the board
>(2+ and 2* are taken) but why not use D? I also mind that DO loops up to,
>not including the limit - it's not intuitive.

   I believe the '2' prefix for double numbers came about because a double
number does not always imply a double-length integer.  The data item might
be a pair of single-length integers, e.g. X-Y coordinates on a grid.  While
'2' is somewhat appropriate for both situations, 'D' clearly is not.  I
often use 2DUP to duplicate two single-length values on the stack.  DDUP
wouldn't "feel" right.
   But remember, this is Forth.  If you don't like a name, then you can
always do the following:

   : D! 2!;
   : DCONSTANT 2CONSTANT ;
   : DO SWAP 1+ SWAP [COMPILE] DO ; IMMEDIATE

   Unless you are distributing source code to the public (in which case
the renaming and redefinition of standard words renders the code nearly
useless) then I would suggest you put all the redefinitions in a file
(or set of blocks depending on your situation) and INCLUDE them whenever
you compile.  Better yet, you can compile the redefintions and do a
SAVE-SYSTEM and they will be there always.

>I appreciate all the sugestions and responses to my last post. I'm writing
>words to define a "parameter list" without the rest of the definition. It
>should let me implement a vectored execution scheme without wasting alot of
>space on headers. Any comments??

    An off the cuff, thirty-second design phase vectored execution scheme:

    : EXEC-VECTOR  ( compile time: n -- ...number of vectors to allocate )
                   ( execution:    n -- ...number of vector to execute )
        CREATE 2* ALLOT
        DOES>  SWAP 2* + @ EXECUTE ;

    : STORE-VECTOR  ( n -- ...cell number to store execution vector into)
                    ( this word is used like:  n STORE-VECTOR <to> <from> )
                    ( where: n is the cell number, <to> is the vector array )
                    ( and <from> is the word to put in the array )
      ' >BODY   ( n pfa-to -- ...get pfa of <to> )
      SWAP 2* + ( cell-adr -- ...calculate vector cell address )
      '         ( cell-adr cfa-from -- ...get cfa of <from> )
      SWAP ! ;  IMMEDIATE   ( store the execution vector )

    10 EXEC-VECTOR ADDS
    0 STORE-VECTOR ADDS +
    1 STORE-VECTOR ADDS D+
    2 STORE-VECTOR ADDS F+

    So, '0 ADDS' will result in '+' being executed, and '2 ADDS' will execute
'F+'.  Actually the example isn't very practical.  I have used a very similar
scheme, however, in a text editor.  I have an execution vector array with 128
cells in it.  Each cell points to a different editing function.  The character
entered on the keyboard is the index into the array that specifies which
function is being called.  So my word EDIT is just:

    : EDIT   GET-FILE    ( Open, create, or re-establish like to the file )
             INITIALIZE  ( set up some stuff to get started )
      BEGIN  KEY DO-EDIT  AGAIN;   ( DO-EDIT is the name of the vector array )

    Cells which correspond to regular characters, like 'A', execute the word
CHARACTER , which stores the character into the file.  The cell which
corresponds to control-A (decimal 1) executes the word ADDLINE, i.e. when
I press control-A, a new line is added to the file being edited.  This makes
it real easy to reconfigure the editor.  Plus I can use forth as an editor
macro language, just define a new editing function and tie the CFA to the
vector array.

>                                        Micha Berger
>

-- Lee Brotzman (FIGI-L Moderator)
-- BITNET:   ZMLEB@SCFVM
-- Internet: zmleb@scfvm.gsfc.nasa.gov
-- The government and my company don't know what I'm saying.
-- Let's keep it that way.

eaker@sunbelt.crd.ge.com (Charles E Eaker) (08/04/89)

In article <10425@dasys1.UUCP> aj-mberg@dasys1.UUCP (Micha Berger) writes:
>As someone new (less than 1 month, only have one working program - life)
>to FORTH, 2 things really bug me. Why is it that we have 2!, 2DUP, 2CONSTANT,
>but D. ? It seems inconsistant. You can't use 2 as a prefix across the board
>(2+ and 2* are taken) but why not use D?

Here's why. The prefix 2 generally means operate on 2 things of the
usual size.  The "usual size" in Forth has traditionally been a 16-bit
"cell".  Note that the operations 2!, 2DUP, and 2CONSTANT could care
less what the 2 cells are interpreted to be. They could be two single
numbers or 1 double number or 4 characters or one or more bit strings
representing a set or representing a packed record structure or
representing a date.  But the dot operation which prints its operand
must interpret the operand's contents.  D. interprets two cells as
being one double number. Another operation, say .TIME might interpret
the two cells as representing seconds since some specified moment. I
suppose a reasonable action for 2. would be to print the two cells as
two consecutive single numbers.

   [What bugs ME is the traditional asymetry between D. and ." and the
    inclination to use the dot as a prefix in other print words such as
    .TIME . Instead, I think that the dot should uniformly be a suffix
    so that to print something right adjusted in a field whose width is
    on the stack we would use D.R and ".R and TIME.R but I'm afraid
    that using dot as a prefix to mean print is now too deeply
    ingrained.]

>                                         I also mind that DO loops up to,
>not including the limit - it's not intuitive.
>

On the contrary, I find DO loop limits in Forth to be quite intuitive.
I always get it right in Forth, I never get it right in Pascal, I
often get it right in C. A limit, after all, is easily thought of
as something which is never quite reached.
If you want to initialize SIZE cells of an array, for example, 
starting at address ARRAY with the pattern PAT, you would use:
     ARRAY SIZE + ARRAY DO I PAT ! LOOP
otherwise you would constantly have to subtract one:
     ARRAY SIZE + 1- ARRAY DO I PAT ! LOOP
which strikes me as being an unnecessary and counter-intuitive nuisance
in a piece of code that becomes a cliche in any array processing
application. (Or would you rather the value of SIZE be one less than
the actual size of the array? That's even more counter-intuitive.)

For being new to Forth, you're asking good questions.
Chuck Eaker                                |  eaker@sunbelt.crd.ge.com
Software Engineering Program               |  eaker@crdgw1.crd.ge.com
GE Corporate Research & Development Center |  eaker@crdgw1.UUCP
P.O. Box 8, K-1 3C12 Schenectady, NY 12301 |  518 387-5964                     

marc@noe.UUCP (Marc de Groot) (08/05/89)

In article <10425@dasys1.UUCP> aj-mberg@dasys1.UUCP (Micha Berger) writes:
>Why is it that we have 2!, 2DUP, 2CONSTANT,
>but D. ? It seems inconsistant. You can't use 2 as a prefix across the board
>(2+ and 2* are taken) but why not use D?

2@ and 2! were intended to fetch and store pairs of single-precision numbers.
D. prints one double-precision number.


-- 
Marc de Groot (KG6KF)                   These ARE my employer's opinions!
Noe Systems, San Francisco
UUCP: uunet!hoptoad!noe!marc
Internet: marc@kg6kf.AMPR.ORG

ir230@sdcc6.ucsd.EDU (john wavrik) (08/06/89)

    Tom Almy (toma@tekgvs.labs.tek.com) writes:
> The prefix "D" refers to double integer (typically 32 bit in a 16 bit FORTH 
> implementation), while the prefix "2" refers to a pair of integers.  A 
> double integer is a subclass of a pair of integers ...
 
> There is a practical reason to have both D@ and 2@ (etc).  LMI UR/FORTH 386 
> implements both operations, and they are not the same!  The 83 standard 
> defines 2@ such that the lower address integer becomes top of stack, and the 
> next integer becomes second on stack.  In the 80386 (and other Intel 
> architectures), the most significant portions of numbers are stored at the 
> highest addresses.  This means that using double integers will store into 
> memory wrong, causing problems with the OS interface or interfacing with 
> other language programs.
-----------------------------------------------------------------------------
                        IMPLEMENTATION DEPENDENCE
 
    There is at least a conceptual difference between a double-precision 
number and an ordered pair of single-precision numbers. The number pair 
operations (with prefix 2) should, as Tom Almy points out, always refer to 
ordered pairs of integers of whatever size. On the other hand, 32-bits seems 
to be the current standard (among other languages) for "long" integers. If 
this were to be the accepted definition of the Forth double-numbers then "D" 
and "2" operations would be different on 32-bit machines.  The ANSI standards 
team, however, seems to lean toward making D-numbers twice the cell size. 
Their BASIS document says:
      "The order in memory of ordered pairs, being structured data, 
      must be predictable. On the other hand experience has 
      indicated that there may be significant advantages to choosing 
      a hardware compatible representation of double numbers in 
      memory". 
An argument could be made for the reverse: As long as 2@ and 2! are 
compatible, the order in memory doesn't matter. On the other hand, the 
component words of a double precision number have arithmetic significance. 
[When used as the basis of multi-precision arithmetic, for example, the high 
word is the "carry" to the next position -- and it must be in a predictable 
place.]
 
   In any case, when dealing with compound data, one can either provide a 
programmer with information about how the data is represented, or one can 
provide selector and manipulator functions to deal with an unknown 
representation. (It is interesting that the ANSI team is proposing that the 
representation of double numbers be implementation-dependent but has not 
suggested selectors for the high and low words!) 
 
    Almy's also gives justification for making data representations 
implementation-dependent. The fact that the Intel chips (as well as others) 
store an integer with the low BYTE lower in memory has no bearing on 2@ vs D@. 
On the Intel 80286, 8086, 8088 there is no architecture-preferred order for 
the 16-bit words of a 32-bit number. 32-bit arithmetic operations on the 80286 
use pairs of registers and these can be pushed or popped in any order. Either 
order is equally fast and neither is "wrong". When a 16-bit Forth is 
implemented on a machine with 32-bit registers there is a machine preferred 
order -- but, in this case, it seems best to use a 32-bit Forth stack. No 
problems have been found with OS interfacing on an 80286-based system (and 
double-precision numbers are not needed for such interfacing!). 
 
   Forth lacks the ability of compiled languages to trap illegal operations on 
mixed data. Some of its amazing robustness and portability are due to an 
historical consistency in implementation: sequences like 2! followed by an 
eventual @ lead to predictable results (counter-intuitive, but predictable!). 
If I were on the Standards team, I'd think long and hard before giving up 
consistency in implementation. Not only will it mean an increase in 
complexity, but also an increase in subtle bugs when applications are 
transported. 
 
 
                                                  John J Wavrik
             jjwavrik@ucsd.edu                    Dept of Math  C-012
                                                  Univ of Calif - San Diego
                                                  La Jolla, CA  92093
 

toma@tekgvs.LABS.TEK.COM (Tom Almy) (08/07/89)

In article <4605@sdcc6.ucsd.EDU> ir230@sdcc6.ucsd.EDU (john wavrik) writes:
[concerning my previous comment about D@ and D! being machine dependent and
 2@ and 2! memory order being a language standard]
>An argument could be made for the reverse: As long as 2@ and 2! are 
>compatible, the order in memory doesn't matter. 

Not necessarily so, and the reason LMI added D@ and D!, was that they changed
2@ and 2! from an earlier version so as to match the Intel preferred order
(oposite from the Forth standard).  This broke my code.  I have a *large*
application which used 2VARIABLEs, and 2@ and @!, to hold x,y coordinate
points.  I rely on "@" getting the Y value and "WSIZE + @" getting the X
value.  So the order is important!

>   In any case, when dealing with compound data, one can either provide a 
>programmer with information about how the data is represented, or one can 
>provide selector and manipulator functions to deal with an unknown 
>representation. (It is interesting that the ANSI team is proposing that the 
>representation of double numbers be implementation-dependent but has not 
>suggested selectors for the high and low words!) 

Good point.  My problem would have been solved had there been something
like 2A@ and 2B@ for the "A" and "B" elements of the pair!

> 
>    Almy's also gives justification for making data representations 
>implementation-dependent. The fact that the Intel chips (as well as others) 
>store an integer with the low BYTE lower in memory has no bearing on 2@ vs D@. 
>On the Intel 80286, 8086, 8088 there is no architecture-preferred order for 
>the 16-bit words of a 32-bit number. 32-bit arithmetic operations on the 80286 
>use pairs of registers and these can be pushed or popped in any order. Either 
>order is equally fast and neither is "wrong". 

Of course you are right from an architectural point of view.  The preferred
order must be inferred from the "little-endian" architecture.  But when 
interfacing with other languages, 32 bit numbers had better be stored with
least significance in the lower addresses.  This is also important if you
intend to access the data in the 80386 -- I have been "burned" by several
Forth programs that 32 bit data via 2!, and then my 80386 native program
has to swizzle the data to read it.  Ugh!

>No
>problems have been found with OS interfacing on an 80286-based system (and 
>double-precision numbers are not needed for such interfacing!). 

You are absolutely correct.  But there is confusion over ordering of 
segment/offset pairs, if you consider the segment to be of greater numeric
significance.
 
Tom Almy
toma@tekgvs.labs.tek.com
Standard Disclaimers Apply