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

defer this not

291 views
Skip to first unread message

Enoch

unread,
Jul 6, 2016, 5:21:46 PM7/6/16
to
Request for Discussion
======================

defer is Forth standard way of dealing with forward references (e.g., see Gforth section 5.9.10 on deferred words).

Would you agree that to resolve a forward reference via defer is inefficient and/or cumbersome?

Having a case of mutual recursion where A calls B and B calls A. How can we really justify the need for a deferred-B construct simply because A is compiled before B.

Indeed, some Forth systems spent a great deal of effort on avoiding such defer-s. See openfirmware/forth/kernel/forward.fth

May I suggest that modern Forth systems would be *required* to deal with forward references silently, even the one pass compile type. That is, create some dictionary place holder when encountering the forward reference first and then, when the definition is presented, replace that place holder. An attempt to execute an unresolved forward reference should cause a specific exception number.

TIA, Enoch.


lawren...@gmail.com

unread,
Jul 6, 2016, 9:31:19 PM7/6/16
to
On Thursday, July 7, 2016 at 9:21:46 AM UTC+12, Enoch wrote:

> May I suggest that modern Forth systems would be *required* to deal with
> forward references silently, even the one pass compile type. That is, create
> some dictionary place holder when encountering the forward reference first
> and then, when the definition is presented, replace that place holder. An
> attempt to execute an unresolved forward reference should cause a specific
> exception number.

That would mean a reference to an undefined name could only be picked up at run-time, not compile-time.

hughag...@gmail.com

unread,
Jul 6, 2016, 9:45:03 PM7/6/16
to
No, it could be done at compile-time. I could add this idea to Straight Forth easily enough.

If a function is called that references an unknown word, the function would still compile, but it would give a warning such as: "unknown word: xxx ". Also, if the function is executed it aborts with an error message such as: "function incomplete; references unknown word". If the unknown word later gets written, then the function that references it gets patched so that it can be executed.

DEFER is inefficient because an indirect call is being done. This would still be useful in a program (my LowDraw.4th is an example) in which multiple functions are available to be plugged into the vector depending upon what the user requests (in the case of LowDraw.4th, depending upon which drawing-strategy is being tested).

lawren...@gmail.com

unread,
Jul 6, 2016, 10:54:35 PM7/6/16
to
On Thursday, July 7, 2016 at 1:45:03 PM UTC+12, hughag...@gmail.com wrote:
>
> On Wednesday, July 6, 2016 at 6:31:19 PM UTC-7, Lawrence D’Oliveiro wrote:
>>
>> That would mean a reference to an undefined name could only be picked up
>> at run-time, not compile-time.
>
> No, it could be done at compile-time. I could add this idea to Straight
> Forth easily enough.
>
> If a function is called that references an unknown word, the function would
> still compile, but it would give a warning such as: "unknown word: xxx ".

Warnings, yuk. Those either get ignored or turned off.

> Also, if the function is executed it aborts with an error message such as:
> "function incomplete; references unknown word".

That’s not compile-time any more, that’s run-time.

hughag...@gmail.com

unread,
Jul 7, 2016, 1:53:49 AM7/7/16
to
On Wednesday, July 6, 2016 at 7:54:35 PM UTC-7, lawren...@gmail.com wrote:
> On Thursday, July 7, 2016 at 1:45:03 PM UTC+12, hughag...@gmail.com wrote:
> >
> > On Wednesday, July 6, 2016 at 6:31:19 PM UTC-7, Lawrence D’Oliveiro wrote:
> >>
> >> That would mean a reference to an undefined name could only be picked up
> >> at run-time, not compile-time.
> >
> > No, it could be done at compile-time. I could add this idea to Straight
> > Forth easily enough.
> >
> > If a function is called that references an unknown word, the function would
> > still compile, but it would give a warning such as: "unknown word: xxx ".
>
> Warnings, yuk. Those either get ignored or turned off.

I said that I "could" add this to StraightForth --- I didn't say that I necessarily would.

I agree that if the warning is ignored (likely), fixing the problem would be delayed significantly because the programmer wouldn't find out about the problem until run-time (and only if the function gets executed).

Mutual-recursion isn't very common --- other than in the novice-package in which every example program involves recursion (except the N-Queens program) --- so making mutual-recursion slightly more efficient isn't a major priority for me.

