1. LANGUAGES AND NAMESPACES In my previous messages, I was concerned that languages were being shoehorned too tightly into their own namespaces.
But after a careful reading about "import_into", I am happy that each language has sufficient ability to insert its symbols into the namespace of another language (when asked to in the proper way, of course). So I retract the concerns that I expressed. But I still find the intent of the spec unclear here: - Languages should contain their namespaces because the "add_namespace" opcode seems to allow arbitrary namespaces to be created. Maybe the strongest thing we can say is: - All namespaces are organized under first-level namespaces whose names will typically correspond to HLL names If the intention is to say anything stronger, then we must say from _where_ the first-level namespace names are derived. 2. TYPED INTERFACE I assume it's an error that both "add_var($S0, $P0)" and "store_var($S0, $P0)" are listed in the typed interface API for namespaces. I assume that "add_var" is the intended name. 3. "name()" METHOD The example suggests that perl5:Some::Module would return an array containing "Some", "Module". Instead, don't we want it to return "perl5", "Some", "Module" to match the params required by the "get_namespace" opcode? If not, then we need some other way to get the language name. 4. LANGUAGES AND COMPILERS There are at least four notions of "Language" here: (1) The language named in the .HLL directive. (2) The name registered with "compreg". (3) The name of the first-level namespace. (4) The programming language in which the source code was originally written. Presumably we can ignore (4) because, by the time the code is compiled, Parrot doesn't know or care what the original language was. Of the other three, which of them are necessarily the same? If (3) must be the same as (1) and/or (2), then we probably cannot force (3) to be all-lowercase unless we force the others to be all-lowercase too. 5. THE FINAL EXAMPLE In the final example, what is the purpose of this line: add_namespace ["perl5"; "Some"; "Module"], $P1 As far as I can tell, the intent of the following line is to import tcl:Some::Module 'w*' into the _current_ perl namespace, not into ["perl5"; "Some"; "Module"]. Am I missing the point here? Regards, Roger Browne > - Namespaces should be hierarchical > - Add a get_namespace opcode (that takes an array or a multidimensional > hash index) > - Namespaces follow the semantics of the HLL in which they're defined > - Imports follow the semantics of the library's language > - Two interfaces: typed and generic > > 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. > > Definitions > HLL A High Level Language, such as Perl, Python, or Tcl. This is in > contrast to PIR. > > Current namespace > The current namespace is the namespace associated with the currently > executing subroutine. > > Naming Conventions > For interoperability, languages should use hierarchical namespaces. > There's no way to outlaw flat namespaces, of course, and that remains an > option for language implementors, but a standard must be chosen for easy > interoperability, and hierarchical seems to be the better choice. > > HLL Private Namespaces > HLLs should use a namespace with an underscore and the lowercased > name of the HLL to store any private items. For instance, Tcl should > use the "_tcl" namespace to store the subroutines that make up the > compiler. > > User Defined Namespaces > All HLLs should prefix any namespaces with the lowercased name of > the HLL (so there's no question of what to capitalize). So Perl 5's > CGI module should be stored under perl5::CGI. This eliminates any > accidental collisions between languages. > > 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 *raw interface* and the *typed interface*. > > Raw Interface > Each HLL may, when working with its own namespace objects, use the *raw > interface*, which allows direct naming in the native style of the > namespace's HLL. This interface consists of the following methods: > > TODO: Decide whether this is best exposed by "does hash". > > add($S0, $P0) > Store the PMC in $P0 under the raw name $S0. > > del($S0) > Delete the entry named $S0. > > $P0 = find($S0) > Find the sub, namespace, or variable named $S0. Return a null PMC on > lookup failure. > > $P0 = names() > Get an array of the names contained in the namespace. > > NOTE: The return value may be a psuedo-array holding a reference to > the namespace and some kind of internal iterator. > > 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 *naming* differences, > and *only* naming differences. It does not enforce, nor even notice, the > interface requirements of "sub" or "namespace". Thus, for example, > successful execution of add_sub("foo", $P0) does *not* automatically > guarantee that $P0 is an invokable subroutine. Caveat usor. > > add_sub($S0, $P0) > Store $P0 as a subroutine with the name of $S0. > > add_namespace($S0, $P0) > Store $P0 as a sub-namespace with the name of $S0. Note that to add > Bar::Baz to the Foo namespace, one must add Bar to Foo and then Baz > to Foo::Bar. > > add_var($S0, $P0) > Store $P0 as a variable under the name of $S0. > > IMPLEMENTATION NOTE: perl6::namespace.add_var may choose to check > which parts of the variable interface are implemented by $P0 so it > can decide on an appropriate sigil. > > del_sub($S0) > del_namespace($S0) > del_var($S0) > Delete the sub, namespace, or variable named $S0. > > $P0 = find_sub($S0) > $P0 = find_namespace($S0) > $P0 = find_var($S0) > Find the sub, namespace, or variable named $S0. > > IMPLEMENTATION NOTE: perl6::namespace.find_var should 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, don't have both > "our $A" and "our @A". > > $P0 = subs() > $P0 = namespaces() > $P0 = vars() > Get an array of the subs, namespaces, or variables in the namespace. > > import_into($P0, ...) > Import items from the current namespace into the namespace in $P0. > The namespace may choose to take any number of arguments for the > import routine, such as the name of subroutines, patterns, or tags. > These always follow the conventions of the callee and not the > caller. > > This aligns with the behavior that users will expect, so that `use > tcl:Some::Module 'c*'` will DTRT and import all the commands that > start with 'c' from the Tcl namespace into the Perl namespace. > > IMPLEMENTATION NOTE: Most namespace import_into 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. > > store_var($S0, $P0) > Store the variable $P0 under the name $S0. > > Non-interface Methods > These methods don't belong to either the typed or the generic interface. > > $P0 = name() > Returns the name of the namespace as an array of strings. So > perl5:Some::Module would return an array containing "Some", > "Module". > > NOTE: This is a naive method. It does not account for any aliasing. > > Class PMC API > Class should inherit from the Namespace PMC. > > Methods > add_method($S0, $P0) > Add a method $P0 under the name $S0. > > del_method($S0) > Delete the method named $S0. > > $P0 = find_method($S0) > Find the method named $S0. > > $P0 = methods() > Return an array of the methods in the class. > > Compiler PMC API > Methods > load_library($S0, $S1, ...) > Ask this compiler to load a library/module named by the strings $S0, > $S1, ... So perl5:Some::Module should be loaded using > "perl5.load_library("Some", "Module")". > > Subroutine PMC API > Some information must be available about subroutines to implement the > correct behavior about namespaces. > > Data > get_namespace > The namespace where the subroutine was defined. (As opposed to a > namespace that it was imported into.) > > Namespace Opcodes > add_namespace $P0, $P1 > Add the namespace PMC $P1 as the namespace $P0 (an array of names or > a multidimensional hash index). > > del_namespace $P0 > Delete the namespace $P0 (an array of names or a multidimensional > hash index). > > $P0 = find_global $P1, $S0 > $P0 = find_global $S0 > Find the variable $S0 in $P1 or the current namespace. > > $P0 = get_namespace $P1 > $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"] > > store_global $P1, $S0, $P0 > store_global $S0, $P0 > Store $P0 as the variable $S0 in $P1 or the current namespace. > > HLL Namespace Mapping > In order to make this work, Parrot must somehow figure out what type of > namespace pmc to create. > > Default Namespace > The default namespace PMC will implement Parrot's current behavior. > > 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 "main" sub would be tied to Perl5 by the ".HLL" > directive, so a Perl5 namespace would be created. > > 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, "store_global" should see that it was called from "main", > which is in a Perl5 namespace, so "Foo::" should be also created as a > Perl 5 namespace. > > Language Notes > Perl 6 > > 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 "find_sub" and > "find_method" methods would, in this case, would append a "&" > sigil to the front of the sub/method name and search in the > internal hash. > > Submethods > Submethods should be handled by adding an additional Class > method "add_submethod" and adding another internal hash > (submethods can have the same name as methods, I believe). > > Python > > Subroutines and Namespaces > Since Python's subroutines and namespaces are just variables > (the namespace collides there), the Python PMC's "find_var" > method may return subroutines as variables. > > Examples > Aliasing > Perl: > > #!/usr/bin/perl6 > sub foo {...} > %Foo::{"&bar"} = &foo; > > PIR: > > .sub main :main > $P0 = find_name "&foo" > $P1 = get_namespace ["perl6"; "Foo"] > # A smart perl6 compiler would emit this, > # because it knows that Foo is a perl6 namespace: > # $P1["&bar"] = $P0 > # But a naive one would emit this: > $P1.add_sub("bar", $P0) > end > .end > > .sub foo > ... > .end > > Cross-language Importing > Perl: > > #!/usr/bin/perl > use tcl:Some::Module 'w*'; > write("this is a tcl command"); > > PIR: > > .sub main :main > .local pmc tcl > tcl = compreg "tcl" > tcl.load_library("Some", "Module") > $P0 = get_namespace > $P1 = get_namespace ["tcl"; "Some"; "Module"] > add_namespace ["perl5"; "Some"; "Module"], $P1 > $P1.import_into($P0, 'w*') > write("this is a tcl command") > end > .end