Programming in Forth with Forth style

Description of the page content

Some examples of Forth code written without the Forth style, and how to rewrite them.

Tags:

Sometimes I've found Forth code that is written without the Forth style. This page shows two examples, and how I rewrote them. This page is a brief version of the original article in Spanish, with step by step changes in the code.

Example 1

In Sideras (page in Spanish), a little game written in Ace Forth by an unknown author, I found the following word:

: izq
  x @ 0 > ascii 5 k= and
  if
    x c@ 1- x !
  then
;

The word k= has the following definition (but it's not relevant for the example);

: k=  inkey =  ;

The word izq (abbreviation of "left" in Spanish) tests the 5 key and, if the player's x coord is more than zero, it is decreased.

It works... But it's not the Forth's style. Here you are my alternative:

: izq  x dup @ ascii 5 k= - 0 max swap !  ;

Result:

| |= original code |= new code | |= words | 15 | 11 | |= control structures | 1 | 0 | |= calculations | 2 | 1 | |= times the x variable is mentioned | 3 | 1 |

In Ace Forth, the result of a boolean operation is 0 or 1. In ANS Forth the result is 0 or -1 (more useful and logical), so the code would be:

: izq  x dup @ [char] 5 k= + 0 max swap !  ;

Example 2

Let's see a larger example. The listing of Chase, a little game for the Jupiter Ace, was published by Andrew Curtis in Popular Computing Weekly in 1983.

Original code

The original code is almost ilegible:

10 VARIABLE X
15 VARIABLE Y
1 VARIABLE A
1 VARIABLE B

: CHASE CLS 10 X ! 15 Y ! 1 A ! 1 B ! BEGIN X @ Y @ AT ."  " A @ B @ AT ."  " INKEY 53 = IF Y @ 2 - Y ! THEN INKEY 54 = IF X @ 2 - X ! THEN INKEY 55 = IF X @ 2 + X ! THEN INKEY 56 = IF Y @ 2 + Y ! THEN X @ 20 > IF 20 X ! THEN Y @ 30 > IF 30 Y ! THEN X @ 1
 < IF 1 X ! THEN Y @ 1 < IF 1 Y ! THEN X @ A @ = IF Y @ B @ = IF ." GOT YOU!" 250 1000 BEEP QUIT THEN THEN X @ A @ > IF A @ 1+ A ! THEN X @ A @ < IF A @ 1– A ! THEN Y @ B @ > IF B @ 1+ B ! THEN Y @ B @ < IF B @ 1– B ! THEN X @ Y @ AT ." A" A @ B @ AT
." E" 250 70 BEEP 0 1 = UNTIL ;

In lowercase and with proper indentation, the code looks much better. It's clear the code was written with the style of BASIC: many conditionals, and many redundant calculations.

10 variable x
15 variable y
1 variable a
1 variable b

: chase
  cls
  10 x ! 15 y !
  1 a ! 1 b !
  begin
    x @ y @ at ."  "
    a @ b @ at ."  "
    inkey 53 = if y @ 2 - y ! then
    inkey 54 = if x @ 2 - x ! then
    inkey 55 = if x @ 2 + x ! then
    inkey 56 = if y @ 2 + y ! then
    x @ 20 > if 20 x ! then
    y @ 30 > if 30 y ! then
    x @ 1 < if 1 x ! then
    y @ 1 < if 1 y ! then
    x @ a @ = if
      y @ b @ = if
        ." got you!" 250 1000 beep quit
      then
    then
    x @ a @ > if a @ 1+ a ! then
    x @ a @ < if a @ 1– a ! then
    y @ b @ > if b @ 1+ b ! then
    y @ b @ < if b @ 1– b ! then
    x @ y @ at ." A"
    a @ b @ at ." E"
    250 70 beep
    0 1 =
  until
;

Modified code

This is my version, with no conditional structure, simplified calculations and simpler main loop:

10 variable x
15 variable y
1 variable a
1 variable b

: chase
  cls
  10 x ! 15 y !
  1 a ! 1 b !
  begin
    x @ y @ at space
    a @ b @ at space
    y @ inkey 53 = 2 * - inkey 56 = 2 * + 1 max 30 min y !
    x @ inkey 54 = 2 * - inkey 55 = 2 * + 1 max 20 min x !
    x @ a @ = y @ b @ = and 0=
  while
    a @  x @ over > +  x @ a @ < negate +  a !
    b @  y @ over > +  y @ b @ < negate +  b !
    x @ y @ at ." A"
    a @ b @ at ." E"
    250 70 beep
  repeat
  ." got you!" 250 1000 beep
;

It's almost Forth style, but not completely: Factoring is needed. Instead of one large word, many little specialized and independent words are better: the code gets easier to read and mantain.

The result of factoring the code of Chase became a new program: Heat Seeker.