Oforth Tutorial 2b : Packages and namespaces

I - Packages

Packages allow to regroup a list of files to be loaded to implement a global functionality.

A package is implemented as a file with name packageName.pkg

In order to be loaded, this file must be present into one of the directories of OFORTH_PATH environnement variable (or into a pack directory included one of them).

This file is an Oforth source that pushes 2 lists on the stack : package signature and the list of package file names.

// ****************************************************************************
// TCP package signature
// ****************************************************************************
[
[ $name, "tcp" ],
[ $version, "V0.9.0" ],
[ $state, $NotStable ],
[ $directory, "tcp" ],
[ $dependencies, [ ] ],
[ $author, "Franck Bensusan" ],
[ $contributors, [ ] ],
[ $url, "www.oforth.com" ],
[ $license, "BSD" ]
]

// ****************************************************************************
// TCP files
// ****************************************************************************
[ "TcpConnection.of", "TcpRequest.of", "TcpServer.of" ]


The most important field of a package signature is $directory. This directory is the location of package files.

For instance, if tcp.pkg file has been found into /home/oforth/pack directory, then the 3 files should be located into /home/oforth/pack/tcp

Package files loading order is the order of their declaration into the package file list.

Packages themselves are words, like functions, classes, ... So a package can't have the same name than another word.

II - Namespaces

All packages are loaded into their own namespace, in order to avoid name conflits : 1 package = 1 namespace.

At anytime, the system has a current namespace and all words are created into this package. When a package is loaded, the current namespace is set to this package name, files are loaded and definitions are created into this namespace. Then the current namespace is set back to its previous value.

Two differents words can have the same name into two different packages.

>#dup package .
oforth ok
>#apply package .
lang ok


A word can be fully qualified by prefixing its name with its package :

12 oforth:dup .s
[1] (Integer) 12
[2] (Integer) 12
>12 lang:dup
[1:interpreter] ExCompiler : Can't evaluate


#dup is declared into oforth package, not into lang package.


At Oforth startup :

1) Package oforth is created and current package is set to "oforth" package.

2) Built-in words are created into oforth package.

3) Package lang is imported into oforth package (see importing packages).

4) After lang has been loaded, system is operationnel and current package is "oforth".


Two functions are available to load a package :

use: package
import: package


III - Use a package

Using a package allows to load all package files into their own namespace. Package words must be qualified to be used, ie all words must be prefixed by the package name.

When you use a package (from oforth package or another package) :

- If the package has already been loaded into the system, do nothing and returns.

- The package word is created into oforth package.

- The current package is now set to this package.

- The package is loaded : all package files are loaded and words are created into this new namespace.

- The current package is set back to its previous value.


So, in order to use words created into this package form outside, names must be qualified :

packageName:word


It is possible to create an alias for a particular word of a used package :

#packageName:word alias: myWord


myWord is now created as an alias of packageName:word into the current package.

Example : Uses package tcp and creates an alias for a word created into tcp package :

use: tcp
ok
>TcpRequest .
[1:interpreter] ExCompiler : Can't evaluate
>tcp:TcpRequest .s
[1] (Class) TcpRequest
ok
>#tcp:TcpRequest alias: TcpRequest
ok
>TcpRequest .s
[1] (Class) TcpRequest
ok
>


IV - Import a package

All packages have a list of imported packages. This list is used when searching for a non qualified word (see search order). This allows to use words declared into an imported package as if they were declared into the current package (ie non qualified).

When you import a package :

- "use: package" is run

- If the package is not into the current package list of imported packages, it is added to the list.

Example :

import: tcp
ok
>TcpRequest .s
[1] (Class) TcpRequest
ok
>#TcpRequest package .
tcp ok


V - Search order for words

Each time a word is searched (by the interpreter, using # or using #find), the search order is :

- If the word is qualified, search only into the qualified package and returns

- If the word is non qualified :

  • Search the word into the current package.
  • Otherwise, search into imported packages of current package.
  • Otherwise, search into oforth package.
  • Otherwise, search into imported packages of oforth package.

  • Consequences :

    1) Non qualified words are searched into imported packages of current package but not into imported packages of those packages. If needed, they must be imported too.

    2) Words declared into packages imported into oforth package are available into all packages even if these word are not qualified.

    3) There is no conflict error when a non qualified word is used and has a name declared more than once. The first word found using the previous search order will be used.



    Franck

    Oforth Documentation

    Current available documentation :

    I - Tutorials

    • Oforth basics : here
    • Oforth syntax : here
    • Writing Oforth programs : here
    • Oforth classes : here
    • Oforth parallelism : here
    • Oforth node : Work in progress...

    II - Reference

    • Lang package reference : here