# Namespaces

Namespaces provided by [lib/ns.fs] are a convenient way to manage sets of
conflicting words. For example, assemblers often have the same mnemonics, so
loading two assemblers in the global namespaces makes the first one unusable.
Namespaces to the rescue!

  : foo 54 ;
  ns[ MyNS
    : foo 42 ;
  ]ns
  foo . \ Prints 54
  MyNS foo . \ Prints 42

In the example above, the second "foo" exists only in the namespace "MyNS" and
can be invoked my calling MyNS followed by the target word in the namespace.

The "ns[ ( -- blkctx )" word creates a new namespace with the specified name and
then "enters" it, that is, it replaces the current context (CURCONTEXT) with its
own context, the one it just created by forking the current context.

When you're "inside" a namespace, you do your stuff like you would normally. You
can load files with f<<, no problem. When you're ready to exit the namespace,
you call "]ns ( bkpctx -- )". When you do so, you need to have PS at the same
level as your "enter" level so that "bkpctx" (taken from CURCONTEXT at "enter"
time) can be properly restored.

And you know why that is? Because namespaces are nestable!

  ns[ MyNS
    : foo 42 ;
    ns[ Nested
      : foo 54 ;
    ]ns
    foo . \ Prints 42
    Nested foo . \ Prints 54
  ]ns
  MyNS Nested foo . \ Prints 54

Therefore, "]ns" doesn't always return to the system context.

You can "extend" an existing context with the word "extends". An extended
context is the same thing as a nested context except that its name live in the
parent context:

  ns[ MyNS
    : foo 42 ;
    : bar 123 ;
  ]ns
  extends MyNS ns[ Extended
    : foo 54 ;
  ]ns
  Extended foo . \ Prints 54
  MyNS foo . \ Prints 42
  Extended bar . \ Prints 123

You can also "enter" a namespace after it's been created. It's done with the
"intons[ ( "name" -- bkpctx )" word. You leave with "]ns":

  ns[ MyNS
    : foo 42 ;
  ]ns
  intons[ MyNS
    foo . \ Prints 42
    : bar 54 ;
  ]ns
  MyNS bar . \ Prints 54

Namespace accesses work as you'd expect in compiled words. If you need the
address of a word in a particular namespace, you can use "ns'" and "[ns']", the
equivalent to "'" and "[']":

  ns[ MyNS
    : foo 42 ;
  ]ns
  : cfoo MyNS foo . ;
  cfoo \ Prints 42
  ns' MyNS foo execute . \ Prints 42
  : cfoo [ns'] MyNS foo execute . ;
  cfoo \ Prints 42

## Structures

We call "structures" (or "struct") namespaces that contains moustaches
[doc/lib/bm] that are offsets relative to PS top.

Many of such structures extend one another. For moustaches to pick up where the
other left off, it's a common pattern to create a "SZ" constant in the
namespace.

  ns[ MyStruct
    create{}   foo
    create{++} bar
    0 @{&++} const SZ
  ]ns
  extends MyStruct ns[ ExtStruct
    create{+SZ} baz
    0 @{&++} const SZ
  ]ns

When a structure extends another, it's common practice for the extending struct
to call its base struct's ":new" word and add to it.

Structures often include methods and initializing those can be done by
piggy-backing on method{}s ability to be "moustache-recalled" with ">".

  ns[ MyAbstract
    createmethod{} :foo
    0 @{&++} const SZ
    : :new ( -- self ) here# ['] abort , ;
  ]ns
  extends MyAbstract ns[ MyImpl
    create{+SZ} myfield
    : impl drop 42 ;
    :override :new ( -- self )
      ~ ( self ) 54 , ['] impl over !{>:foo} ;
  ]ns
  MyImpl :new dup :foo . \ prints 42
  myfield . \ prints 54

":override", as you can see in [doc/usage/word], makes "~" the equivalent of
typing "MyAbstract :new".

## Namespaces API

ns[      ( "name" -- bkpctx )
  Creates a new namespace "name" and enters it.
]ns      ( bkpctx -- )
  Restores the context that was active before the previous "enter".
extends  ( "name" -- )
  The next "ns[" call will fork namespace "name" instead of forking the current
  context.
intons[  ( "name" -- bkpctx )
  Enter a namespace.
nsfind   ( 'ns "name" -- w )
  Find a word "name" in namespace "'ns". Aborts if not found.
ns'      ( "nsname" "name" -- w )
  Find a word "name" in namespace "nsname". Aborts if not found.
[ns']    ( "nsname" "name" -- ) *I*
  Find a word "name" in namespace "nsname" and then compile the address.
  Aborts if not found.
[ns]     ( "nsname" -- ) *I*
  Find namespace "nsname" and compile its address.
[nsdict] ( "nsname" -- ) *I*
  Find namespace "nsname" and compile the address of its dictionary.
nabort,  ( n -- )
  Write address of word "abort" n times.
