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!