Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

OBJECTS.FS Question

5 views
Skip to first unread message

Doug Hoffman

unread,
Mar 26, 2008, 9:00:22 PM3/26/08
to
I am having a problem running Anton's OBJECTS.FS extensions. Likely I'm
doing something simple wrong and hopefully someone can see my error. I
am running the ANS compatible version of OBJECTS.FS on Carbon MacForth.
The objects.fs file loads just fine and I am able to run the example
code snippets just fine as well. For example:

interface
selector val
selector inc
end-interface foo

object class
foo implementation
cell% inst-var n
m: ( object -- )
0 n ! ;m
overrides construct
m: ( object -- )
n @ ;m
method val
m: ( object -- )
1 n +! ;m
method inc
end-class counter

interface
selector add
end-interface foobar

counter class
foobar implementation
m: ( n object -- )
0 do
this inc
loop
;m overrides add
end-class xcounter


xcounter dict-new constant x

x val .
0 ok
x inc x val .
1 ok

As you can see from the above everything is running just fine at this
point. Note that I instantiated the xcounter object named x in the
dictionary, I think.

If I then make a snapshot image of my Forth system and re-launch that I
am unable to get my object x to do anything. Something like 'x val .'
leaves two large numbers on the stack (they look like addresses). Same
for 'x inc' and so on. Worse, I cannot even reload the above code
starting with 'interface selector val ...'. I get compilation errors
that appear related to the vocabulary system. The only way I can get
the object system to work again is to reload everything from the very
beginning. Any ideas?

TIA

-Doug

Anton Ertl

unread,
Mar 27, 2008, 5:36:02 PM3/27/08
to
Doug Hoffman <no.spam> writes:
>If I then make a snapshot image of my Forth system and re-launch that I
>am unable to get my object x to do anything.

Most Forth systems don't save ALLOCATEd memory when you make an image,
so when you use an image, any ALLOCATEd data is gone. objects.fs uses
ALLOCATE and RESIZE to store some of the data on classes, and that
would then be lost. I guess that's the problem you see.

> Worse, I cannot even reload the above code
>starting with 'interface selector val ...'.

There is already something stored in ALLOCATEd memory when you include
objects.fs (in particular, parts of the definition of the OBJECT
class).

Should we change the Forth systems to also save ALLOCATEd memory,
should we change applications and libraries to avoid ALLOCATEd memory,
or should we just be happy with loading applications from the start on
every startup (and make the systems compile fast enough)?

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2008: http://www.complang.tuwien.ac.at/anton/euroforth/ef08.html

Bruce McFarling

unread,
Mar 27, 2008, 9:33:47 PM3/27/08
to
On Mar 27, 5:36 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
wrote:

> Should we change the Forth systems to also save ALLOCATEd memory,
> should we change applications and libraries to avoid ALLOCATEd memory,
> or should we just be happy with loading applications from the start on
> every startup (and make the systems compile fast enough)?

??? AFAICT, the answer to the question is "No".

Applications and libraries that use ALLOCATEd memory that are, like
OBJECTS.FS, designed to provide fundamental semantics that one would
wish to have in a system that has been saved and reloaded, should
provide a means to serialize any information required from memory that
they have ALLOCATEd so that they are able to restore it from its
serialized form.

IOW, the answer is option four, applications and libraries that use
ALLOCATEd memory should provide the capability to save and restore it
to users and applications that may wish or need to do so.

Doug Hoffman

unread,
Mar 27, 2008, 10:27:11 PM3/27/08
to
Anton Ertl wrote:
> Doug Hoffman <no.spam> writes:
>> If I then make a snapshot image of my Forth system and re-launch that I
>> am unable to get my object x to do anything.

> objects.fs uses
> ALLOCATE and RESIZE to store some of the data on classes, and that
> would then be lost. I guess that's the problem you see.