> > Also, if the function is executed it aborts with an error message such as:
> > "function incomplete; references unknown word".
>
> That’s not compile-time any more, that’s run-time.

True enough.

I meant to say that the error message would be:
"function incomplete; references unknown word: xxx"
That would be a pretty clear error-message that would tell the programmer exactly what went wrong.

Raimond Dragomir

unread,
Jul 7, 2016, 2:13:14 AM7/7/16
to
DEFER is a simple way to avoid complications and keep the system simple.
The compiler can have any complexity you like. A simple compiler will
compile indirect calls. A more elaborate one will compile direct calls.

DEFER should be used only to resolve mutual-recursions.

For vectored execution there is always VARIABLE and then @ EXECUTE.
If one don't like how it looks, one can implement a VECTOR or some
other naming for a word that just acts as VARIABLE when reserving the
memory cell and like @ EXECUTE when used.

Lars Brinkhoff

unread,
Jul 7, 2016, 2:24:54 AM7/7/16
to
Raimond Dragomir <raimond....@gmail.com> writes:
> DEFER should be used only to resolve mutual-recursions.
> For vectored execution there is always VARIABLE and then @ EXECUTE.

Why not use DEFER for vectored execution?

JennyB

unread,
Jul 7, 2016, 2:42:12 AM7/7/16
to
What happens when the name chosen for a forward reference accidentally clashes with that of an existing or future definition? I would prefer code to self-documents ford references.

Defer A
: B .... A ... ;
:NONAME ... B ... ; is A

is clear, and works. If the inefficiency bothers you then perhaps your compiler could optimise the pattern, or you preferably you could have a pair of words (say FORWARD and RESOLVE) to declare and handle invariant forward references.

hughag...@gmail.com

unread,
Jul 7, 2016, 2:43:47 AM7/7/16
to
I reviewed LowDraw.4th and I don't use DEFER --- I just pass the xt in as a parameter --- now that I think about it, DEFER wouldn't be useful for vectored execution because IS only works at compile-time not run-time.

So, Raimond was right.

Well, actually I have VECTOR in the novice-package that is more efficient than DEFER --- so Raimond was half right.

hughag...@gmail.com

unread,
Jul 7, 2016, 2:49:26 AM7/7/16
to
My naming convention is to put pointy brackets around the function name:

vector A

: B ... A ... ;

: <A> ... B ... ;

' <A> is-A

Your code is fine though --- it doesn't really matter --- whatever people feel comfortable with.

This could be done instead:

vector A

: B ... A ... ;

:noname ... B ... ;
is-A

Elizabeth D. Rather

unread,
Jul 7, 2016, 2:52:17 AM7/7/16
to
DEFER was invented for vectored execution, and for many years has been
principally used that purpose. Mutual recursion is a small minority
reason for it to exist.

Cheers,
Elizabeth

--
==================================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310.999.6784
5959 West Century Blvd. Suite 700
Los Angeles, CA 90045
http://www.forth.com

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

Raimond Dragomir

unread,
Jul 7, 2016, 3:11:33 AM7/7/16
to
Because it is implementation dependent. I compile in flash (for example).

Also, I forgot about IS.

IS should work with VECTOR, not with DEFER. There's no need for IS in the
mutual-recursion-only DEFER. There's only one definition that will
implement the deferred word and that can be just a plain colon definition.

For example:

DEFER DeferredFoo

: bar DeferredFoo ;

: DeferredFoo ... ;

Using DEFER for both vectored execution and mutual-rescursion is just
not portable (if you care about portability) but worse, it mix two
very different things. Mutual-recursion is just a compiling issue,
vectored execution is an application technique.

JennyB

unread,
Jul 7, 2016, 3:12:51 AM7/7/16
to
Yes. Mutual recursion is not common, and very much a minority use case for Defer ... Is.

If I found myself doing it a lot I might be tempted to write Forward and Resolve as aliases for Defer and Is just to clarify what was going on, and so I could rewrite them to resolve at compile time if it turned out that the speed difference between a direct and indirect call really mattered.

Lars Brinkhoff

