# Copyright (C) 2005, The Perl Foundation.
# $Id: pdd21_namespaces.pod 12839 2006-05-30 14:34:31Z coke $

=head1 NAME

docs/pdds/pdd21_namespaces.pod - Parrot Namespaces

=head1 VERSION

$Revision: 12839 $

=head1 DESCRIPTION

=over 4

=item - Namespaces should be stored under first-level namespaces corresponding
to the HLL language name

=item - Namespaces should be hierarchical

=item - Add a get_namespace opcode (that takes an array or a multidimensional
hash index)

=item - Namespaces follow the semantics of the HLL in which they're defined

=item - exports follow the semantics of the library's language

=item - Two interfaces: typed and generic

=back

=head1 DEFINITIONS

=head2 "HLL"

A High Level Language, such as Perl, Python, or Tcl, in contrast to PIR, which
is a low-class language.

=head2 "current namespace"

The I<current namespace> at runtime is the namespace associated with the
currently executing subroutine.  Pasm assigns each subroutine a namespace when
compilation of the subroutine begins.  Don't change the associated namespace
of a subroutine unless you're prepared for weird consequences.

(Pasm also has its own separate concept of current namespace which is used to
initialize the runtime current namespace as well as determine where to store
compiled symbols.)

=head2 namespace indexing syntax

Namespaces are denoted in Parrot as either simple strings or (potentially)
multimentional hash keys.

A non-nested namespace may appear in Parrot source code as the string
C<"a"> or the key C<["a"]>.

A nested namespace "b" inside the namespace "a" will appear as the key
C<["a"; "b"]>.

(There is no limit to namespace nesting.)

=head1 IMPLEMENTATION

=head2 Namespace PMC API

There are many different ways to implement a namespace and Parrot's target
languages display a wide variety of them.  By implementing an API, it should
be possible to allow interoperability while still allowing each one choose the
best internal representation.

=head3 Naming Conventions

=over 4

=item HLL Root Namespaces

Each HLL must store public items in a namespace named with the lowercased
name of the HLL.  This is the HLL root namespace.  For instance, Tcl's user-
created namespaces should live in the C<tcl> namespace.  This eliminates any
accidental collisions between languages.

This namespace must be stored at the first level in parrot's namespace
hierarchy.  These top-level namespaces should also be specified in a standard
unicode encoding.  The reasons for these restrictions is to allow compilers
to remain completely ignorant of each other.

=item True Root Namespace

The true root namespace is available only via introspection with the
C<interpinfo> opcode, e.g. C<$P0 = interpinfo .INTERPINFO_NAMESPACE_ROOT>.

=item HLL Implementation Namespaces

Each HLL must store implementation internals (private items) in a namespace
named with an underscore and the lowercased name of the HLL.  For instance,
Tcl's implementation internals should live in the C<_tcl> namespace.

=item HLL User-Created Namespaces

Each HLL must store all user-created namespaces under the HLL root namespace.
It is suggested that HLLs use hierarchical namespaces to the extent
practical.  A single flat namespace can be made to work, but it complicates
symbol exportation.

=back

=head3 Namespace PMC Interfaces: Generic and Typed

Most languages leave their symbols plain, which makes lookups quite
straightforward.  Others use sigils or other mangling techniques, complicating
the problem of interoperability.

Parrot namespaces assist with interoperability by providing two interface
subsets: the I<raw interface> and the I<typed interface>.

=head4 Raw Interface

Each HLL may, when working with its own namespace objects, use the I<raw
interface>, which allows direct naming in the native style of the namespace's
HLL.

This interface consists of standard Parrot hash interface, with all its keys,
values, lookups, deletions, etc.  Just treat the namespace like a hash.  (It
probably is one, really, deep down.)

It's kind of an anticlimax, isn't it, giving a fancy name like "raw interface"
to a hash?  "It's a just a hash," you say.  Oh well.  I'll try to live with
the shame.

=head4 Typed Interface

When a given namespace's HLL is either different from the current HLL or
unknown, an HLL should generally use only the language-agnostic namespace
interface.  This interface isolates HLLs from each others' naming quirks.  It
consists of add_foo(), find_foo(), and del_foo() methods, for values of "foo"
including "sub" (something executable), "namespace" (something in which to
find more names), and "var" (anything).

NOTE: The job of the typed interface is to bridge I<naming> differences, and
I<only> naming differences.  Therefore:

(1) It does not enforce, nor even notice, the interface requirements of "sub"
or "namespace": e.g. execution of add_sub("foo", $P0) does I<not>
automatically guarantee that $P0 is an invokable subroutine; and: (2) It does
not prevent overwriting one type with another

=over 4

=item add_namespace($S0, $P0)

Store $P0 as a namespace under the name of $S0.

=item add_sub($S0, $P0)

Store $P0 as a subroutine with the name of $S0.

=item add_var($S0, $P0)

Store $P0 as a variable under the name of $S0.