That's a significant problem to deal with. A problem that the Neon-like
model doesn't suffer. It would have been a more balanced paper had you
brought these facts out in your "Yet another Forth objects package"
http://www.complang.tuwien.ac.at/forth/objects/objects.html especially
since your prior paper was unduly and inaccurately critical of the
Neon-like model (that paper was titled "On Standardizing Object-Oriented
Forth Extensions" but in reality was a rant of Andrew McKewan's work on
the Neon-like model for Forth. For other readers, see
http://www.complang.tuwien.ac.at/forth/objects-standard.html ).

In the "Standardizing" paper there was quite a bit that I didn't follow.
For example, you make an issue of McKewan's use of state smart words.
Why not just point out that the Neon model is easily written without
them? Took me less than 5 minutes to do so.

You make issue of the relative speeds of late binding, calling McKewan's
"inefficient" just because it is a bit slower than a vtable. In an
Olympic sprinting race, would we call the silver medalist slow?
Actually, I was able to speed up McKewans late binding code. It uses an
8-way linked list (instead of a single-way) but he was waiting to
compute the 8-way until run time. This calculation can be done at
compile time and speeds things up noticeably. I have done so. A linked
list search is still very fast. It can be made faster yet by writing
the routine in assembler. It's a simple routine. I don't like
assembler but even I was able to easily write that.

A serious flaw with Objects.fs is the use of late binding when the class
of the object is known at compile time. Like SWOOP, the Neon-like model
defaults to the extremely fast early binding in those cases. That's why
the Neon-like model typically outperforms Objects.fs in real world code.
It is also why, IMO, one sees more method factoring in class
definitions using the Neon or SWOOP early binding default.

The ancient debate of the ordering of object and message seems to me
irrelevant and a bit silly to obsess over. For one thing the Neon model
can *easily* do it either way. As far as the ordering being natural or
Forthlike or non-Forthlike: We seem to get along just fine with the
locals syntax ( parameter-message-object ). Forthers will similarly
have no problems at all doing the same for objects.


>> Worse, I cannot even reload the above code
>> starting with 'interface selector val ...'.
>
> There is already something stored in ALLOCATEd memory when you include
> objects.fs (in particular, parts of the definition of the OBJECT
> class).
>
> Should we change the Forth systems to also save ALLOCATEd memory,
> should we change applications and libraries to avoid ALLOCATEd memory,
> or should we just be happy with loading applications from the start on
> every startup (and make the systems compile fast enough)?

Neither. We could use a different Forth OOP extension that doesn't
suffer this serious problem.

-Doug


>
> - anton

Albert van der Horst

unread,
Mar 28, 2008, 5:00:39 AM3/28/08
to
In article <2008Mar2...@mips.complang.tuwien.ac.at>,

Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>Doug Hoffman <no.spam> writes:
>>If I then make a snapshot image of my Forth system and re-launch that I
>>am unable to get my object x to do anything.
>
>Most Forth systems don't save ALLOCATEd memory when you make an image,
>so when you use an image, any ALLOCATEd data is gone. objects.fs uses
>ALLOCATE and RESIZE to store some of the data on classes, and that
>would then be lost. I guess that's the problem you see.
>
>> Worse, I cannot even reload the above code
>>starting with 'interface selector val ...'.
>
>There is already something stored in ALLOCATEd memory when you include
>objects.fs (in particular, parts of the definition of the OBJECT
>class).
>
>Should we change the Forth systems to also save ALLOCATEd memory,
>should we change applications and libraries to avoid ALLOCATEd memory,
>or should we just be happy with loading applications from the start on
>every startup (and make the systems compile fast enough)?

I think we should forego up front ALLOCATE-ing in library modules.
As far as an application is concerned, I think it is sufficient
that it is known that you can't SAVE-SYSTEM ALLOCATE d memory.
There is always an other solution. In particular I think that
it makes more sense to ALLOT initialised data.
(My 2 ct).


--
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- like all pyramid schemes -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

Anton Ertl

unread,
Mar 28, 2008, 4:48:24 PM3/28/08
to
Bruce McFarling <agi...@netscape.net> writes:
>On Mar 27, 5:36 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
>wrote:
>> Should we change the Forth systems to also save ALLOCATEd memory,
>> should we change applications and libraries to avoid ALLOCATEd memory,
>> or should we just be happy with loading applications from the start on
>> every startup (and make the systems compile fast enough)?
>
>??? AFAICT, the answer to the question is "No".

I have thought about it some more, and my answer is:

- If a Forth implementor thinks that making an image is an important
feature (e.g., because they want to facilitate distributing
applications in non-source form, or because they have a slow
compiler), then he should implement image-making for all of the
supported Forth features; i.e., if the Forth system claims to
support the Memory Allocation wordset, it should also keep ALLOCATEd
memory across image saving and restoring.

- If, OTOH, making an image is not an important feature of a Forth
system, then it can be as limited as the implementor wants; if some
user then wants full-featured image-making for some reason, they
should look for a different system that has better support for
image-making.

In any case, there is no reason to make the Memory Allocation wordset
a second-class citizen for programs.

>IOW, the answer is option four, applications and libraries that use
>ALLOCATEd memory should provide the capability to save and restore it
>to users and applications that may wish or need to do so.

That might be a favour that a programmer might do for users of his
software, so they can run the software on deficient systems, just like
he might work to eliminate the Memory Allocation wordset completely
for systems that don't support it.

However, in the present case (objects.fs), no user has asked for that
favour since objects.fs exists (since 1996), and it seems to me that
Doug Hoffman is not interested in using objects.fs seriously, he is
only complaining about this "serious problem"
<1d11d$47ec577e$cdd085fc$38...@DIALUPUSA.NET> to win some points for
his favourite OO extension. Wouldn't it be unfair to deprive him of
that opportunity?

Bruce McFarling

unread,
Mar 29, 2008, 1:24:06 AM3/29/08
to
On Mar 28, 4:48 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
wrote:

> In any case, there is no reason to make the Memory Allocation wordset


> a second-class citizen for programs.

Dynamically allocated memory is ... uhm, dynamically allocated?

I don't see how its unusual for statically allocated memory to be
loaded from an image and dynamically allocated memory to be created by
an initialization process.

I would, indeed, be surprised if the existing practice that was
standardized in ALLOCATE provided any such entitlement to support
libraries for applications that the memory allocation wordset would
infer which allocated memory would managed by the initializing routine
when starting a system image and which allocated memory would require
auto-initialization.

However, what I expect from a SAVESYSTEM is to get my codespace and
ALLOTted dataspace back as it was when SAVESYSTEM executed, and to
have a hook into the initialization routine that runs when the image
is reloaded.

Indeed, Camel for Z80 and CP/M only have the hook for the
initialization routine and the ability to report the parameter to hand
to the CP/M SAVE command. So there, the argument that SAVESYSTEM
should automagically infer which allocated memory requires system
support for the initialization capabilities omitted from the creating
application is not an argument with the Brad Rodriguez, but an
argument with Gary Kildall.

> However, in the present case (objects.fs), no user has asked for that
> favour since objects.fs exists (since 1996), and it seems to me that
> Doug Hoffman is not interested in using objects.fs seriously, he is
> only complaining about this "serious problem"

The validity of Doug Hoffman's argument on this point is independent
of the broader argument in which it is couched and, indeed, of whether
or not he makes it because he is seriously interested in using
object.fs.

Marcel Hendrix

unread,
Mar 29, 2008, 1:01:59 AM3/29/08
to
Bruce McFarling <agi...@netscape.net> writes Re: Images and libraries (was: OBJECTS.FS Question)
[..]

> However, what I expect from a SAVESYSTEM is to get my codespace and
> ALLOTted dataspace back as it was when SAVESYSTEM executed, and to
> have a hook into the initialization routine that runs when the image
> is reloaded.

I don't see a reason for a hook. Most of the SAVE-SYSTEMs I am familiar
with work with a boot vector to put the xt of a startup word in.

So provision for persistent objects is possible under program control --
no system extensions are needed.

-marcel

Andrew Haley

unread,
Mar 29, 2008, 6:29:43 AM3/29/08
to
Bruce McFarling <agi...@netscape.net> wrote:
> On Mar 28, 4:48 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
> wrote:

>> In any case, there is no reason to make the Memory Allocation wordset
>> a second-class citizen for programs.

> Dynamically allocated memory is ... uhm, dynamically allocated?

> I don't see how its unusual for statically allocated memory to be
> loaded from an image and dynamically allocated memory to be created
> by an initialization process.

> I would, indeed, be surprised if the existing practice that was
> standardized in ALLOCATE provided any such entitlement to support
> libraries for applications that the memory allocation wordset would
> infer which allocated memory would managed by the initializing
> routine when starting a system image and which allocated memory
> would require auto-initialization.

> However, what I expect from a SAVESYSTEM is to get my codespace and
> ALLOTted dataspace back as it was when SAVESYSTEM executed, and to
> have a hook into the initialization routine that runs when the image
> is reloaded.

That sounds right to me too. When calling an OS to get memory you
sometimes have no way to control where that memory is. In UNIX you
might be able to cope by allocating all memory via sbrk(), so all
dynamic meory is contiguous. In general, however, a requirement that
SAVESYSTEM save all dynamic memory places a great burden on the way
that ALLOCATE is implemented.

Andrew.

Doug Hoffman

unread,
Mar 29, 2008, 7:05:58 AM3/29/08
to
Anton Ertl wrote:
> Bruce McFarling <agi...@netscape.net> writes:
>> On Mar 27, 5:36 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
>> wrote:
>>> Should we change the Forth systems to also save ALLOCATEd memory,
>>> should we change applications and libraries to avoid ALLOCATEd memory,
>>> or should we just be happy with loading applications from the start on
>>> every startup (and make the systems compile fast enough)?
>> ??? AFAICT, the answer to the question is "No".
>
> I have thought about it some more, and my answer is:
>
> - If a Forth implementor thinks that making an image is an important
> feature (e.g., because they want to facilitate distributing
> applications in non-source form, or because they have a slow
> compiler), then he should implement image-making for all of the
> supported Forth features; i.e., if the Forth system claims to
> support the Memory Allocation wordset, it should also keep ALLOCATEd
> memory across image saving and restoring.

I agree with Albert, Bruce, Andrew, and suspect most others that this
would not be desirable.

> - If, OTOH, making an image is not an important feature of a Forth
> system, then it can be as limited as the implementor wants; if some
> user then wants full-featured image-making for some reason, they
> should look for a different system that has better support for
> image-making.
> In any case, there is no reason to make the Memory Allocation wordset
> a second-class citizen for programs.

I don't see where anyone has suggested that. Certainly not me.

>> IOW, the answer is option four, applications and libraries that use
>> ALLOCATEd memory should provide the capability to save and restore it
>> to users and applications that may wish or need to do so.

Agreed.


> However, in the present case (objects.fs), no user has asked for that
> favour since objects.fs exists (since 1996),

My guess is that no one is using it to create applications. One reason
for this would be the problem of getting objects.fs to run in a
non-source, or turnkey, application.


> and it seems to me that
> Doug Hoffman is not interested in using objects.fs seriously,

My interest is in increasing my knowledge about the different OOP models
available for Forth. I am also studying Bernd's OOF, Forth Inc.'s
SWOOP, and Win32Forth's dialect of Neon. This is a serious study, at
least it is to me. Did I ever intend to make a turnkey application with
objects.fs? That was going to depend on the outcome of my study. At
this point I would say no.

> he is
> only complaining about this "serious problem"
> <1d11d$47ec577e$cdd085fc$38...@DIALUPUSA.NET> to win some points for
> his favourite OO extension.

I am stating the facts as I know them. The Neon model does not rely on
ALLOCATEd memory to be saved or restored. Object.fs does. If this is
incorrect please tell me where.

-Doug

Bruce McFarling

unread,
Mar 29, 2008, 11:51:33 AM3/29/08
to
On Mar 29, 1:01 am, m...@iae.nl (Marcel Hendrix) wrote:
> I don't see a reason for a hook. Most of the SAVE-SYSTEMs I am familiar
> with work with a boot vector to put the xt of a startup word in.

You see no reason for a hook, because most of the SAVE-SYSTEMs you
are familiar with work with a hook?

I'm getting a parse error here. I don't see how those systems work
without that boot vector.

Bruce McFarling

unread,
Mar 29, 2008, 11:57:52 AM3/29/08
to
On Mar 29, 7:05 am, Doug Hoffman <no.spam> wrote:
> My interest is in increasing my knowledge about the different OOP models
> available for Forth. I am also studying Bernd's OOF, Forth Inc.'s
> SWOOP, and Win32Forth's dialect of Neon. This is a serious study, at
> least it is to me. Did I ever intend to make a turnkey application with
> objects.fs? That was going to depend on the outcome of my study. At
> this point I would say no.

I am using Mini-OOF in Nicl, since my target is to span across from
smallish free-standing systems to the systems sitting in a modern
desktop OS.

So for me, OOF would probably be the most natural step up if anything
more than Mini-OOF is needed, e.g., for white box OOP (what I am
attempting now is all black-box, and Mini-OOF is sufficient).

Does it have this problem with savesystem? Obviously working
effectively with savesystem is important for my context.

Elizabeth D Rather

unread,
Mar 29, 2008, 12:54:53 PM3/29/08
to
Doug Hoffman wrote:
> Anton Ertl wrote:
>> Bruce McFarling <agi...@netscape.net> writes:
>>> On Mar 27, 5:36 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
>>> wrote:
>>>> Should we change the Forth systems to also save ALLOCATEd memory,
>>>> should we change applications and libraries to avoid ALLOCATEd memory,
>>>> or should we just be happy with loading applications from the start on
>>>> every startup (and make the systems compile fast enough)?
>>> ??? AFAICT, the answer to the question is "No".
>>
>> I have thought about it some more, and my answer is:
>>
>> - If a Forth implementor thinks that making an image is an important
>> feature (e.g., because they want to facilitate distributing
>> applications in non-source form, or because they have a slow
>> compiler), then he should implement image-making for all of the
>> supported Forth features; i.e., if the Forth system claims to
>> support the Memory Allocation wordset, it should also keep ALLOCATEd
>> memory across image saving and restoring.
>
> I agree with Albert, Bruce, Andrew, and suspect most others that this
> would not be desirable.

Let me chime in to add my agreement. The whole purpose of ALLOCATE is
for *dynamic* memory allocation. If you want something that will
survive image saving and restoring, that's properly speaking a *static*
allocation, and should be recognized as such.

Cheers,
Elizabeth

--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310-491-3356
5155 W. Rosecrans Ave. #1018 Fax: +1 310-978-9454
Hawthorne, CA 90250
http://www.forth.com

"Forth-based products and Services for real-time
applications since 1973."
==================================================

Albert van der Horst

unread,
Mar 29, 2008, 1:28:00 PM3/29/08
to

It depends. I can understand Anton Ertl's argument. You want
SAVE-SYSTEM to save a snapshot of the system and be done with it.
If your system understands ALLOCATE, the allocated memory should
be transparently in the snapshot.

Mostly I use SAVE-SYSTEM via
lina -c ape.frt
In this case I may take measures to prevent static 1 Megabyte
arrays in the resulting ape (ape.exe for MS fans) even if I have
to write a special initialisation. Then the mindset is compiling
a program, not taking a snapshot.

>-marcel

Groetjes Albert

Bruce McFarling

unread,
Mar 29, 2008, 1:57:17 PM3/29/08
to
On Mar 29, 1:28 pm, Albert van der Horst <alb...@spenarnc.xs4all.nl>
wrote:

> It depends. I can understand Anton Ertl's argument. You want
> SAVE-SYSTEM to save a snapshot of the system and be done with it.
> If your system understands ALLOCATE, the allocated memory should
> be transparently in the snapshot.

Does Anton want SAVE-SYSTEM at all?

I get the impression from the scolding tone of what implementers
should do who dare to provide a SAVE-SYSTEM facility for their users
that he would be perfectly happy if nobody was ever provided with a
SAVE-SYSTEM facility.

Bruce McFarling

unread,
Mar 29, 2008, 2:07:13 PM3/29/08
to
On Mar 29, 1:01 am, m...@iae.nl (Marcel Hendrix) wrote:
> Bruce McFarling <agil...@netscape.net> writes Re: Images and libraries (was: OBJECTS.FS Question)

Oh! ... you are reading that like an implementer, as a request to
implement something. I'm writing it like a user, as a request to have
something available, by one means or another.

Yes, normally the hook is "already there" by the time SAVE-SYSTEM
appears in the source of the implementation ... unless the SAVE-SYSTEM
is patched in to a system implemented by someone else, the simplest
way to provide it is to build it in at the ground floor.

SAVE-SYSTEM has to *have* that hook available to the user, it doesn't
have to *add* that hook if the hook already exists.

Doug Hoffman

unread,
Mar 29, 2008, 6:20:50 PM3/29/08
to
Bruce McFarling wrote:

-snip-

> So for me, OOF would probably be the most natural step up if anything
> more than Mini-OOF is needed,

-snip-

> Does it have this problem with savesystem? Obviously working
> effectively with savesystem is important for my context.

I just now tried doing a "savesytem" (snapshot in Carbon MacForth
parlance) with OOF. Unfortunately I then had the same problems as with
Objects.fs. What I don't know, either for OOF or Objects.fs, is the
degree of difficulty in modifying the code to allot rather than allocate
the required memory. Or perhaps (hopefully) it would not be difficult
to write out to a file the memory state and read it back in
automatically upon a restart. Bernd could best answer those questions
for OOF.

I like what I see in OOF in terms of syntax and readability. It uses
the more readable, to me, convention of placing the names of new
definitions at the *beginning* of the definition instead of at the end
(classes and methods). OOF does not require the redundant declarations
of, for example, 'method' when it seems obvious that the code is a
method. Same for 'overrides' when it is obvious that the method is
overriding. OOF also looks to be a fairly complete implementation with
support for arrays. In these respects OOF looks to be similar to the
SWOOP and Neon-like models. But these are just first impressions
because I haven't finished looking at everything I plan to.

-Doug

Anton Ertl

unread,
Mar 30, 2008, 3:14:33 PM3/30/08
to
Bruce McFarling <agi...@netscape.net> writes:
>On Mar 28, 4:48 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
>wrote:
>
>> In any case, there is no reason to make the Memory Allocation wordset
>> a second-class citizen for programs.
>
>Dynamically allocated memory is ... uhm, dynamically allocated?

And? All memory that a Forth program allocates is allocated at
run-time (that's what's usually meant by "dynamically allocated"),
both ALLOTed memory and ALLOCATEd memory. Consider:

50 allocate throw constant buf1
here 50 allot constant buf2

Would you say that the memory for buf2, which was allocated later,
is less dynamic than the memory for buf1?

BTW, searching for "dynamic" in the standard document, I see only one
occurence of something like "dynamic allocation", in the definition of
WORDLIST; there is no occurence of "dynamic" in chapter 14 (on the
Memory Allocation wordset).

Anton Ertl

unread,
Mar 30, 2008, 3:23:04 PM3/30/08
to
Andrew Haley <andr...@littlepinkcloud.invalid> writes:
>When calling an OS to get memory you
>sometimes have no way to control where that memory is.

In that case you are out of luck with ALLOTed memory, too.

> In UNIX you
>might be able to cope by allocating all memory via sbrk(), so all
>dynamic meory is contiguous.

Actually, mmap() seems to be more promising, because you can ask
mmap() to give you a specific address (unlike sbrk()).

A relatively easy way would be to save all anonymously mapped areas, then
restore them to the same places.

>In general, however, a requirement that
>SAVESYSTEM save all dynamic memory places a great burden on the way
>that ALLOCATE is implemented.

I don't think it's a great burden. The way outlined above (based on
the mmaped areas) is completely independent of the implementation of
ALLOCATE (it's OS-dependent, though).

Even if we go into the internals of ALLOCATE, I don't see a burden on
the implementation of ALLOCATE: ALLOCATE has to keep track of what
memory areas it is managing, and which parts of these areas are free
anyway. That information is enough to save all the ALLOCATEd memory.

Admittedly, the implementation of snapshotting would become a bit more
complicated, but I think the cost is rather minor compared to the cost
of restricting the use of ALLOCATE in all programs. Even converting
one large program from using ALLOCATE to using second-class ALLOCATE
will cost more than fixing snapshotting to support first-class
ALLOCATE.

Anton Ertl

unread,
Mar 30, 2008, 3:40:00 PM3/30/08
to
Bruce McFarling <agi...@netscape.net> writes:
>Does Anton want SAVE-SYSTEM at all?

As a programmer, I don't care for SAVESYSTEM. I distribute my code in
source form.

As a user, I don't care for SAVESYSTEM: the Forth systems I use
compile fast enough that I don't need it.

As a programmer again, I don't brake for SAVESYSTEM. If a user cares
for SAVESYSTEM, they should ask their Forth system implementor to
provide a full-featured SAVESYSTEM instead of asking me to work around
deficient SAVESYSTEMs.

Bernd Paysan

unread,
Mar 30, 2008, 4:10:35 PM3/30/08
to
Doug Hoffman <no.spam> wrote:
> I just now tried doing a "savesytem" (snapshot in Carbon MacForth
> parlance) with OOF. Unfortunately I then had the same problems as with
> Objects.fs. What I don't know, either for OOF or Objects.fs, is the
> degree of difficulty in modifying the code to allot rather than allocate
> the required memory. Or perhaps (hopefully) it would not be difficult
> to write out to a file the memory state and read it back in
> automatically upon a restart. Bernd could best answer those questions
> for OOF.

OOF can be used in such a way that you can savesystem everything (the living
objects and the class metadata). There are two words, STATIC and DYNAMIC
(not in an OO context), which switch the allocator to ALLOT or ALLOCATE.

I usually keep the dynamic allocator when I SAVESYSTEM things, and make sure
I recreate the objects I need at startup.

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://www.jwdt.com/~paysan/

Bruce McFarling

unread,
Mar 30, 2008, 4:40:29 PM3/30/08
to
On Mar 30, 3:14 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
wrote:

> And? All memory that a Forth program allocates is allocated at
> run-time (that's what's usually meant by "dynamically allocated"),
> both ALLOTed memory and ALLOCATEd memory. Consider:

> 50 allocate throw constant buf1
> here 50 allot constant buf2

> Would you say that the memory for buf2, which was allocated later,
> is less dynamic than the memory for buf1?

Yes, of course, obviously.

The allocated memory for buf1 is designed to be freed at any later
time, while the only way to release buf2 is to release all ALLOTments
made following buf2.

Just because the above uses ALLOCATE to create a buffer that it never
intends to free doesn't free ALLOCATE from the responsibility of
handing over a buffer that can later be freed.\

Bernd Paysan

unread,
Mar 30, 2008, 5:23:34 PM3/30/08
to
Bernd Paysan wrote:
> OOF can be used in such a way that you can savesystem everything (the
> living objects and the class metadata). There are two words, STATIC and
> DYNAMIC (not in an OO context), which switch the allocator to ALLOT or
> ALLOCATE.

I should note that OOF has a method NEW for dynamic allocation (which can be
made static if you need), and a method : for static allocation (which
produces a named object). So if you do e.g.

gforthmi oof.fi oof.fs oofsampl.fs

to create a oof.fi image with the oofsampl.fs stuff compiled in, you can
restart it with

gforth -i oof.fi

but the dynamic part of the created objects will fail (i.e. then only the
interface test will work).

If you create the image with

gforthmi oof.fi oof.fs -e static oofsampl.fs

the array also works (arrays are normally dynamically allocated - but this
makes the array static). However, the string class defined in offsampl.fs
uses allocate and resize for the strings itself, and doesn't go to a static
version if STATIC is selected, so this part won't work. That's not the
fault of the OOF system ;-).

Note that you need gforthmi under most recent Linux versions, since the
randomized load address will spoil a simple SAVESYSTEM image.

Bruce McFarling

unread,
Mar 30, 2008, 5:58:43 PM3/30/08
to
On Mar 30, 3:40 pm, an...@mips.complang.tuwien.ac.at (Anton Ertl)
wrote:

> Bruce McFarling <agil...@netscape.net> writes:
> >Does Anton want SAVE-SYSTEM at all?

> As a programmer, I don't care for SAVESYSTEM. I distribute my code in
> source form.

> As a user, I don't care for SAVESYSTEM: the Forth systems I use
> compile fast enough that I don't need it.

This establishes a type of target programming environment.

> As a programmer again, I don't brake for SAVESYSTEM. If a user cares
> for SAVESYSTEM, they should ask their Forth system implementor to
> provide a full-featured SAVESYSTEM instead of asking me to work around
> deficient SAVESYSTEMs.

Braking for SAVESYSTEM is not at issue here.

A full-featured SAVESYSTEM, without feature bloat, has an opportunity
to establish the initialization routine. Any static entity that exists
when SAVESYSTEM executes is in the image, and any dynamic entity that
is desired at start can be created and initialized in the
initialization routine.

A library that does not aspire to be useful outside the above target
programming environment does not have to be compatible with re-
initializing dynamic structure that have already been defined.

A library that aspires to be useful outside the above target would
have that compatibility.

It seems that OBJECTS.FS is not, and OOF is, so for someone to build a
library, on top of an OOP library, that is intended to be SAVESYSTEM
compatible, OOF would be the clear choice.

Albert van der Horst

unread,
Mar 31, 2008, 3:43:03 AM3/31/08
to
In article <2008Mar3...@mips.complang.tuwien.ac.at>,

Anton Ertl <an...@mips.complang.tuwien.ac.at> wrote:
>Bruce McFarling <agi...@netscape.net> writes:
>>Does Anton want SAVE-SYSTEM at all?
>
>As a programmer, I don't care for SAVESYSTEM. I distribute my code in
>source form.
>
>As a user, I don't care for SAVESYSTEM: the Forth systems I use
>compile fast enough that I don't need it.

If we care for promoting Forth, we should try to make it easier to
use it. E.g. my flash programmer for one of Elektuurs single board
computer (8051 based) can be down loaded and run. Compare this to
having to load the programmer on a configured gForth system on
Windows. Oops. First have to install gForth first. This will
shrink the number of users by an order of magnitude.

If there are no useful programs, the language will be conceived
as not useful.

>- anton

Stephen Pelc

unread,
Mar 31, 2008, 9:15:43 AM3/31/08
to
On Sun, 30 Mar 2008 19:40:00 GMT, an...@mips.complang.tuwien.ac.at
(Anton Ertl) wrote:

>As a programmer, I don't care for SAVESYSTEM. I distribute my code in
>source form.
>
>As a user, I don't care for SAVESYSTEM: the Forth systems I use
>compile fast enough that I don't need it.
>
>As a programmer again, I don't brake for SAVESYSTEM. If a user cares
>for SAVESYSTEM, they should ask their Forth system implementor to
>provide a full-featured SAVESYSTEM instead of asking me to work around
>deficient SAVESYSTEMs.

You don't write applications.

Especially, you don't write large applications.

You don't write embedded applications.

Stephen


--
Stephen Pelc, steph...@mpeforth.com
MicroProcessor Engineering Ltd - More Real, Less Time
133 Hill Lane, Southampton SO15 5AF, England
tel: +44 (0)23 8063 1441, fax: +44 (0)23 8033 9691
web: http://www.mpeforth.com - free VFX Forth downloads

Bernd Paysan

unread,
Mar 31, 2008, 11:33:03 AM3/31/08
to
Stephen Pelc wrote:
> You don't write applications.
>
> Especially, you don't write large applications.

Just for comparison: On the machine I'm sitting right now, MINOS (~10kloc)
takes 0.1s to compile (with bigForth). MINOS can be save-system'd (and the
time for this is included in the 0.1s). Theseus takes 0.08s to compile on
top of it. The largest application so far that I created with Theseus
(about 5kloc), the audio amplifier GUI I showed last EuroForth, takes 0.05s
to compile. It takes 0.25s to initialize the USB interface to talk to the
device, so I've not bothered with save-system-ing this part.

