6.2.2395 UNUSED CORE EXT

( -- u )

u is the amount of space remaining in the region addressed by HERE, in address units.

ContributeContributions

EricBlakeavatar of EricBlake [383] What should the behavior be if the system has no hard-coded limit on size?Request for clarification2025-07-19 01:57:17

On a system where the data space grows dynamically, there is no inherent compile-time limit on the maximum address in data space, and there might be no easy way to probe at runtime how large of an address can be allocated without failure. In that scenario, is it better to include the word UNUSED and have it return -1 to indicate unknown (or rather, the maximum unsigned integer since the prototype uses 'u'), or to omit the word UNUSED from the core extension set? Some traditional systems had MORECORE for adding more storage to the data space when UNUSED indicated that the current space was insufficient, but MORECORE is not standardized.

AntonErtlavatar of AntonErtl

If you include unused, it has to provide the size of the remaining dictionary (here region) space. Returning the maxiumum unsigned value (what -1 becomes if you interpret it as unsigned) is probably wrong: unused allot should work.

Letting unused report less than might actually be allotable is not according to the specification, either, but I don't see how a standard program that uses unused would run into problems from that. At worst it uses less memory than would otherwise be available.

Finally, not implementing unused avoids the problem completely, but programs that use unused will not work out of the box. I don't think there are many such programs, however.

Closed

ruvavatar of ruv

is it better to include the word UNUSED and have it return -1 to indicate unknown (or rather, the maximum unsigned integer since the prototype uses u), or to omit the word UNUSED from the core extension set?

Of these two options, it is better to omit unused, since this word has type ( -- u ) and so it cannot return -1.

The program interprets the result of unused as an unsigned number, and the system must ensure that the corresponding amount of memory can be reserved in one or more subsequent calls to allot. Note that allot has type ( n -- ), and it reserves memory if n > 0, and releases memory if n < 0.

Thus, the system should pass the following testcase:

: u/ ( u u\0 -- u ) 0 swap um/mod nip ;

s" MAX-N" environment? invert [if] -1 2 u/ 1 - [then]
constant largest-n

: reserve ( u -- )
  dup largest-n u< if ( +n )        allot exit then  dup 2 u/  dup recurse  - recurse
;
: release ( u -- )
  dup largest-n u< if ( +n ) negate allot exit then  dup 2 u/  dup recurse  - recurse
;

t{ here unused  2dup reserve here swap - over =  over release  ->  here unused true }t

Regarding unused and dynamic memory or unknown memory size. An alternative option is to provide a specific (possible configured) amount of memory, which can be reserved with allot, and update the available memory on creating a definition.

An example (derived from my another comment):

\ private

2variable dictspace-dp \ the data pointer and border
: assume-dictspace ( addr u -- ) over + swap dictspace-dp 2! ;

\ public

: unused  ( -- u    ) dictspace-dp 2@ - ;
: here    ( -- addr ) dictspace-dp @    ;
: allot   ( n --    ) dictspace-dp +!   ;

\ private

500 1024 * constant dictspace-unused-initial
1   1024 * constant dictspace-unused-low

: ensure-dictspace-reservation ( -- )
  unused dictspace-unused-low u> if exit then
  dictspace-unused-initial  dup allocate throw  swap  assume-dictspace
;

\ initialization
0 0 assume-dictspace ensure-dictspace-reservation

\ public

: ; ( colon-sys -- )  postpone ;  ensure-dictspace-reservation  ; immediate

I think, a standard Forth system is allowed to provide such an implementation.

Reply New Version