FOOS isn't half bad!

33 views
Skip to first unread message

The Beez

unread,
Sep 28, 2016, 3:42:03 PM9/28/16
to 4tH-compiler
Hi 4tH-ers!

I know when something is lacking. And it irritates me. E.g. we got some great working constructors in FOOS, but no destructors. You might say that constructors are more important than destructors - and I agree. But there are still lacking. The problem is that a class definition is just another word, which is executed - and the first thing it executes is the constructor of the superclass.

It should be the same thing with the destructor, but a word has only one execution semantics. Yes, you might define a hidden method, but how would it know the hidden method of its super? And how could we TRANSPARENTLY execute that one from the current destructor? Problems, problems..

Still, you'd better steal correctly than invent wrongly, so I tried to be inspired by other Forth OO frameworks. Not much luck. But I stumbled into this page: "An Assembly Programer's Approach to Object-oriented Forth" (http://forth.org/literature/andras.html). It had a nice OO example with number classes and I wondered if I could translate it to FOOS.

Well, no problem! It was very straightforward. As a matter of fact, I was able to duplicate every single piece of functionality without any effort (think, I fixed a few of his bugs along the way :). Anyway, I think the FOOS version is much more readable - but that's just me ;-)

 Note FOOS has "super" constructs - I wonder if this solution (secretly calling "Init") does the same (recursive) thing. Anyway, I don't think I have to be too ashamed for my OO solution.

I developed the entire program with PP4TH and yes, I was happy to see that it made development MUCH easier, because I didn't have to translate the .4PP code manually. What shocked me is that I was so "into the program" I had completely lost track what code was actually generated - so I was kind in for a shock when I first saw it decompiled. Good thing. That's the kind of abstraction that you really want.

As usual, code in SVN, but I'll copy the darn thing here as well.

Hans Bezemer

\ FOOS translation of "An Assembly Programer's Approach to Object-oriented Forth"
\ by Andras Zsoter, Department of Chemistry, The University of Hong Kong
\ See: http://forth.org/literature/andras.html

include lib/gcdlcd.4th
include 4pp/lib/foos.4pp

:: Numbers                             \ create an interface
   class
     virtual: Add ( Number -- )
     virtual: Sub ( Number -- )
     virtual: Mul ( Number -- )
     virtual: Div ( Number -- )
     virtual: Print
   end-class {}
;

:: Integers
   extends Numbers
     field: n                          \ store number here
   end-extends {

     this -> n !                       \ constructor

     :virtual add   { -> n @ this -> n +! }                   ;method
     :virtual sub   { -> n @ negate this -> n +! }            ;method
     :virtual mul   { -> n @ this -> n @ * this -> n ! }      ;method
     :virtual div   { -> n @ this -> n @ swap / this -> n ! } ;method
     :virtual print { this -> n ? }                           ;method
                                       \ make methods and fields private
     private{ n }
   }
;

:: Rationals
   extends Numbers
     field: num                        \ numerator
     field: den                        \ denominator
     method: (add)                     ( num den -- )           ( A "factor" of Add )
     method: Normalize                 ( --)
     virtual: inv
   end-extends {

     :method Normalize {
        this -> den @ this -> num @    ( get denominator and numerator. )
        2dup xor -rot                  ( a not quite ansi way to determine the sign. )
        abs swap abs                   ( calculate the absolute value of both. )
        2dup gcd                       ( calculate the gcd. )
        tuck / this -> den ! /         ( normalize the denominator and numerator )
        swap 0< if negate then         ( adjust the sign. )
        this -> num !
     } ;method

     :method (Add) {                   ( This is not the best way to add two rational numbers)
        dup this -> num @ * this -> num !
        this -> den @ tuck * this -> den !
        * this -> num +! this -> Normalize
     } ;method                         ( num*DEN+NUM*den => NUM )

     :virtual print { this -> num @ 0 .r ." /" this -> den ? } ;method
     :virtual add   { dup -> num @ swap -> den @ this -> (Add) } ;method
     :virtual sub   { dup -> num @ negate swap -> den @ this -> (Add) } ;method

     :virtual inv {
        this -> num @ this -> den @ this -> num ! this -> den ! this -> Normalize
     } ;method

     :virtual mul {
        dup -> num @ swap -> den @     ( Get the values of the other Rational. )
        this -> den @ * this -> den !  ( Multiply denominator by the other's denominator.)
        this -> num @ * this -> num !  ( Multiply numerator by the other's numerator.)
        this -> Normalize
     } ;method

     :virtual div {
        dup -> num @ swap -> den @     ( Get the values of the other Rational. )
        this -> num @ * swap           ( Multiply numerator by the other's denominator.)
        this -> den @ * this -> den !  ( Multiply denominator by the other's numerator.)
        this -> num ! this -> Normalize
     } ;method

     this -> den !
     this -> num ! this -> Normalize
                                       \ make methods and fields private
     private{ (Add) Normalize num den }
  }
;

: %. ( Number -- ) => Print ;
: %+ ( Number1 Number2 -- Number1+Number2 ) OVER => Add ;
: %- ( Number1 Number2 -- Number1-Number2 ) OVER => Sub ;
: %* ( Number1 Number2 -- Number1*Number2 ) OVER => Mul ;
: %/ ( Number1 Number2 -- Number1/Number2 ) OVER => Div ;

  4 16  static Rationals r1
-50 100 static Rationals r2

r1 r2 %/ %. cr

10 static Integers i1
 5 static Integers i2

i1 i2  %/ %. cr

-50 100 static Rationals r3
r3 => Inv r3 => print cr

Reply all
Reply to author
Forward
0 new messages