Yes, neither Anton nor I write 1 million line applications. It takes about
10 seconds to compile a 1 million line application on a 2GHz PC with
bigFORTH. Gforth AFAIK compiles a bit faster than bigFORTH. For historical
reasons, bigFORTH's compiler is more optimized for compile speed than for
code speed (compared to VFX). I wanted reasonable compile times on my Atari
ST, which is more than a 1000 times slower than a current PC. I also made
quite some efforts back then to have as much as possible saved with
SAVESYSTEM (excluding dynamically allocated memory).

> You don't write embedded applications.

I think objects.fs is not really made for embedded applications. Those would
more likely use mini-oof. There are ways to "finalize" dynamic storage
systems like the metadata of objects.fs, so that you can savesystem them
when you absolutely want to.

Jonah Thomas

unread,
Mar 31, 2008, 1:12:13 PM3/31/08
to
Bernd Paysan <bernd....@gmx.de> wrote:
> Stephen Pelc wrote:

> > You don't write applications.
> >
> > Especially, you don't write large applications.
>
> Just for comparison: On the machine I'm sitting right now, MINOS
> (~10kloc) takes 0.1s to compile (with bigForth). MINOS can be
> save-system'd (and the time for this is included in the 0.1s). Theseus
> takes 0.08s to compile on top of it. The largest application so far

> that I created with Theseus(about 5kloc), the audio amplifier GUI I


> showed last EuroForth, takes 0.05s to compile. It takes 0.25s to
> initialize the USB interface to talk to the device, so I've not
> bothered with save-system-ing this part.
>
> Yes, neither Anton nor I write 1 million line applications. It takes
> about 10 seconds to compile a 1 million line application on a 2GHz PC
> with bigFORTH. Gforth AFAIK compiles a bit faster than bigFORTH. For
> historical reasons, bigFORTH's compiler is more optimized for compile
> speed than for code speed (compared to VFX). I wanted reasonable
> compile times on my Atari ST, which is more than a 1000 times slower
> than a current PC. I also made quite some efforts back then to have as
> much as possible saved with SAVESYSTEM (excluding dynamically
> allocated memory).

If you're thinking in terms of compiling applications on the spot, would
it make sense to have a virtual file system? So you could put all your
files into one big file and users who install it all can then have just
two files to deal with -- the Forth system and the application file.

I guess people who send out applications in source form and are
concerned about piracy and such, might want some sort of obfuscator.
That isn't hard to do, and results in source code that's probably about
as hard to reverse-engineer as compiled code.

Source code is slower to compile than to use a saved system, though it
has to be a great big application for it to matter at all. And it's
probably going to be bulkier. It lets you avoid the complications of
SAVESYSTEM . Is there any other advantage?