IMPLEMENTATION NOTE: Perl namespace implementations may choose to implement
add_var() by checking what which parts of the variable interface are
implemented by $P0 (scalar, array, and/or hash) so it can decide on an
appropriate sigil.

=item del_namespace($S0)

=item del_sub($S0)

=item del_var($S0)

Delete the sub, namespace, or variable named $S0.

=item $P0 = find_namespace($S0)

=item $P0 = find_sub($S0)

=item $P0 = find_var($S0)

Find the sub, namespace, or variable named $S0.

IMPLEMENTATION NOTE: Perl namespace implementations should implement
find_var() to check all variable sigils, but the order is not to be counted on
by users.  If you're planning to let Python code see your module, you should
avoid exporting both C<our $A> and C<our @A>.  (Well, you might want to
consider not exporting variables at all, but that's a style issue.)

=item export_to($P0, $P1)

Export items from the current namespace into the namespace in $P0.  The items
to export are named in the array $P1; a null $P1 requests the 'default' set of
items.  The interpretation of the array in $P1 always follows the conventions
of the source (exporting) namespace.

The base Parrot namespace export_to() function interprets item names as
literals -- no wildcards or other special meaning.  There is no default list
of items to export, so $P1 of null and $P1 of an empty array have the same
behavior.

NOTE: Exportation may entail non-obvious, odd, or even mischievious behavior.
For example, Perl's pragmata are implemented as exports, and they don't
actually export anything.

IMPLEMENTATION EXAMPLES: Suppose a Perl program were to import some Tcl module
with an import pattern of "c*" -- something that might be expressed in Perl 6
as C<use tcl:Some::Module 'c*'>.  This operation would import all the commands
that start with 'c' from the given Tcl namespace into the current Perl
namespace.  This is so because, regardless of whether 'c*' is a Perl 6 style
export pattern, it I<is> a valid Tcl export pattern.

{XXX - Is the ':' for HLL approved or just proposed?  Somebody familiar with
Perl 6 please fix the example in the preceding paragraph to use the currently
planned syntax for importing modules from other languages.}

IMPLEMENTATION NOTE: Most namespace export_to implementations will restrict
themselves to using the typed interface on the target namespace.  However,
they may also decide to check the type of the target namespace and, if it
turns out to be of a compatible type, to use same-language shortcuts.

DESIGN TODO: Figure out a good convention for a default export list in the
base namespace PMC.  Maybe a standard method "expand_export_list()"?

=back

=head3 Non-interface Methods

These methods don't belong to either the typed or the generic interface.

=over 4

=item $P0 = get_name()

Gets the name of the namespace as an array of strings.  For example, if the
current language is Perl 5 and the current Perl 5 namespace is "Some::Module"
(that's Perl 5 syntax), then get_name() on that namespace returns an array of
"perl5", "Some", "Module".

NOTE: Due to aliasing, this value may be wrong, even if nobody's been playing
around with it.

=back

=head2 Compiler PMC API

=head3 Methods

=over 4

=item get_namespace($P0)

Ask this compiler to find its namespace named by the elements of the array in
$P0.  Returns namespace PMC on success and null PMC on failure.  Note that a
null PMC or an empty array requests the HLL's base namespace.

This method allows other HLLs to know one name (the HLL) and then work with
that HLL's modules without having to know the name it chose for its namespace
tree.  (If you really want to know the name, the name() method should work on
the returned namespace PMC.)

Note that this method is basically a convenience and/or performance hack, as
it does the equivalent of C<interpinfo .INTERPINFO_NAMESPACE_ROOT> followed by
zero or more calls to <namespace>.find_namespace().  However, any compiler is
free to cheat if it doesn't get caught, e.g. to use the untyped namespace
interface if the language doesn't mangle namespace names.

=item load_library($P0, $P1)

Ask this compiler to load a library/module named by the elements of the array
in $P0, with optional control information in $P1.

For example, Perl 5's module named "Some::Module" should be loaded using (in
pseudo Perl 6): C<perl5.load_library(["Some", "Module"], null)>.

The meaning of $P1 is compiler-specific.  The only universal legal value is
Null, which requests a "normal" load.  The meaning of "normal" varies, but
the ideal would be to perform only the minimal actions required.

On failure, an exception is thrown.  {XXX - I'd settle for a universal error
pmc interface.  Hm, sounds like a new pdd.  >>TODO}

=back

=head2 Subroutine PMC API

Some information must be available about subroutines to implement the correct
behavior about namespaces.

=head3 Methods

=over 4

=item get_namespace

The namespace where the subroutine was defined. (As opposed to namespace(s)
that it may have been exported to.)

=back

=head2 Namespace Opcodes

Note that all namespace opcodes operate from the local HLL root namespace.
Navigating outside one's own HLL namespace requires either the C<interpinfo
.INTERPINFO_NAMESPACE_ROOT> opcode or the get_namespace() compiler PMC method.

=over 4

=item add_namespace $P0, $P1

Add the namespace PMC $P1 as the namespace $P0 (an array of names or a 
multidimensional hash index).

=item del_namespace $P0

Delete the namespace $P0 (an array of names or a multidimensional hash index).

=item $P0 = find_global $P1, $S0

=item $P0 = find_global $S0

Find $P0 as the variable $S0 in the current namespace. or in $P1, relative
to the HLL root namespace.

=item $P0 = get_namespace $P1

=item $P0 = get_namespace

Get the namespace $P1 (an array of names or a multidimensional hash index) or
the current namespace.  To get the "Foo::Bar" namespace, one would use this:

  $P0 = split "::", "Foo::Bar"
  $P1 = get_namespace $P0

or this:

  $P1 = get_namespace ["Foo"; "Bar"]

=item store_global $P1, $S0, $P0

=item store_global $S0, $P0

Store $P0 as the variable $S0 in the current namespace, or in $P1, relative
to the HLL root namespace.

=back

=head2 HLL Namespace Mapping

In order to make this work, Parrot must somehow figure out what type of
namespace PMC to create.

=head3 Default Namespace

The default namespace PMC will implement Parrot's current behavior.

=head3 Compile-time Creation

This perl:

  #!/usr/bin/perl
  package Foo;
  $x = 5;

should map roughly to this PIR:

  .HLL "Perl5", "perl5_group"
  .namespace [ "Foo" ]
  .sub main :main
    $P0 = new .PerlInt
    $P0 = 5
    store_global "$x", $P0
  .end

In this case, the C<main> sub would be tied to Perl5 by the C<.HLL> directive,
so a Perl5 namespace would be created.

=head3 Run-time Creation

Consider the following Perl5 program:

  #!/usr/bin/perl
  $a = 'x';
  ${"Foo::$a"} = 5;

The Foo:: namespace is created at run-time (without any optimizations).  In
these cases, Parrot should create the namespace based on the HLL of the PIR
subroutine that calls the store function.

  .HLL "Perl5", "perl5_group"
  .sub main :main
    # $a = 'x';
    $P0 = new .PerlString
    $P0 = "x"
    store_global "$a", a
    # ${"Foo::$a"} = 5;
    $P1 = new PerlString
    $P1 = "Foo::"
    $P1 .= $P0
    $S0 = $P1
    $P2 = split "::", $S0
    $S0 = pop $P2
    $S0 = "$" . $S0
    $P3 = new .PerlInt
    $P3 = 5
    store_global $P2, $S0, $P3
  .end

In this case, C<store_global> should see that it was called from "main", which
is in a Perl5 namespace, so it will create the "Foo" namespace as a Perl5
namespace.

=head1 LANGUAGE NOTES

=head2 Perl 6

=head3 Sigils

Perl6 may wish to be able to access the namespace as a hash with sigils.  That
is certainly possible, even with subroutines and methods.  It's not important
that a HLL use the typed namespace API, it is only important that it provides
it for others to use.

So Perl6 may implement get_keyed and set_keyed VTABLE slots that allow the
namespace PMC to be used as a hash.  The C<find_sub> method would, in this
case, would append a "&" sigil to the front of the sub/method name and search
in the internal hash.

=head2 Python

=head3 Importing from Python

Since functions and variables overlap in Python's namespaces, when exporting
to another HLL's namespace, the Python namespace PMC's C<export_to> method
should use introspection to determine whether C<x> should be added using
C<add_var> or C<add_sub>.  C<$I0 = does $P0, "Sub"> may be enough to decide
correctly.

=head3 Subroutines and Namespaces

Since Python's subroutines and namespaces are just variables (the namespace
collides there), the Python PMC's C<find_var> method may return subroutines as
variables.


