<< Home | About Forth | About TurboForth | Download | Language Reference | Resources | Tutorials | YouTube >>


Applications Support

For Alea

TurboForth currently does not support vocabularies, as found in many other Forth systems. If one is loading single applications into memory this is rarely an issue. However, if one wishes to load multiple applications into memory, or applications, and say, a shared library (that the applications themselves utilise) there is a potential for name collisions, since all definitions, of all types share the same dictionary.

The following provides a solution to the issue. The following code (see bottom of article) introduces the concept of "applications". All words within an application are private. They cannot be seen by words that are outside of the application. The developer of an application can 'expose' certain words to the outside world, effectively making those words global.

It is very useful to be able to hide the low-level implementation details of applications. When an application is loaded into memory, typing WORDS can lead to screen-fuls of words being displayed, and it is not clear which words are internal to the application, and which words are the "public interface" side of the application. Indeed, it is impossible to tell which words belong to which application! Applications Support solves that problem. It allows the internal workings of an application to be hidden from WORDS, and indeed the dictionary overall, such that only the words that the application developer has explicitly chosen to expose are visible. This of course also vastly reduces the risk of name collisions.

Example of Usage:

  application: fred
    : test1 ( -- n ) 123 ;
    : test2 ( -- n ) 456 ;
    : test3 ( -- n ) 789 ;
    : start ( -- n1 n2 n3 ) test1 test2 test3 ; entry-point
  end-application

In the above example, test1, test2, test3, and indeed start are not visible to words outside of the application called fred. It is not possible to refer to them outside of the application itself. They are private to the application.

Entry Points

Note that in the example shown above, the word start has been marked as the ENTRY-POINT. This is useful where it is desirable to wrap an entire application up and expose a single word as the entry-point to the application (a game, for example). When a word is marked as the entry-point the word is linked to name of the application, such that referencing the name of the application causes the nominated entry-point to execute. Therefore, in the above example, fred inherits the stack signature of start, and executing or referencing fred shall cause start to be executed. In turn, start subsequently executes the private words test1, test2, and test3. In fact, it should be noted that start itself cannot be directly executed, because it is private by default, just like test1, test2, and test3. In this particular case, the only way to execute the application is via the name of the application.

Only one word should be defined as the entry-point. If more than one word is marked as the entry-point, the previously so marked word shall revert to private, and the last so marked word shall become the entry-point.

Note that the name of the application is (obviously) globally accessible and is a "normal" (i.e. non-immediate) word, and may be compiled into definitions either directly or indirectly (i.e. defining words) without complication.

Default Entry Point

When an application is defined, a default entry-point word is automatically assigned (noEntry), until such time as it is overridden with ENTRY-POINT. The run-time action of this default word is to abort with the message "Error: No application entry-point defined." When the application is closed (with END-APPLICATION) a check is performed. If the default entry-point word has not been overridden, an error message is issued. This is the only sensible course of action, since, at this point, the programmer has neglected to associate his application with an entry point!

Making Words Public (Defining the Public Interface)

It is of course possible to expose other words in the application to the outside world, not just the entry-point. This is very useful for library development; it allows the 'public facing' words (the interface) to be exposed to the outside world, and allows the inner words (the implementation) to be hidden. Use the EXPOSE keyword to expose a word, as shown in the following example:

   application: string_lib ( t/f -- ) 
     256 constant stack_size
     variable stack_pointer
     create string_stack stack_size allot \ reserve stack space
     string_stack stack_pointer ! \ init stack pointer
   
     : $depth ( -- depth ) ... ... ... ... ... ;
     : 2strings ( -- ) $depth 2 < abort" Need two strings!" ;
   
     : do_setup ( t/f -- ) ... ... ... ... ; entry-point
     : dup$ ( -- ) 2strings? ... ... ... ... ;
     : swap$ ( -- ) 2strings? .. .. ... ... ;
   
     \ the following words shall be made public
     expose dup$
     expose swap$
   end-application

The words dup$ and swap$ are exposed, and are therefore public/global in scope; they can be accessed from anywhere, including (of course) other Applications.

Note that stack_size, stack_pointer, string_stack, $depth and 2strings? are not exposed, and are therefore private to the application; they may not be referenced outside of the application in which they are defined.

Important Note Regarding Word Exposure

It is important that the words are exposed in the order in which they are compiled. In the above example, if swap$ were exposed before dup$ then dup$ would become "linked out" of the dictionary, and thus not be found.

Application Stack Signature

In the above example, do_setup is marked as the entry-point of the application/library. Note that, as described above, despite being marked as the entry-point, it is in fact a private word and cannot be referenced outside of the application. The application is in fact launched via the application name, in this case string_lib which is effectively a delegate for do_setup. Because string_lib is a delegate of do_setup, it is recommended to duplicate the stack signature of the entry-point at the definition of the application, as shown above in green.

Implementation Code

The following code implements the functionality described above:

19th October 2014


<< Home | About Forth | About TurboForth | Download | Language Reference | Resources | Tutorials | YouTube >>