unread,
Jul 7, 2016, 3:33:34 AM7/7/16
to
Raimond Dragomir <raimond....@gmail.com> writes:
> There's no need for IS in the mutual-recursion-only DEFER. There's
> only one definition that will implement the deferred word and that can
> be just a plain colon definition.
>
> For example:
>
> DEFER DeferredFoo
>
> : bar DeferredFoo ;
>
> : DeferredFoo ... ;

I don't understand. In this code, bar calls the first DeferredFoo. The
second DeferredFoo doesn't affect the first DeferredFoo or bar.

hughag...@gmail.com

unread,
Jul 7, 2016, 3:53:03 AM7/7/16
to
On Wednesday, July 6, 2016 at 11:52:17 PM UTC-7, Elizabeth D. Rather wrote:
> On 7/6/16 8:24 PM, Lars Brinkhoff wrote:
> > Raimond Dragomir <raimond....@gmail.com> writes:
> >> DEFER should be used only to resolve mutual-recursions.
> >> For vectored execution there is always VARIABLE and then @ EXECUTE.
> >
> > Why not use DEFER for vectored execution?
>
> DEFER was invented for vectored execution, and for many years has been
> principally used that purpose. Mutual recursion is a small minority
> reason for it to exist.

As I said, DEFER doesn't work for vectored-execution because IS only works at compile-time --- with vectored-execution you typically want to choose the vector at run-time depending upon the user's input.