=head2 Examples

=head3 Aliasing

Perl:

  #!/usr/bin/perl6
  sub foo {...}
  %Foo::{"&bar"} = &foo;

PIR:

  .sub main :main
    $P0 = find_name "&foo"
    $P1 = get_namespace ["Foo"]

    # A smart perl6 compiler would emit this,
    # because it knows that Foo is a perl6 namespace:
    $P1["&bar"] = $P0

    # But a naive perl6 compiler would emit this:
    $P1.add_sub("bar", $P0)

  .end

  .sub foo
    ...
  .end

=head3 Cross-language Exportation

Perl5:

  #!/usr/bin/perl
  use tcl:Some::Module 'w*';   # XXX - is ':' after HLL standard Perl 6?
  write("this is a tcl command");

PIR (without error checking):

  .sub main :main
    .local pmc tcl
    .local pmc ns
    tcl = compreg "tcl"
    ns = new .Array
    ns = 2
    ns[0] = "Some"
    ns[1] = "Module"
    null $P0
    tcl.load_library(ns, $P0)
    $P0 = tcl.get_namespace(ns)
    $P1 = get_namespace
    $P0.export_to($P1, 'w*')
    "write"("this is a tcl command")
  .end

=head1 ATTACHMENTS

None.

=head1 FOOTNOTES

None.

=head1 REFERENCES

None.

=cut

__END__
Local Variables:
  fill-column:78
End:
