It’s time to update the subject line

Visto 11 veces
Saltar al primer mensaje no leído

John Peters

no leída,
9 may 2021, 10:23:389/5/21
a 4th-co...@googlegroups.com


John Alan Peters owner 
Brookline Electric
415-239-5393 TEXT/cell

On May 9, 2021, at 5:15 AM, The Beez <the.bee...@gmail.com> wrote:

Hi 4tH-ers!

There have been some subtle, but important changes to FOOS. First of all, ALL examples now have proper constructors and destructors. 

The Singleton example has been almost completely rewritten. The reason for that is that it resembled somewhat a singleton, but as a matter of fact - it wasn't.

The point is - in the examples on the Internet, the new instance is created by calling a function getInstance() and disabling the constructor. Implementing a Multiton design pattern brought me a bit closer - but not completely.

The point is - how do you disable the constructor? In FOOS it is done by the :NEW keyword, which points to a completely hidden field in the object. I can't disable that. It would have no effect. The point is, FOOS *DOES* have a constructor, which is identical to the class name. By making that one private you can issue "new Singleton", "instance Singleton" or "static Singleton" anymore - your only access is through the "getInstance" method.

Now, the instance has to be locked. In other languages, this is achieved by making a static property inside the class - which FOOS doesn't have. So, it has to be allocated outside - which is perfectly feasible. We can even make it private, so outside manipulation doesn't work. By initializing it to (ERROR) we have a perfect way of probing it - through ERROR?

All of that HAS a consequence. Most singletons are created statically - which we made (almost) completely impossible. So - your best way is to make a dynamically created singleton - which is a minor price to pay. But now we're only allowed to call it by "lazy evaluation" (see: https://en.wikipedia.org/wiki/Lazy_initialization). Most languages use the "class name" for that - but we can't because it's also the name for the constructor (as we've seen before). For that, I created a dummy object (actually - just a constant) named "Nothing", which will allow you to do lazy initialization by serving as an object placeholder for calling static methods.

So, to make a long story short, combing all this allows you to create a singleton (or multiton) by using lazy initialization:

  Nothing -> getInstance to mySingleton

Subsequent calls to this method will give you the very same object over and over again, while other methods of creation are blocked. That's a Singleton pattern in my book. So, with all those tiny changes I think I achieved my goal. The FOOS keyword "single" is now superfluous and hence removed. If you ever used that one, take a look at the new implementation. It's in SVN.

Hans Bezemer

On Saturday, May 8, 2021 at 4:28:28 PM UTC+2 The Beez wrote:
Hi 4tH-ers!

So, all FOOS stuff has been uploaded. If you want a new manual which has been updated to accommodate these changes, you can get one here: https://thebeez.home.xs4all.nl/4tH/4tHmanual.pdf

Have phun!

Hans Bezemer
On Friday, May 7, 2021 at 10:19:37 AM UTC+2 The Beez wrote:
Hi 4tH-ers!

It's done! The fifth incarnation of FOOS is a fact. And I'm quite proud of myself, because this was a significant cleanup of the syntax:
  1. It now has proper constructors and destructors without any significant technical drawbacks;
  2. All those pesky curly braces have been removed (they're still there for special occasions, though - like exiting early, switching objects within a method or changing methods of existing instances);
  3. A discrepancy in KINDOF has been fixed - it just returns a type;
  4. Lists and hashmaps were replicated several times. They're now a new kind of library - an class library;
  5. Use of the indispensible Dynamic String library - which makes the code much cleaner and easier to use;
  6. All but one of the examples now have proper destructors - and it works beautifully.
I wouldn't say conversion was a walk in the park. I could be including the wrong FOOS library, the Dynamic String library posed its own challenges - and of course I could always forget a curly brace here and there.
Often the lists and hashmaps would contain objects, so I created a subclass that assumed there were objects stored there, which allowed for a special destructor that would delete them silently when the list itself was deleted.

I think the current incarnation can be compare favorably with other OO Forth frameworks in ease of use and legibility. Lemme know what YOU think!

\ Preprocessor FOOS visitor pattern demo - Copyright 2017, 2021 J.L. Bezemer
\ You can redistribute this file and/or modify it under
\ the terms of the GNU General Public License


include lib/memcell.4th
include lib/dstringt.4th

include 4pp/lib/foos.4pp
include 4pp/foos/list.4pp

:class CarElement
   extends Object
     virtual: Accepts
   end-extends
;class

:class CarElementVisitor
   extends Object
     virtual: visit
   end-extends
;class

:class Wheel
   extends CarElement
     field:  name
     method: getName
   end-extends

   :new this -> name dup ds.init ds.place ;method
   :method getName this -> name ds.count  ;method
   :virtual Accepts this swap => visit    ;method
   :delete this -> name ds.free           ;method
;class

:class Body
   extends CarElement
   end-extends

   :virtual Accepts this swap => visit ;method
;class

:class Engine
   extends CarElement
   end-extends

   :virtual Accepts this swap => visit ;method
;class

:class Car
   extends CarElement
     field: elements
   end-extends

   :new
     new ObjectList this -> elements !

     s" front left"  new Wheel this -> elements @ -> lpush
     s" front right" new Wheel this -> elements @ -> lpush
     s" back left"   new Wheel this -> elements @ -> lpush
     s" back right"  new Wheel this -> elements @ -> lpush

     new Body   this -> elements @ -> lpush
     new Engine this -> elements @ -> lpush
   ;method

   :delete this -> elements @ delete ;method

   :virtual Accepts
      this -> elements @ -> lsize 1- \ example lists these in reverse
      begin                          ( vis i)
        dup 0<
      except
        over over this -> elements @ -> lget swap => visit 1-
      repeat drop this over => visit delete
   ;method
;class

:class CarElementDoVisitor
   extends CarElementVisitor
   end-extends

   :virtual visit
      dup type@ case
        typeof Body   of ." Moving my body" drop endof
        typeof Car    of ." Starting my car" drop endof
        typeof Wheel  of ." Kicking my " -> getName type ."  wheel" endof
        typeof Engine of ." Starting my engine" drop endof
      endcase cr
   ;method
;class

:class CarElementPrntVisitor
   extends CarElementVisitor
   end-extends

   :virtual visit
      dup type@ case
        typeof Body   of ." Visiting body" drop endof
        typeof Car    of ." Visiting car" drop endof
        typeof Wheel  of ." Visiting " -> getName type ."  wheel" endof
        typeof Engine of ." Visiting engine" drop endof
      endcase cr
   ;method
;class

instance Car myCar
new CarElementPrntVisitor myCar => Accepts cr
new CarElementDoVisitor myCar => Accepts

mycar delete

Hans Bezemer
On Monday, May 3, 2021 at 6:38:13 PM UTC+2 The Beez wrote:
Hi 4tH-ers!

When looking at the code yesterday, I found out that curled braces are almost everywhere. So I thought, why not kill these pesky things. And that experiment worked out just fine. Even the :NEW problem of the previous FOOS version was solved this way. 

Drawback: don't exit methods prematurely using ?EXIT, EXIT or ;THEN. If you know what you're doing, you can get away with it using "}" (yes, it's still there), but you make your life a little more difficult that way. BTW, previous versions have had the same drawback, so not much is lost. The advantage is a MUCH cleaner and more Forth-like syntax:

\ Preprocessor FOOS command pattern demo - Copyright 2017, 2021 J.L. Bezemer
\ You can redistribute this file and/or modify it under
\ the terms of the GNU General Public License

include foos.4pp

\ The Command interface
:class Command
   extends Object
     virtual: MakeItSo
   end-extends
;class

\ The Invoker class
:class Switch                          ( cmd --)
   extends Object
     virtual: DoIt
   end-extends

   :virtual DoIt => MakeItSo ;method
;class

\ The Receiver class
:class Light
   extends Object
     virtual: turnOn
     virtual: turnOff
   end-extends

   :virtual turnOn  ." The light is on"  cr ;method
   :virtual turnOff ." The light is off" cr ;method
;class

\ The Command for turning on the light - ConcreteCommand #1
:class FlipUpCommand                   ( light --)
   extends Command
     field: theLight
   end-extends

   :new this -> theLight ! ;method
   :virtual MakeItSo this -> theLight @ => turnOn ;method

   private{ theLight }
;class

\ The Command for turning off the light - ConcreteCommand #2
:class FlipDownCommand                 ( light --)
   extends Command
     field: theLight
   end-extends

   :new this -> theLight ! ;method
   :virtual MakeItSo this -> theLight @ => turnOff ;method

   private{ theLight }
;class

static Light lamp
lamp static FlipUpCommand switchUp
lamp static FlipDownCommand switchDown
static Switch mySwitch

switchUp   mySwitch => DoIt
switchDown mySwitch => DoIt
switchUp   mySwitch => DoIt

I've converted all programs I converted yesterday and it's pretty painless. Lemme know what you think.

Hans Bezemer
On Sunday, May 2, 2021 at 4:38:53 PM UTC+2 The Beez wrote:
Hi 4tH-ers!

You haven't heard from me for along time, so let me explain what I've been doing alls this time.

You know I have been working for a LONG time on a humble Banana Pi M3. September last year I've gotten my brand new machine. In the old times I would have installed it up to the point where I essentially got most of my old machine back.

Unfortunately, that goes with a lot of stress, so I rarely expose myself to that. My work is stressing enough and I need my time to recuperate. I'll be 61 this year, in a few years 4tH will hit its 30th anniversary, so you can imagine I'm not the young god I used to be.

That means, most time I do during vacations, when I'm well rested and have few things that require my attention. I got my machine with Ubuntu 20.04 preinstalled, so my first attention was to restore the functionality of the Banana - since that is the setup I need for work. Which is particularly important in these times.

I wanted to restore my files from the 12 years old disks from my old machine. They're nicely located in a few USB enclosures, but 12 years - you never know what happens when you expose them to a long and intense workload. So I put that off.

The Xmas vacation I spend on restoring the monitoring capacity of my Raspi Pi B, which involved hooking it up to my old VGA monitor.

This vacation I've spend on restoring over a MILLION files of my old machine. I already got a few X-compilers working as well. My old development environment for packaging is restored as well. Yesterday I spend a whole day on configuring my old account. 

Since it is stored on a different, unpartitioned disk, I had some(!) trouble with getting SNAP packages to work. They don't work over a symbolic link, so I had to remount the disk under /home/users. Then I had to add the directory under /etc/apparmor.d/tunables/home.

Finally, finally it worked. Except for the keyboard in graphical apps. This was due to an ibus conflict, which had to be fixed by setting it to a different value in the MATE control center. I was exhausted after that, I must admit. In the end, it seems so simple and if I'd had that solution, it would have been fixed in 15 mins.

Next, I've tackled a thing in FOOS. The constructor was defined in a much different way from all other methods and that didn't do. So, I've defined a :NEW method. It is defined much like the :DELETE method, but uses a completely different technique. Note you can STILL use the "old" method as well.

The only restriction is that IF you use the new method, you MUST use curly braces. Other methods allow you to handle the object address yourself, but I must admit, I hardly ever do, so I can safely assume others won't as well. It takes away the abstraction and is a lot of hassle.

It requires some more testing, but I'm pretty confident it works just fine. Your class definitions get a lot less quirky look:

:class CarBuilder
   extends ICarBuilder
     field: _Car_
   end-extends {

     :new { new Car this -> _Car_ ! } ;method
     :virtual SetColor  { this -> _Car_ @ => Color!  } ;method
     :virtual SetWheels { this -> _Car_ @ => Wheels! } ;method
     :virtual Result@ { this -> _Car_ @ } ;method
     :delete { this -> _Car_ @ delete } ;method
   }

   private{ _Car_ }
;class

It works like replicating the address on the returnstack, so the braces can do their job. Of course, it requires an extra address on the stack, but if you're this much stack space, I guess you're in trouble already.

You may also note I've added a few odd routines. I did a 64 bit version of KISS, since otherwise you wouldn't have a high performance randomizer on you 64 bit machine.

Second, I've written a few routines I need to implement a lean version of ZIP. Without that one, formats like .XLSX are impossible, since these require ZIP. I can only tell you that the one posted on a Forth site won't do. These produce files which are so mangled that most ZIPers barf them out - so I gotta do this myself. I don't expect to include these in the current version, it's just a new project.

Having back my staging area means I can now start releasing stuff. Like I said before, it won't be all platforms at once. It'll be a few major ones and them some added bit by bit.

So, now you know where I'm at. Comments welcome.

Hans Bezemer

--
You received this message because you are subscribed to the Google Groups "4tH-compiler" group.
To unsubscribe from this group and stop receiving emails from it, send an email to 4th-compiler...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/4th-compiler/bb0415fd-35eb-40ea-82a8-92292a1be59dn%40googlegroups.com.

dudley ackerman

no leída,
9 may 2021, 21:26:239/5/21
a 4th-co...@googlegroups.com
i don’t catch your meaning. subject line of beez’s emails?


The Beez

no leída,
10 may 2021, 2:59:1510/5/21
a 4tH-compiler
.. and he's right. It's no longer "hi, I'm back - did you miss me?" but lots of OO stuff. 

BTW, talking of FOOS, yesterday I has another look at FOOSTATE.4PP and found the "fix" quite ugly. Well, it took a different expansion of "NEW" to fix it, but I think I now got a good syntax for deferred classes:

"class <myclass>" makes a forward declaration of a class, while "resolve <myclass> <actual implementation" is the "IS" equivalent. I was so happy with this solution I added it to FOOS. Another thing was "lazy initialization", which requires the class name doubling for an object while invoking static methods. Well, we can't have that for technical reasons - but "NOTHING" is a word that can be used in its  place consistently, so that one was adopted.

We're now AT LEAST as good as the famous NEON/YERK ( https://www.bradrodriguez.com/papers/oofs.htm ). There is not much information on that one ( https://www.complang.tuwien.ac.at/forth/objects/opinion.html ) and the table in the Rodriguez papers lacks definitions, but I doubt it had full destructors. I'm also happy that - contrary to NEON/YERK - FOOS has the "message object" format we're so familiar with.

And yes, OO is known to cause overhead, but I think FOOS overhead is acceptable, due to the preprocessor solution. You don't have to link in libraries or call them during runtime. Note some OOF solutions have to *SEARCH* for their selectors using a "linked list".

The only thing I'd rather see disappear is the difference between invoking virtual or static methods - but since Forth isn't typed I don't see this happen any time soon.

Well, that's how *I* am seeing things. Lemme know what YOU think.

Hans Bezemer

The Beez

no leída,
11 may 2021, 7:02:0911/5/21
a 4tH-compiler
Hi 4tH-ers!

Well, it doesn't quite leave me alone. Due to the implementation of the formal "FORWARD" functionality for classes, I was forced to change the code generation for the (~~NEW) internal. First, it took the execution token of the constructor and the size of an object, passed that to (~~NEW), which returned your initialized object - and that was it. Drawback - that won't work with forward classed when you have a DEFERRED word.

So I changed (~~NEW) a bit, so it simply took ONLY the size of the object and returned TWO addresses of an uninitialized object. Then one of 'em got on the return stack (we may have initializations, so NO CLUTTER on the datastack), it ran the constructor and returned the address of the now initialized object on the data stack. That's two instructions more per "NEW" call.

To offset that a very little bit, I added an optimizer to 4tH, which replaces ">R RDROP" calls by "DROP". Not much, one instruction per interface, but it counts ;-)

And more: we got a very nice example of a dependency injector pattern. Something strange happened here. It's a conversion of some C# code and I had at first some trouble understanding it - where do all the bits go and have I got everything covered?

I was not exactly sure HOW it worked, but I decided to recode it in FOOS - but when I was at the end, I found out I knew EXACTLY how it was working. It worked first time! And I had no trouble adding all these thingies like changing some parameters - which was not covered in the original source - or to add all destructor stuff (which also worked first time).

May it be that FOOS code is more accessible? Or was it just the act of transcribing the stuff? I dunno - may be you have an idea.

Code in SVN, r1295.

Hans Bezemer

Responder a todos
Responder al autor
Reenviar
0 mensajes nuevos