Also, if you know what DEFER is used for (I don't think you do), then why is it that ANS-Forth doesn't have any deferred words? For example, LITERAL could be deferred --- this would help make it easy to write a cross-compiler in ANS-Forth that uses the built-in outer-interpreter because LITERAL could be revectored by the HOST colon to compile the literal into the target memory rather than the host memory, and then revectored back to the default by semicolon.

This is not the only example of how Forth can be made more extensible by making various low-level words vectored --- I'm not the only Forther who is aware of this --- Stephen Pelc made a lot of low-level words vectored in VFX.

ANS-Forth is cripple-ware! You purposely crippled ANS-Forth so that it could only be used for writing toy programs --- you did this to prevent ANS-Forth programmers from writing useful programs in competition with Forth Inc. and MPE --- if they do write useful programs, they have to abandon ANS-Forth compliance on the first day of the project, then you howl that their program is non-standard (being non-standard makes it difficult to sell a program because the customer worries that the program can't be ported to another compiler if the compiler-vendor goes out of business).

Stephen Pelc is well aware that ANS-Forth is cripple-ware --- this is why he works around the bugs in ANS-Forth in his VFX --- he makes no effort to fix the ANS-Forth bugs in Forth-200x, because his only goal is to sell VFX, not to provide the Forth community with a usable Standard.

Elizabeth D. Rather

unread,
Jul 7, 2016, 4:23:05 AM7/7/16
to
DEFER/IS is *primarily* for vectored execution. If you want a word
dedicated to mutual recursion, it should be something else.

Gerry Jackson

unread,
Jul 7, 2016, 5:01:04 AM7/7/16
to
On 07/07/2016 08:53, hughag...@gmail.com wrote:
> On Wednesday, July 6, 2016 at 11:52:17 PM UTC-7, Elizabeth D. Rather wrote:
>> >On 7/6/16 8:24 PM, Lars Brinkhoff wrote:
>>> > >Raimond Dragomir<raimond....@gmail.com> writes:
>>>> > >>DEFER should be used only to resolve mutual-recursions.
>>>> > >>For vectored execution there is always VARIABLE and then @ EXECUTE.
>>> > >
>>> > >Why not use DEFER for vectored execution?
>> >
>> >DEFER was invented for vectored execution, and for many years has been
>> >principally used that purpose. Mutual recursion is a small minority
>> >reason for it to exist.
> As I said, DEFER doesn't work for vectored-execution because IS only works at compile-time --- with vectored-execution you typically want to choose the vector at run-time depending upon the user's input.

http://forth-standard.org/standard/core/DEFERStore overcomes that
problem. Also IS can be used in a word that does the switching if the
target is known at compile time.

--
Gerry

Raimond Dragomir

unread,
Jul 7, 2016, 6:42:27 AM7/7/16
to
There is only one DeferredFoo. I'm sure you canthink of an implementation
technique that makes this possible. My LFTForth works this way.

This is in fact an example for Enoch, to show that a simple DEFER declaration
before using the deferred word doesn't hurt and in fact can simplify
the compiler. Enoch wants that the example work without DEFER at all:

: bar DeferredFoo ;
: DeferredFoo bar ;

This should silently compile ok. However, having this will "defer" all
undefined word errors till the end of the compilation. The simplest
thing is to declare the deferred word first:

DEFER DeferredFoo
: bar DeferredFoo ;
: DeferredFoo bar ;

Coos Haak

unread,
Jul 7, 2016, 6:47:17 AM7/7/16
to
Op Thu, 7 Jul 2016 00:53:01 -0700 (PDT) schreef hughag...@gmail.com:

<snip>
> As I said, DEFER doesn't work for vectored-execution because IS only
> works at compile-time --- with vectored-execution you typically want
> to choose the vector at run-time depending upon the user's input.

IS works in compilation as well as during interpretation.

RTFM stupid!

Raimond Dragomir

unread,
Jul 7, 2016, 6:52:29 AM7/7/16
to
joi, 7 iulie 2016, 10:12:51 UTC+3, JennyB a scris:
> Yes. Mutual recursion is not common, and very much a minority use case for Defer ... Is.
>
> If I found myself doing it a lot I might be tempted to write Forward and Resolve as aliases for Defer and Is just to clarify what was going on, and so I could rewrite them to resolve at compile time if it turned out that the speed difference between a direct and indirect call really mattered.

In your system where the DEFER can work both as a vectored execution and
mutual recursion you can do that.

In my system where the code space is in flash and data space is in ram,
I can't. I'm forced to implement these at the low level. The compiler should
compile mutual rescursions in flash, vectored execution is happening at
runtime using ram. Tell me why should I choose DEFER for vectored
execution and another naming for mutual recursion compilation?
In any case, my system will not be compatible with ANS Standard...

Matthias Koch

unread,
Jul 7, 2016, 7:57:32 AM7/7/16
to
Dear Enoch,

when performance matters, I would suggest using

: first ( ... )
[ here 1 cells allot ]
;

( a-addr )

and later patching back the call when the second definition is known.

: second ( ... )
first
;

' second make-this-a-call-opcode !

Of course, this is not standard, it works in RAM only and
you have to build a proper opcode yourself.

I found this necessary when I wrote a bit-bang VGA video signal
generator interrupt handler for Mecrisp-Ice, which will be
released with the next mainstream package.

: vga-irq-active ( -- )
...
\ Address of the second handler will be inserted here
\ as soon as the address is known.
[ here ] 0 $1FFE !
...
;

: vga-irq-sync ( -- )
...
['] vga-irq-active 2/ $1FFE !
...
;

\ Insert the address of the second handler into the first
' vga-irq-sync 2/ swap +!

Technically, this boils down to an optimized variant
of Jennys idea of FORWARD and RESOLVE.

Best wishes,
Matthias

Lars Brinkhoff

unread,
Jul 7, 2016, 2:31:38 PM7/7/16
to
Raimond Dragomir <raimond....@gmail.com> writes:
> There is only one DeferredFoo. I'm sure you canthink of an implementation
> technique that makes this possible. My LFTForth works this way.

Sure, but then your're not talking about the DEFER defined in the 2012
standard. Which is fine, but it confused me.

Enoch

unread,
Jul 7, 2016, 2:37:58 PM7/7/16
to
Dear Matthias,

I do back patching now, see my Cookbook section in <https://github.com/wexi/amforth-shadow/blob/master/amforth-shadow.org>. I am not happy with it though.

DEFER/IS or even Leo Brodie old MAKE/DOER idea to resolve forward reference add complexity where none is really needed.

A programmer should have the freedom to arrange his word definitions in whatever order he/she wishes (within one compilation unit) without being concerned about creating unresolved forward references, and if this causes the compiler a little effort, so be it.

Shouldn't READABILITY (*) be number one concern of any programming language?

Regards, Enoch.

(*) "Readability refers to the ease with which a human reader can comprehend the purpose, control flow, and operation of source code". Wikipedia on Computer Programming.









Julian Fondren

unread,
Jul 7, 2016, 3:09:14 PM7/7/16
to
On Thursday, July 7, 2016 at 1:37:58 PM UTC-5, Enoch wrote:
>
> A programmer should have the freedom to arrange his word definitions in whatever order he/she wishes (within one compilation unit) without being concerned about creating unresolved forward references, and if this causes the compiler a little effort, so be it.
>
> Shouldn't READABILITY {) be number one concern of any programming language?

Suppose I have this code:

variable file
: open ( -- ) z" links.list" [ O_WRONLY O_APPEND or ] literal open dup ?ERRUR file ! ;
: append ( 'line' -- ) file @ write-file throw ;
: close ( -- ) file @ close-file throw -1 file ! ;

: go ( -- )
open
get-things append
get-more-things append
yet-more? if get-them append then
close ;

-- program ends here --

Is there a collision between FILE OPEN APPEND CLOSE GO and anything
else in the program? I don't have to go looking to figure it out.
I don't have to open every library I might have included to confirm.
The anaswer is "no". When I see "variable X", or ": X", I know that I
only need to consider the *following* code to know anything relevant
to X.

It is both safe and irrelvant to the above code if somewhere else in
my program, earlier and in the same vocabulary, I had written

variable file
: m:logline ( 'log' -- ) -matching
skipping s" LOG" match m:spaces* m:number m:spaces*
file into m:hexnumber m:newline ;

That FILE would be obscured by the later one, but so what? The short
name is its own hint that I don't care much about its lifetime. If I
need to access it, what is obscured can still be dug up.

Forth's linearity is a readability aid. Forth does not have the
lexical scope or the tradition of abusing wordlists that it might have
as readabiliy aids alternate to this one. Forth's encouagements of
factoring and of having lots and lots of words mean that these
alternate aids would suit the language less, anyway. Abuse of
wordlists in particular just tends to work out to longer words, the
same as if you'd given them long names in the first place, just more
annoying to use.


Your proposal would make Forth significantly harder to read.


-- Julian

Alex Dowad

unread,
Jul 7, 2016, 4:01:31 PM7/7/16
to
On Thursday, 7 July 2016 20:37:58 UTC+2, Enoch wrote:
> A programmer should have the freedom to arrange his word definitions in whatever order he/she wishes (within one compilation unit) without being concerned about creating unresolved forward references, and if this causes the compiler a little effort, so be it.

With some programming languages, your code is executed as it is read. With others, your code is parsed in its entirety and put through multiple stages of (often complex) preprocessing, before execution. Forth and Lisp are firmly in the first category, as are all the "scripting languages". You are probably accustomed to languages in the second category, like C or Haskell.

The first type allow for a much simpler implementation. Additionally, they are amenable to interactive use, where you type a line of code and immediately see the results, then type another line, and so on. This is a powerful feature.

Of course, the second type also has its place. But trying to force Forth into the latter paradigm is a poor fit. You would do better to create your own (new) language, and borrow whatever features you like from Forth.

Paul Rubin

unread,
Jul 7, 2016, 4:32:17 PM7/7/16
to
Alex Dowad <alexin...@gmail.com> writes:
>> A programmer should have the freedom to arrange his word definitions
>> in whatever order he/she wishes (within one compilation unit)...
> With some programming languages, your code is executed as it is
> read. With others.... Forth and Lisp are firmly in the first category,
> as are all the "scripting languages". Of course, the second type also
> has its place. But trying to force Forth into the latter paradigm is a
> poor fit.

The difference isn't whether the whole file is read before execution
starts. Rather, it's that Forth traditionally uses early binding while
Lisp and scripting languages typically use late binding. So

(defun cube (x) (* x (square x)))
(defun square (x) (* x x))
(print (cube 3))

prints 27, because when cube is compiled, it allocates a cell for the
previously unseen symbol "square", then when square is compiled it puts
code into that cell, and then when cube is called, it runs the code that
is now in the "square" cell. The Forth approach would throw an error
in the definition of cube, because square was not already defined.

I believe late-binding Forths have also been implemented.

Julian Fondren

unread,
Jul 7, 2016, 5:54:57 PM7/7/16
to
On Thursday, July 7, 2016 at 3:32:17 PM UTC-5, Paul Rubin wrote:
> I believe late-binding Forths have also been implemented.

Wil Baden's ThisForth made extensive use of macros. As in:

s" blah" EVALUATE

The result was that it words were sort of randomly bound.

Redefining + would change some prior uses of it, and not others.
Redefining another word might have the normal result.
This might depend on the current search order. And BASE

I wasn't around to see how ThisForth was received...


-- Julian

hughag...@gmail.com

unread,
Jul 7, 2016, 7:19:29 PM7/7/16
to
DEFER isn't in the ANS-Forth document, so I can't RTFM. If IS is STATE-smart (it is in the novice-package) then it will work during compilation --- with most implementations it only works during interpretation --- because it is not standardized in ANS-Forth, the ANS-Forth programmer can't expect any particular behavior (if he assumes interpretation only, then his code should be portable to most systems).

This code is in the novice-package:

: bad-vector \ pre-initialize vectors with this and overwrite it with a good vector later
true abort" *** uninitialized vector ***" ;

: defer ( -- ) \ stream: name \ defines a deferred word
create ['] bad-vector ,
does>
@ execute ;

: is ( xt -- ) \ stream: name \ resolves a deferred word
state @ if
postpone [']
postpone >body
!,
else
' >body ! then ;
immediate

\ DEFER and IS are very traditional, so I provided them.
\ VECTOR is much more efficient.

: <vector> { name | xt -- }
here ['] bad-vector , to xt
c" is-" name get-current :2name \ runtime: xt --
xt lit, !, ;,
name get-current :name \ runtime: -- \runtime runtime: i*x -- j*x
state@, if, xt lit, postpone lit, postpone @, postpone execute,
else, xt lit, @, execute, then, ;,
immediate
;

: vector ( -- )
bl word hstr dup >r <vector> r> dealloc ;

Under SwiftForth, this is what gets compiled for DEFER words:

defer aaa ok
: test-aaa aaa ; ok

see test-aaa
48E98F 48E94F ( aaa ) JMP E9BBFFFFFF ok

see aaa
48E94F 4867D9 ( defer +1A ) CALL E8857EFFFF

see defer
4867BF 40FAFF ( CREATE ) CALL E83B93F8FF
4867C4 4 # EBP SUB 83ED04
4867C7 EBX 0 [EBP] MOV 895D00
4867CA 8276F # EBX MOV BB6F270800
4867CF 40AA2F ( , ) CALL E85B42F8FF
4867D4 40DA4F ( (;CODE) ) CALL E87672F8FF
4867D9 4 # EBP SUB 83ED04
4867DC EBX 0 [EBP] MOV 895D00
4867DF EBX POP 5B
4867E0 0 [EBX] EBX MOV 8B1B
4867E2 40434F ( EXECUTE ) JMP E968DBF7FF ok

see execute
40434F EBX ECX MOV 8BCB
404351 0 [EBP] EBX MOV 8B5D00
404354 4 # EBP ADD 83C504
404357 ECX ECX OR 09C9
404359 40435F JZ 7404
40435B EDI ECX ADD 01F9
40435D ECX JMP FFE1
40435F RET C3 ok

This is what gets compiled for VECTOR words:

vector bbb ok
: test-bbb bbb ; ok

see test-bbb
48EA3F 4 # EBP SUB 83ED04
48EA42 EBX 0 [EBP] MOV 895D00
48EA45 48E994 # EBX MOV BB94E94800
48EA4A 0 [EBX] EBX MOV 8B1B
48EA4C 40434F ( EXECUTE ) JMP E9FE58F7FF ok

As you can see, my VECTOR is more efficient than DEFER is.

Coos Haak

unread,
Jul 7, 2016, 7:40:03 PM7/7/16
to
Op Thu, 7 Jul 2016 16:19:28 -0700 (PDT) schreef hughag...@gmail.com:

> On Thursday, July 7, 2016 at 3:47:17 AM UTC-7, Coos Haak wrote:
>> Op Thu, 7 Jul 2016 00:53:01 -0700 (PDT) schreef hughag...@gmail.com:
>>
>> <snip>
>>> As I said, DEFER doesn't work for vectored-execution because IS only
>>> works at compile-time --- with vectored-execution you typically want
>>> to choose the vector at run-time depending upon the user's input.
>>
>> IS works in compilation as well as during interpretation.
>>
>> RTFM stupid!
>
> DEFER isn't in the ANS-Forth document, so I can't RTFM. If IS is STATE-smart (it is in the novice-package) then it will work during compilation --- with most implementations it only works during interpretation --- because it is not standardized in ANS-Forth, the ANS-Forth programmer can't expect any particular behavior (if he assumes interpretation only, then his code should be portable to most systems).
>

Right, OK. But then you can't say anything about it (and IS) if it works
during compilation or during interpretation.
You meant 'in my implementation DEFER doesn't work...'

groet Coos

Elizabeth D. Rather

unread,
Jul 7, 2016, 8:31:57 PM7/7/16
to
On 7/7/16 1:39 PM, Coos Haak wrote:
...
>> DEFER isn't in the ANS-Forth document, so I can't RTFM. If IS is STATE-smart (it is in the novice-package) then it will work during compilation --- with most implementations it only works during interpretation --- because it is not standardized in ANS-Forth, the ANS-Forth programmer can't expect any particular behavior (if he assumes interpretation only, then his code should be portable to most systems).
>>
>
> Right, OK. But then you can't say anything about it (and IS) if it works
> during compilation or during interpretation.
> You meant 'in my implementation DEFER doesn't work...'

DEFER is a defining word (like VARIABLE), whose behavior is to execute
an xt in its data space. Possible (common) definitions are:

:NONAME ABORT" Unitialized DEFER" ;

: DEFER ( xt -- ) CREATE ,
DOES> @ EXECUTE ;

DEFER MYTYPE ' TYPE IS MYTYPE

Whether it is initialized when it's defined and how you handle an
uninitialized DEFER, etc., are not specified; it's an ambiguous
condition if it's uninitialized or if the object of IS is not defined by
DEFER.

The full definitions of DEFER, IS, and related words are in Forth2012,
although they're consistent with long-standing common usage. There was
actually discussion of standardizing them in Forth94, but the prospect
was raised so late in the process no one had the energy to pursue it.

hughag...@gmail.com

unread,
Jul 7, 2016, 8:41:29 PM7/7/16
to
In my implementation DEFER works in the usual way --- also, IS works during compilation or during interpretation.

As I also said, VECTOR generates more efficient code than DEFER does.

hughag...@gmail.com

unread,
Jul 7, 2016, 8:46:07 PM7/7/16
to
On Thursday, July 7, 2016 at 5:31:57 PM UTC-7, Elizabeth D. Rather wrote:
> The full definitions of DEFER, IS, and related words are in Forth2012,
> although they're consistent with long-standing common usage. There was
> actually discussion of standardizing them in Forth94, but the prospect
> was raised so late in the process no one had the energy to pursue it.

You didn't put DEFER or VECTOR or any such thing in ANS-Forth because you don't know what deferred words are used for.

If you knew what DEFER is used for, then why is it that ANS-Forth doesn't have any deferred words? For example, LITERAL could be deferred --- this would help make it easy to write a cross-compiler in ANS-Forth that uses the built-in outer-interpreter because LITERAL could be revectored by the HOST colon to compile the literal into the target memory rather than the host memory, and then revectored back to the default by semicolon.

lawren...@gmail.com

unread,
Jul 12, 2016, 6:32:19 PM7/12/16
to
On Friday, July 8, 2016 at 8:01:31 AM UTC+12, Alex Dowad wrote:
> With some programming languages, your code is executed as it is read. With
> others, your code is parsed in its entirety and put through multiple stages
> of (often complex) preprocessing, before execution. Forth and Lisp are
> firmly in the first category, as are all the "scripting languages". You are
> probably accustomed to languages in the second category, like C or Haskell.

What about ones which compile to some intermediate code, which is then interpreted? E.g. Perl, Java, Python. Or even good old UCSD Pascal...

Brad Eckert

unread,
Jul 12, 2016, 10:48:24 PM7/12/16
to
On Thursday, July 7, 2016 at 5:31:57 PM UTC-7, Elizabeth D. Rather wrote:
>
> The full definitions of DEFER, IS, and related words are in Forth2012,
> although they're consistent with long-standing common usage. There was
> actually discussion of standardizing them in Forth94, but the prospect
> was raised so late in the process no one had the energy to pursue it.
>

I'm only using a small subset of the DEFER standard, just for forward references in ROM. IS resolves a forward branch (similar to THEN). I can see how your example provided above could do something similar in CDATA space (a non-modifiable xt) and behave more like the classic DEFER in IDATA space.

I never got around to a full DEFER because my new favorite word for declaring execution vectors is BUFFER:. MOVE performs the function of IS.

Elizabeth D. Rather

unread,
Jul 13, 2016, 2:58:29 AM7/13/16
to
Well, sure, if a bunch of things need to be changed, like the responses
to a button panel.

DEFER/IS is mostly for single things that need to change, such as your
terminal display & keyboard.

Bernd Paysan

unread,
Aug 20, 2016, 5:40:25 PM8/20/16
to
I've done that in bigForth, there's a FORWARD <name> defining word, which
creates a forward reference each time it is compiled (a linked list).
Resolve is automatic through the actual definition, i.e. instead of
printing a warning that the word is already defined, the forward
reference is resolved.

With a primitive centric system like Gforth, this would only work for
high-level words, but that should be ok for the usual purpose.

You should do a .UNRESOLVED at the end of your program to see if all your
forward references have been successfully resolved.

Larger programs usually need forward references here and there, not too
many, but a few, and FORWARD would be handy.

The Gforth development version has a hook for doing the warning check, so
that feature could be added to Gforth; though at the moment, that check
is performed too early; I'll change that and add a loadable file for
forward references, as it is really easy to do.

.unresolved gives an example of quotations inside quotations (loop
through all wordlists, and warning code). Though no outer state is needed.

: .unresolved ( -- )
[: [: dup >namevt @ >vtcompile, @ ['] forward, = IF
dup >body @ [: dup .name ." is unresolved" cr ;] ?warning
THEN drop true ;] swap traverse-wordlist ;] map-vocs ;

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
net2o ID: kQusJzA;7*?t=uy@X}1GWr!+0qqp_Cn176t4(dQ*
http://bernd-paysan.de/

Albert van der Horst

unread,
Aug 28, 2016, 7:38:11 PM8/28/16
to
In article <npaio8$59r$2...@dont-email.me>,
Bernd Paysan <bernd....@gmx.de> wrote:
>Am Thu, 07 Jul 2016 00:12:50 -0700 schrieb JennyB:
>
>> Yes. Mutual recursion is not common, and very much a minority use case
>> for Defer ... Is.
>>
>> If I found myself doing it a lot I might be tempted to write Forward and
>> Resolve as aliases for Defer and Is just to clarify what was going on,
>> and so I could rewrite them to resolve at compile time if it turned out
>> that the speed difference between a direct and indirect call really
>> mattered.
>
>I've done that in bigForth, there's a FORWARD <name> defining word, which
>creates a forward reference each time it is compiled (a linked list).
>Resolve is automatic through the actual definition, i.e. instead of
>printing a warning that the word is already defined, the forward
>reference is resolved.
>
>With a primitive centric system like Gforth, this would only work for
>high-level words, but that should be ok for the usual purpose.
>
>You should do a .UNRESOLVED at the end of your program to see if all your
>forward references have been successfully resolved.
>
>Larger programs usually need forward references here and there, not too
>many, but a few, and FORWARD would be handy.

Within a recent largish program (flasher for MSP430) my experience
is the same. An occasional forward reference is better than
making the programs flow less logical.

Instead of separate words I've "almost:" words. This is how it works
for mutual recursion.
:F xxx ; \ Forward reference
: zzz ... xxx ... ;
:R xxx ... zzz ... ; \ Resolve refence, no message.

This makes it directly clear that it is only for high level code,
not assembler words, not created data structures.
Of course in an indirect threaded Forth this is easy.


>
>The Gforth development version has a hook for doing the warning check, so
>that feature could be added to Gforth; though at the moment, that check
>is performed too early; I'll change that and add a loadable file for
>forward references, as it is really easy to do.
>
>.unresolved gives an example of quotations inside quotations (loop
>through all wordlists, and warning code). Though no outer state is needed.
>
>: .unresolved ( -- )
> [: [: dup >namevt @ >vtcompile, @ ['] forward, = IF
> dup >body @ [: dup .name ." is unresolved" cr ;] ?warning
> THEN drop true ;] swap traverse-wordlist ;] map-vocs ;
>

If I bothered to do error detection, I'd do an exception in :F .
This would result in run time errors, probably good enough.


>--
>Bernd Paysan
>"If you want it done right, you have to do it yourself"
>net2o ID: kQusJzA;7*?t=uy@X}1GWr!+0qqp_Cn176t4(dQ*
>http://bernd-paysan.de/
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

0 new messages