Bruce McFarling

unread,
Mar 31, 2008, 2:39:05 PM3/31/08
to
On Mar 31, 1:12 pm, Jonah Thomas <jethom...@gmail.com> wrote:

If they are all text files, and the text in the files is under your
control, its not hard to organize the source so that the first line is
a "file comment", containing the name of the file (possible followed
by a contiguous string of file comment lines, and requiring at least
one non-file comment line), and then if the files are concatenated, a
single pass through the file would allow writing an index file
identifying the line numbers in the master file associated with each
original source file. If you have time and date modified available,
you can use the existing index file when the index file is modified
after the master file, and regenerate the index file when the master
file is modified later.

I have been using my block comment words
[- file -]
[-- section --]
[--- subsection ---]

looking ahead to exactly that kind of system. Leading single character
punctuation in the title fields are reserved for later use, so, for
example, maybe to have a virtual subdirectory, relative to the current
actual directory:

[- / VER02/REV05 -]

in front of the concatenated text files from that subdirectory.

> I guess people who send out applications in source form and are
> concerned about piracy and such, might want some sort of obfuscator.

That's obviously not an issue that I am ever concerned with, either in
support of professional work or for hobbyist programming, so I'll
defer on that to those who face the issue.

> That isn't hard to do, and results in source code that's probably about
> as hard to reverse-engineer as compiled code.

> Source code is slower to compile than to use a saved system, though it
> has to be a great big application for it to matter at all. And it's
> probably going to be bulkier. It lets you avoid the complications of
> SAVESYSTEM . Is there any other advantage?

