Forth Synergy
๐ง๐ง๐ง๐ง
๐
July 24, 2021
FORTH ๐บ
the LONE WOLF
FORTH IS POWERFUL ๐ฒ
๐ค
โข Compile Time Metaprogramming
โข Domain Specific Languages
FORTH IS SUCCINCT ๐
๐ค
: WASHER
WASH SPIN RINSE SPIN ;
But FORTH can be CRYPTIC! ๐ฎ
๐ค
: ch>stream ( ch st -- )
dup wait-write
>r r@ >write @ r@ >offset c!
r@ >write @ 1+ r@ @ mod r> >write ! ;
How can we program
๐ช
Forth together?
Do we ๐น
want to?
More Hands aren't
Always Good!
๐ฎ๐ ๐ฎ๐ ๐ฎ๐ ๐ฎ๐
๐ฎ๐ ๐ฎ๐ ๐ฎ๐ ๐ฎ๐
๐ฎ๐ ๐ฎ๐ ๐ฎ๐ ๐ฎ๐
๐ฎ๐ ๐ฎ๐ ๐ฎ๐ ๐ฎ๐
WHY THEN? ๐๐๐๐
๐ค
โข Sometimes you're programming
with YOURSELF from years ago
โข We use words because
we hope to connect!
โข Help Forth play in a complex world
FOCUS ON TWO GAPS
๐ค
โข Modularity ๐
โข Data Abstraction
MODULARITY ๐
๐ค
โข Be explicit about interfaces
โข Limit how much has to be
understood at once
โข Limit the effects of change
THINKING FORTH: ๐
๐ค
"But Forth extends the concepts of modularity
and information-hiding further than any other
contemporary language. Forth even hides
the manner in which words are invoked and
the way local arguments are passed."
How to make
๐
a Module?
FORML ๐จโโ๏ธ - Dewey Val Schorre
๐ค
: INTERNAL ( --> ADDR) CURRENT @ @ ;
: EXTERNAL ( --> ADDR) HERE ;
: MODULE( ADDRl ADDR2 --> )PFA LFA ! ;
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
https://www.complang.tuwien.ac.at
/forth/forth-dimensions/FD-V2.pdf
INTERNAL ๐จโโ๏ธ
100 constant stack-depth
create elements stack-depth cells allot
variable tos elements tos !
EXTERNAL
: >p ( n -- ) cell tos +! tos @ ! ;
: p@ ( -- n ) tos @ @ ;
: p> ( -- n ) p@ -1 cells tos +! ;
MODULE
GET-CURRENT VOCABULARY Stack ALSO Stack DEFINITIONS
100 constant stack-depth
create elements stack-depth cells allot
variable tos elements tos !
SET-CURRENT
: >p ( n -- ) cell tos +! tos @ ! ;
: p@ ( -- n ) tos @ @ ;
: p> ( -- n ) p@ -1 cells tos +! ;
PREVIOUS ๐ซ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
https://www.complang.tuwien.ac.at/forth/gforth
/Docs-html/Word-list-example.html#Word-list-example
PROBLEMS ๐ ๐คข
๐ค
โข Internals can't call externals
โข Externals are shared with everyone
( What if this is INTERNAL? ๐คข )
: pover p> p> dup >r >p >p r> ;
( But this is EXTERNAL ๐ฒ)
: 2pdup pover pover ;
GET-CURRENT VOCABULARY Stack ALSO Stack DEFINITIONS
100 constant stack-depth
create elements stack-depth cells allot
variable tos elements tos !
: >p ( n -- ) cell tos +! tos @ ! ; ๐
: pover p> p> dup >r >p >p r> ; ๐
SET-CURRENT
: 2pdup pover pover ; ๐
: >p >p ; ๐
: p@ ( -- n ) tos @ @ ;
: p> ( -- n ) p@ -1 cells tos +! ;
PREVIOUS
+----------+
| stack.fs |<----+
+----------+ |
^ |
| |
+-+------+ +---+----+
| foo.fs |-->| bar.fs |
+--------+ +--------+
^ ^
| |
+-+------++
| main.fs |
+---------+
N+1th MODULE SYSTEM โโ
๐ค
โข Python like import syntax
โข Explicit out of order exports
โข Two wordlists per module
โข Share instances of an import
modules.fs ๐
โโโโโโโโโโ
wordlist constant modules
variable exporting
: >wordlist ( xt wid -- )
get-current >r set-current execute r> set-current ;
: import-name ( a n -- )
2dup included? 0= if
2>r exporting @ wordlist exporting ! ( new exports )
2r> 2dup 2>r nextname exporting @ ['] constant modules >wordlist
get-current get-order ( save search order )
only forth wordlist >order definitions ( new wordlist )
2r> 2dup 2>r included
set-order set-current ( restore search order )
exporting ! ( restore exports ) 2r>
then
modules search-wordlist 0= throw execute >order ;
: import ( "module" ) bl parse import-name ;
: alias-last latest name>string nextname lastxt alias ;
: export ['] alias-last exporting @ >wordlist ;
collections/stack.fs ๐
โโโโโโโโโโโโโโโโโโโโ
100 constant stack-depth
create elements stack-depth cells allot
variable tos elements tos !
: >p ( n -- ) cell tos +! tos @ ! ; EXPORT
: p@ ( -- n ) tos @ @ ; EXPORT
: p> ( -- n ) p@ -1 cells tos +! ; EXPORT
foo.fs โจ
โโโโโโ
import collections/stack.fs
import bar.fs
: run 1 >p 2 >p 3 >p 3p. ; EXPORT
bar.fs ๐ฅ
โโโโโโ
import collections/stack.fs
: 3p. p> p> p> . . . cr ; EXPORT
main.fs ๐ฆ
โโโโโโโ
needs modules.fs
import foo.fs
run bye
โ ๏ธ ~ WARNING ~ โ ๏ธ
Uncertain Findings
ELEMENTS OF PROGRAMMING ๐งช
๐ค
โข Primitive Expressions
- the simplest entities
the language is concerned with
โข Means of Combination
- how compound elements are built
from simpler ones
โข Means of Abstraction
- how compound elements can be
named and manipulated as units
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
https://mitpress.mit.edu/sites/default
/files/sicp/full-text/sicp/book/node5.html
MEANS OF DATA COMBINATION ๐งช
๐ค
โข In conventions languages structures and arrays
- Structures are feasible in Forth, but unidiomatic
- Arrays in Forth are untyped
โข This is a weak spot in Forth's typical usage
- You can easily define strings,
but not so easily fuse 2 of them into
a First+Last name "thing".
- You can make a stack and a string,
but this doesn't naturally create a stack of strings.
MEANS OF DATA ABSTRACTION ๐งช
๐ค
โข CREATE DOES> is the closest mechanism in Forth
- But it dispatches only a single operation.
OBJECT ORIENTED LEXICONS ๐งฑ
๐ค
โข SWOOP or other OO lexicons "solve" Forth's weak
data combination and abstraction,
but at the cost of a "C++/Java in Forth" style.
โข OO puts data first, which usually requires naming
that data. Forth wants data hidden/implicit:
: WASHER
WASH SPIN RINSE SPIN ;
CLASS POINT โด๏ธ
VARIABLE X
VARIABLE Y
: SHOW ( -- ) X @ . Y @ . ;
: DOT ( -- ) ." Point at " SHOW ;
END-CLASS
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
http://soton.mpeforth.com/flag/swoop/index.html
POINT BUILDS ORIGIN โด๏ธ
5 ORIGIN X !
8 ORIGIN Y !
ORIGIN DOT
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
http://soton.mpeforth.com/flag/swoop/index.html
0 VALUE FOO \ Contains pointer to instance
POINT NEW TO FOO \ Construct instance of class POINT
8 FOO USING POINT X ! \ Store data in X
99 FOO USING POINT Y ! \ Store data in Y
FOO USING POINT DOT \ Display X and Y
FOO DESTROY 0 TO FOO \ Release space โด๏ธ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
http://soton.mpeforth.com/flag/swoop/index.html
DATA GENERALIZATION ๐๏ธ
๐ค
โข Naturalistic Forth relies on
implict scope/context
โข When data needs to generalize,
this best happens by introducing
abstraction of that context
APPROACHES TO GENERALIZATION ๐๏ธ
๐ค
โข Singleton - UPDATE, PAD
โข Additional Stacks
โข Implicit Stack - String stack
โข Explicit Stack - Graphics Context
โข Named - VOCABULARY, USE
โข References - OPEN-FILE, ALLOCATE
IMPLICIT STACK ๐
๐ค
$" foo" $" bar" $+ $.
EXPLICIT STACK ๐
: box ( n -- ) ๐ฅก
4 0 do
dup fd 90 rt
loop drop ;
save-pen ๐๏ธ
100 100 moveto
10 box
200 200 moveto
10 box
restore-pen
NAMED ๐
๐ค
screen 10 box
printer 10 box
REFERENCES ๐
๐ค
โข Passed around on stack
โข Remeber to release it!
EASY TRANSITIONS ๐บ
๐ค
Singleton โ Stack
Singleton โ Named
HARD TRANSITIONS ๐ต
๐ค
Singleton โ References
โข Update all callers
โข Manage lifetime
How to avoid
๐
References?
s" source.txt" R/O OPEN-FILE
READ-COMPLEX-DATA
CLOSE-FILE ๐๏ธ
s" source.txt" R/O OPEN-FILE infile
s" dest.txt" W/O OPEN-FILE outfile
infile READ-COMPLEX-DATA
outfile WRITE-COMPLEX-DATA
infile CLOSE-FILE
outfile CLOSE-FILE ๐
s" source.txt" R/O OPEN-FILE
s" dest.txt" W/O OPEN-FILE
READ-COMPLEX-DATA FILE-SWAP
WRITE-COMPLEX-DATA
CLOSE-FILE
CLOSE-FILE ๐๏ธ
What about
๐ฆ
Generics?
"PARTS" โ๏ธ
๐ค
โข Create a scope/context
bearing thing
โข Use variables defined
relative to a context
โข Capture enough info to
allocate multiple instances
variable @part โ๏ธ
: part ( "name" ) create here @part ! 0 , 0 , ;
: var ( sz "name" ) create @part @ , @part @ cell+ @ ,
@part @ cell+ +!
does> dup @ @ swap cell+ @ + ;
: tuple ( n sz "name" ) swap 1- for dup var next drop ;
: part@ ( pt -- pt ) @ ; : part! ( a pt -- ) ! ;
: part+! ( n a -- ) dup part@ rot + swap part! ;
: size ( a -- ) cell+ @ ;
: singleton ( pt -- ) ๐บ
here over size allot swap part! ;
part point โด๏ธ
3 cell tuple x y z
: p! ( x y z ) z ! y ! x ! ;
: p? x @ . y @ . z @ . ;
point singleton
: named ( pt "name" -- ) ๐
create dup , size allot
does> dup cell+ swap @ part! ;
point named bob
point named joe
bob 1 2 3 p!
joe 2 3 4 p!
bob p? joe p?
๐ค
1 2 3
2 3 4 ๐ฏ
: stack ( n t "name" ) ๐
create 2dup , , 0 , here over part! size * allot ;
: pop ( st -- )
dup @ size negate swap @ part+! ;
: push ( st -- )
@ dup part@ over size dup >r over + r> cmove
dup size swap part+! ;
30 point stack pstack ๐
: pdup pstack push ;
: pdrop pstack pop ;
: p. p? pdrop ;
: p+ x @ y @ z @ pdrop
z +! y +! x +! ;
1 2 3 p! pdup
2 3 4 p! pdup
5 6 7 p! p+
p. cr
p. cr
๐ค
7 9 11
1 2 3 ๐ฅ
But I'm
๐
unsatified...
Make STACK ๐
a part?
part stack-part ๐
cell var kind
cell var start
cell var items
: stack ( n t "name" )
stack-part named lastxt execute
kind ! items ! here start !
kind @ size items @ * allot
start @ kind @ part! ;
: stack+! ( n -- ) kind @ size * kind @ part+! ;
: stack-s ( -- a n ) kind @ part@ kind @ size ;
: pop ( st -- ) -1 stack+! ;
: push ( st -- ) stack-s 2dup + swap cmove
1 stack+! ;
But still I'm
๐
unsatified...
DISCUSSION ๐บ
& QUESTIONS?
โ
Thank you!