The simplest obfuscator is compressed source using a non-standard or
obscure form for the compression algorithm or using decompression
information stored in the implementation rather than the file ... eg,
Huffman encoding with a fixed character table, and the character table
in the Forth implementation rather than the source file. If you used
the PuCrunch compression for the Commodore 64 ... easy to decompress,
hard to compress, ... with the decruncher in the Forth implementation,
that would be pretty substantially obfuscated, and would at the same
time give much smaller sources, given how well Forth source tends to
compress with a mix of LZ77 and RLE compression.

I don't think of SAVE-SYSTEM in terms of obfuscation, but in terms of
creating something for student use locked into a specific wordset with
error trapping and not having to worry about teaching them about the
extreme programming mindset. That is, the original source and free
software Forth implementation would be available for download if they
wanted it, but most students would only want the thing that they
download to work.

Bernd Paysan

unread,
Mar 31, 2008, 3:48:45 PM3/31/08
to
Jonah Thomas wrote:
> If you're thinking in terms of compiling applications on the spot, would
> it make sense to have a virtual file system? So you could put all your
> files into one big file and users who install it all can then have just
> two files to deal with -- the Forth system and the application file.

Actually, you could put the virtual file system (e.g. a zip archive) at the
end of the executable itself, and then have only one single file for
everything. That's not that bad as idea, even if I prefer that the user is
able to extract the sources, too. If the virtual file system happens to be
a standard zip archive, the user can have the advantage of a single file
*and* sources he can manipulate (by extracting the zip archive, changing,
and then using zip to manipulate the archive).

The executable in front would be the Forth loader, and it would use the zip
archive to load the image and the sources from.

However, with the typical setup.exe on Windows and package manages on Linux,
I don't see a need for that - even though there may be hundred of files,
the user sees a single icon, and they expect to install programs through
setup.exes (which also provide an uninstaller). Also, when you have more
than a single program, things would be a bit more difficult (but not too
much - you probably can use the zip archive as generic starter, and an
additional parameter would be the source file to load).

Any volunteer who would evaluate which zip-like archive has the best support
as virtual filesystem, and put an add-on to Gforth or bigForth for using
such a virtual filesystem to retrieve image and sources?

Bruce McFarling

unread,
Apr 1, 2008, 11:22:47 AM4/1/08
to
On Mar 31, 3:48 pm, Bernd Paysan <bernd.pay...@gmx.de> wrote:
> Jonah Thomas wrote:
> > If you're thinking in terms of compiling applications on the spot, would
> > it make sense to have a virtual file system? So you could put all your
> > files into one big file and users who install it all can then have just
> > two files to deal with -- the Forth system and the application file.

> Actually, you could put the virtual file system (e.g. a zip archive) at the
> end of the executable itself, and then have only one single file for
> everything. That's not that bad as idea, even if I prefer that the user is
> able to extract the sources, too. If the virtual file system happens to be
> a standard zip archive, the user can have the advantage of a single file
> *and* sources he can manipulate (by extracting the zip archive, changing,
> and then using zip to manipulate the archive).

> The executable in front would be the Forth loader, and it would use the zip
> archive to load the image and the sources from.

Indeed the executable in front could just be a self-extractor, which
would load the Forth from the archive with the desired start-up
options.

> However, with the typical setup.exe on Windows and package manages on Linux,
> I don't see a need for that - even though there may be hundred of files,
> the user sees a single icon, and they expect to install programs through
> setup.exes (which also provide an uninstaller). Also, when you have more
> than a single program, things would be a bit more difficult (but not too
> much - you probably can use the zip archive as generic starter, and an
> additional parameter would be the source file to load).

It would be used for a single program ... which could be a wrapper
that accesses others. Once you start installing systems of programs,
you get to the reason for the installation management systems built
into or bundled with the OS.

It wouldn't be for permanent installations ... indeed, there is an
appeal among some users for programs that simply sit in a directory
and are executed from a shortcut. This allows:
* try it out to see whether to keep it
* low profile install to subdirectory with shortcut / symbolic links
(which means uninstall has to be accessible from the program itself)
* full fledged install

Scaling up from a simple executable is easier than scaling down from a
full fledged install.

> Any volunteer who would evaluate which zip-like archive has the best support
> as virtual filesystem, and put an add-on to Gforth or bigForth for using
> such a virtual filesystem to retrieve image and sources?

If a self-extracting executable system exists for a zip archive system
that allows starting a binary with access by that binary to the rest
of the archive, that all that is needed is to do a SAVE-SYSTEM of the
underlying Forth system with the initialization set to read the start-
up from the correct file in the archive.

And, yes, this could readily be before OBJECTS.FS is loaded from
archived source.

The simplest way to make the source itself immediately available is to
use a widely supported archive format that is capable of accessing
self-executing archives using normal archive tools. That is, I would
suppose, the .zip archive itself, which can create self-executing
files that can be opened like .zip archives. For niche systems, that
best leverages existing efforts by other developers for those systems.

rago...@gmail.com

unread,
Apr 2, 2008, 8:20:17 PM4/2/08
to
On 29 mar, 13:05, Doug Hoffman <no.spam> wrote:


>
> My guess is that no one is using it to create applications. One reason
> for this would be the problem of getting objects.fs to run in a
> non-source, or turnkey, application.
>

Guess wrong :-)

I am using it ( a VFX for Linux porting ).
Most of the time I use dynamically allocated objects.
I have no need to name them, only a few and
I don't need to save any persistent state.

By the way, I have discovered that objects.fs is not thread-afe,
even with a cooperative multitasker.

The current implementation of the 'this' pointer uses a VALUE, shared
by all tasks.
This has given me lots of hours of headaches. I have changed to the
alternate implementation
written in the comments, but using a USER variable instead. Problem
solved.
Conclussion: any serious OOP package should be thread-safe :-)

Greetings
Rafael


Doug Hoffman

unread,
Apr 2, 2008, 8:59:13 PM4/2/08
to
rago...@gmail.com wrote:
> On 29 mar, 13:05, Doug Hoffman <no.spam> wrote:
>
>
>> My guess is that no one is using it to create applications. One reason
>> for this would be the problem of getting objects.fs to run in a
>> non-source, or turnkey, application.
>>
>
> Guess wrong :-)
>
> I am using it ( a VFX for Linux porting ).
> Most of the time I use dynamically allocated objects.
> I have no need to name them, only a few and
> I don't need to save any persistent state.

By "application" I mean non-source programs for other people
(non-programmers) to use. If you have done that, great. Is it
something I could download and look at?


> By the way, I have discovered that objects.fs is not thread-afe,
> even with a cooperative multitasker.
>
> The current implementation of the 'this' pointer uses a VALUE, shared
> by all tasks.
> This has given me lots of hours of headaches. I have changed to the
> alternate implementation
> written in the comments, but using a USER variable instead. Problem
> solved.
> Conclussion: any serious OOP package should be thread-safe :-)

Thanks for the warning.

Did you do anything to safely catch the error when sending an
unrecognized message? As it is objects.fs will simply crash my Forth.
I would want to add a safe check (which would slow down the late binding).

-Doug

rago...@gmail.com

unread,
Apr 3, 2008, 4:19:09 AM4/3/08
to
On 3 abr, 02:59, Doug Hoffman <no.spam> wrote:


> By "application" I mean non-source programs for other people
> (non-programmers) to use. If you have done that, great. Is it
> something I could download and look at?

Yes, that is my purpose, However it is not mature enough and have not
decide even to release it. It is a hobbyst project with potential use
in the field of amateur astronomy devices control. What do you want
exactly to look up ?

I am still loading from source each time, and have not done the
turnkey application. I'd like to add a GUI when VFX offer this
possibility. However, as said before, I don't need dictionary objects.
I use 'heap-new' all the time.

>
> Did you do anything to safely catch the error when sending an
> unrecognized message? As it is objects.fs will simply crash my Forth.
> I would want to add a safe check (which would slow down the late binding).

I'm not sure what you mean here, but if you just declare a selector
and then you do not override it, the default selector implementation
in objects.fs is to abort.

I have changed that to throw a user defined exception.

hope it helps
Rafael

Doug Hoffman

unread,
Apr 3, 2008, 5:58:15 AM4/3/08
to
rago...@gmail.com wrote:
> On 3 abr, 02:59, Doug Hoffman <no.spam> wrote:

>> By "application" I mean non-source programs for other people
>> (non-programmers) to use.

> I am still loading from source each time, and have not done the
> turnkey application.

I see.

>> Did you do anything to safely catch the error when sending an
>> unrecognized message? As it is objects.fs will simply crash my Forth.
>> I would want to add a safe check (which would slow down the late binding).
>
> I'm not sure what you mean here, but if you just declare a selector
> and then you do not override it, the default selector implementation
> in objects.fs is to abort.

I mean if you accidentally attempt to send a message that is not defined
for that class of object, but the message is defined for a different
class of object. In gforth I get an "invalid memory address" error. In
Carbon MacForth I get a crash with no error message.

-Doug

rago...@gmail.com

unread,
Apr 3, 2008, 6:59:41 AM4/3/08
to
On 3 abr, 11:58, Doug Hoffman <no.spam> wrote:

> I mean if you accidentally attempt to send a message that is not defined
> for that class of object, but the message is defined for a different
> class of object. In gforth I get an "invalid memory address" error. In
> Carbon MacForth I get a crash with no error message.
>
> -Doug

If the selector was defined in an interface that the class did not
implement, I get the expectd exception message "No message/selctor
defined .. blah, blah"

However, for public methods that are not selectors, if I send the
message to the wrong object, I get a SIGSEGV signal (VFX Forth for
Linux)

-Rafael


rago...@gmail.com

unread,
Apr 29, 2008, 8:20:20 PM4/29/08
to
On 27 mar, 03:00, Doug Hoffman <no.spam> wrote:
> I am having a problem running Anton'sOBJECTS.FSextensions. Likely I'm
> doing something simple wrong and hopefully someone can see my error. I
> am running the ANS compatible version ofOBJECTS.FSon Carbon MacForth.
> Theobjects.fsfile loads just fine and I am able to run the example
> code snippets just fine as well. For example:
>
> interface
> selector val
> selector inc
> end-interface foo
>
> object class
> foo implementation
> cell% inst-var n
> m: ( object -- )
> 0 n ! ;m
> overrides construct
> m: ( object -- )
> n @ ;m
> method val
> m: ( object -- )
> 1 n +! ;m
> method inc
> end-class counter
>
> interface
> selector add
> end-interface foobar
>
> counter class
> foobar implementation
> m: ( n object -- )
> 0 do
> this inc
> loop
> ;m overrides add
> end-class xcounter
>
> xcounter dict-new constant x
>
> x val .
> 0 ok
> x inc x val .
> 1 ok
>
> As you can see from the above everything is running just fine at this
> point. Note that I instantiated the xcounter object named x in the
> dictionary, I think.
>
> If I then make a snapshot image of my Forth system and re-launch that I
> am unable to get my object x to do anything. Something like 'x val .'
> leaves two large numbers on the stack (they look like addresses). Same
> for 'x inc' and so on. Worse, I cannot even reload the above code
> starting with 'interface selector val ...'. I get compilation errors
> that appear related to the vocabulary system. The only way I can get
> the object system to work again is to reload everything from the very
> beginning. Any ideas?
>
> TIA
>
> -Doug

Hi all,

Let me reopen the debate of objects.fs.
So far I had not been able to experiencing any problem, because I
loaded my code all
the time. But this week, I reached the point where I wanted to
generate a turnkey app.

In the turnkey application, I created new objects of the classes
previuously defined
and suprise, suprise, it crashed !!

Having a look at the objects.fs source code, I realized that the
"virtal tables"
where XTs or methods are stored, they are allocated from the heap.
My understanding is that it is easy to layout the virtual table
incrementally and
this requires resizing as each method is being defined.

However if you SAVE-SYSTEM, you loose all the XTs in the saved
image !

I have found an easy way to make it fully persistant: after all
methods have been defined,
you have the full size and start address of the virtual table for
each class.
So it is easy to add a word (let's say "persistant") that copies this
table back to
the dictionary,
then patch the last class bookeeping fields and release the memory
from the heap.
This must be done for each class and interface you want to persist. It
works,
at least for me.

I attach the code and example of usage.

greetings
Rafael


\
----------------------------------------------------------------------

: persistant
\ *G Copy the last defined interface map from the heap
\ ** back to the dictionary so that it can be safely saved in turnkey
\ ** applications, freeing the unusued memory from the heap
current-interface @ interface-map 2@
here dup >r over allot
swap move
current-interface @ interface-map 2@ swap free throw
r> swap current-interface @ interface-map 2!
;

persistant \ First: make root class 'object' persistant

object class
Cell% inst-var m-count
end-class example

example methods
public

m:
m-count off
;m overrides construct

m:
." I'm foo" cr
." count is " m-count ? cr
1 m-count +!
;m overrides print

end-methods persistant

example dict-new constant e1

e1 print
e1 print

save persistant.elf cr
bye

Doug Hoffman

unread,
Apr 30, 2008, 8:22:29 PM4/30/08
to
rago...@gmail.com wrote:

> I have found an easy way to make it fully persistant: after all
> methods have been defined,
> you have the full size and start address of the virtual table for
> each class.
> So it is easy to add a word (let's say "persistant") that copies this
> table back to
> the dictionary,
> then patch the last class bookeeping fields and release the memory
> from the heap.
> This must be done for each class and interface you want to persist. It
> works,
> at least for me.

Thank you for that. I wonder if persistant could simply be made part of
the end-methods definition? This would follow the rule of Minimum
Astonishment when saving an image or creating a turnkey.

-Doug

rago...@gmail.com

unread,
May 1, 2008, 4:06:28 AM5/1/08
to
Hi Doug

Further test have shown that this do not work for classes implementing
interfaces. I'm working on that to find out why.

Yes, I think that there is no reason to let all the class maps live in
the heap. For interfaces it is easy to embed "persistant" inside "end-
interface". For classes, it is not possible IMHO, because there are
two ways of defining them: the "Java style", with all the methods
inside the end-class definition; anth the C++ style with separate
header and implementation. Embedding "persistant" in "end-methods"
would not allow the "Java" style and embdeding "persistant" into "end-
class" would not allow the "C++" style. So, my conclussion is that we
should add "persistant" manually.

Rafael

On 1 mayo, 02:22, Doug Hoffman <no.spam> wrote:

Doug Hoffman

unread,
May 3, 2008, 12:37:01 PM5/3/08
to
rago...@gmail.com wrote:

> Further test have shown that this do not work for classes implementing
> interfaces. I'm working on that to find out why.

That is unfortunate. Let's hope there is a way to do so. IMHO
Objects.fs *require* interfaces so the programmer is not burdened with
the constraints of which messages can be passed to which objects, i.e.,
having to design the class hierarchy in a specific way.

With the Neon style model all messages can be sent to all objects and
interfaces are not required (nor do interfaces even exist). Neon has
always been compatible with saved images and turnkeys. I have recently
implemented message dispatch tables for Neon, let's call it Neon+.
Neon+ has a constant time for sending late-bound messages and by my
measurement is clearly faster than Objects.fs in doing so. Neon+
retains all other features of Neon, notably default early binding (no
extra work required from the programmer), and so is considerably faster
than Objects.fs.

-Doug

rago...@gmail.com

unread,
May 7, 2008, 9:20:43 AM5/7/08
to
I finally made it work. I attach the source code. There is no need to
modify objects.fs although I'd love to see it included in the
"official" release by Anton. Just include this after objects.fs.

Note that if you wish to omit the "persistant" word after each
interface, you need to redefine
end-interface as
: end-interface end-interface persistant ;

As I said before, this cannot be done generally in classes. If you
always stick to the same class declaration style, then you could
probably do a similar thing either in end-class or end-methods

-Rafael

\
==============================================================================================
\ Persistant classes for objects.fs
\ Rafael Gonzalez Fuentetaja, May, 7th, 2008.
\ Public Domain, no warranty.

: heap>dict \ addr1 u1 -- addr2
\ +G Transfer a chunk of memory from the heap to the dictionary
memory,
\ +* releasing the old heap memory.
over >r
here dup >r over allot \ -- addr1 n addr2 ; R: -- addr1 addr2
swap move
r> r> free throw
;

: persist-interface-map \ old-ifce-map -- new-ifce-map
\ +G Persist a single interface map into the dictionary memory.
dup
@ interface-map 2@ nip \ get the interface map size
heap>dict \ and reallocate
;

: persist-interface-maps \ --
\ +G Persist all interface maps for classes that implement interfaces.
\ Loop not executed if no interfaces are implemented.
current-interface @ dup interface-map-offset @ swap interface-map
2@ drop
swap bounds ?do
i @ ?dup if persist-interface-map
i ! \ patch the interfaces list with the new address.
then
1 cells +loop
;

: persistant
\ *G Copy the last defined interface map from the heap
\ ** back to the dictionary so that it can be safely saved in turnkey

\ ** applications, freeing the unusued heap memory.
current-interface @ interface-map 2@ dup >R
heap>dict
R> current-interface @ interface-map 2!
persist-interface-maps
;

object persistant \ make the root class persistant

0 [if] \ example code

interface
selector sel1
selector sel2
end-interface i-test1 persistant

interface
selector sel3
selector sel4
end-interface i-test2 persistant

object class
i-test2 implementation

Cell% inst-var m-count

selector foo

end-class per1

per1 methods
public

m:
m-count off
;m overrides construct

m:


." count is " m-count ? cr
1 m-count +!
;m overrides print

m:
." I'm foo selector" cr
;m overrides foo

:m bar
." I'm bar method"
;m

m:
." I'm selector sel4" cr
;m overrides sel4

end-methods persistant

per1 dict-new constant p1

p1 print
p1 print

save persis.elf cr
bye


[then]

Doug Hoffman

unread,
May 7, 2008, 11:06:44 AM5/7/08
to
rago...@gmail.com wrote:
> I finally made it work. I attach the source code.

That's great. Thank you.

The syntax still seems like a lot of work compared to other objects
packages. Consider the same example in Neon. No need for the following
words:

interface
selector
end-interface
persistant
implementation
inst-var
methods
overrides
end-methods
dict-new
constant

The default early binding will cause 'print: p1' to execute about twice
as fast as the objects.fs 'p1 print'. Forcing Neon to late bind with
'p1 print: **' will give about the same execution speed. As it always
has been, Neon is compatible with image saving and turnkeys.

-Doug

:class per1
var m-count

:m classinit: 0 put: m-count ;m

:m print:
." count is " print: m-count cr
1 +: m-count ;m

:m foo:


." I'm foo selector" cr ;m

:m bar:
." I'm bar method" ;m

:m sel4:


." I'm selector sel4" cr ;m

;class


per1 p1

\ early binding
print: p1
print: p1

\ or late binding
p1 print: **
p1 print: **

rago...@gmail.com

unread,
May 7, 2008, 2:36:26 PM5/7/08
to
On 7 mayo, 17:06, Doug Hoffman <no.spam> wrote:

> ragof...@gmail.com wrote:
> > I finally made it work. I attach the source code.
>
> That's great. Thank you.
>


>


> The default early binding will cause 'print: p1' to execute about twice
> as fast as the objects.fs 'p1 print'. Forcing Neon to late bind with
> 'p1 print: **' will give about the same execution speed. As it always
> has been, Neon is compatible with image saving and turnkeys.
>
> -Doug


When I started writing my pet project, I wished there was a standard
for an OOP package, Neon or whatever, just like the same way as there
is now a standard proposal for structs in Forth 200x.
Now, it's too late for me - I don't want to rewrite my software - but
perhaps not for others.

-Rafael

rago...@gmail.com

unread,
May 10, 2008, 7:07:39 AM5/10/08
to
On 7 mayo, 15:20, ragof...@gmail.com wrote:
> I finally made it work. I attach the source code. There is no need to
> modify objects.fs although I'd love to see it included in the
> "official" release by Anton. Just include this after objects.fs.
>

Corrected a bug where FREE was invoked on ALLOTed memory in some
cases.

\ Persistant.fs
\ Adding persistance to objects.fs
\ Include this file after objects.fs
\ to use it, add "persistant" after each end-interface and
\ end-methods (if you declare methods outside the class)
\ or end-class (if you declare all methods within the class)
\
\ Rafael Gonzalez Fuentetaja, May, 10th 2008
\ Public Domain. No Warranty

: allot&move \ addr1 u1 -- addr2
\ +G Copy a chunk of memory to the dictionary memory,
\ +* Return the new address.


here dup >r over allot

swap move
r>
;

: heap>dict \ addr1 u1 -- addr2
\ +G Transfer a chunk of memory from the heap to the dictionary
memory,

\ +* releasing old heap memory.
over >r allot&move r> free throw
;

: persist-interface-map \ old-ifce-map -- new-ifce-map
\ +G Persist a single interface map into the dictionary memory.

\ Memory leaks and dupplication occur here, but it is of no relevance
\ in the saved system.


dup
@ interface-map 2@ nip \ get the interface map size

allot&move \ and reallocate
;

: persist-interface-maps \ class --
\ +G Persist all interface maps for *\i{class} that implement
interfaces.
\ +* Does nothing if *\i{class} do not implement interfaces.


dup interface-map-offset @ swap interface-map 2@ drop
swap bounds ?do

i @ ?dup if persist-interface-map i ! then
1 cells +loop
;

: persistant \ --


\ *G Copy the last defined interface map from the heap
\ ** back to the dictionary so that it can be safely saved in turnkey

\ ** applications.


current-interface @ interface-map 2@ dup >R
heap>dict
R> current-interface @ interface-map 2!

current-interface @ persist-interface-maps
;

persistant \ make the root 'object' class persistant

0 [if]

0 new messages