Root-relative namespace keys

Allison Randal allison at parrot.org
Wed Jan 7 04:44:31 UTC 2009


I'm going to start out by taking a step back. First off, define the 
fundamental problem we're trying to solve: accessing classes from 
foreign HLLs. If I've understood Patrick/chromatic, then they agree with 
that.

We're specifically considering several core opcodes:

>>     $P0 = newclass ['Foo';'Bar']
>>     $P1 = subclass ['Hash'], ['MyHash']
>>     $P2 = get_class ['MyHash']
>>     $I0 = isa $P1, ['Hash']

And a :modifier

>>     .sub 'xyz' :multi(['MyHash'])

which currently are a bit too limited in features to adequately handle 
foreign HLLs. I'll put :multi in a separate message.

On general principles, any solution that works for one of the opcodes 
should work for all opcodes that lookup a class. (These opcodes are 
currently consistent, both in how they lookup a class and in how they 
create a class.)

For class lookups 'newclass', 'subclass', 'get_class', and 'isa' all 
accept a string name or a PMC. That PMC can currently be a Key, String, 
ResizableStringArray, or NameSpace. If it's a namespace, the class is 
directly extracted from the namespace. If it's one of the other three, 
then it does a namespace lookup (HLL-relative) and extracts the class 
from that namespace (if it exists).

For class creation, 'newclass' and 'subclass' accept a string name or a 
PMC. The PMC can be a Key, String, ResizableStringArray, NameSpace, or 
Hash. The first four are treated as an HLL-relative namespace lookup, 
with the difference that Key, String, and ResizableStringArray will 
create a new namespace if one isn't found. The Hash contains a 'name' 
element that acts just like the first four, and may also contain 
elements for 'parents', 'methods', 'roles', and 'attributes'.

The class creation behavior isn't unique to 'newclass' and 'subclass', 
it's core behavior of Class itself, and happens any time a Class object 
is created and passed an initialization argument (that is 'init_pmc'). 
The 'newclass' and 'subclass' opcodes are just syntactic sugar for:

   $P2 = new 'Hash'
   # set 'name' and optionally 'parents' keys of hash

   $P1 = new 'Class', $P2

Whatever solution we choose for improving HLL handling with classes 
should fit within this system. And it needs to flexibly handle all 
variations of class lookups in foreign HLLs.

I propose we extend class lookups to also accept a Hash PMC (the code is 
centralized, so it's a straightforward change). Then extend class 
creation so it accepts the same hash keys as class lookups. The keys 
would be:

   - 'name', the class name (string, key, or array of strings)
   - 'hll', selecting which HLL namespace to use as the root
   - 'namespace', a namespace object or namespace name (string, key, or 
array of strings)

To lookup a class relative to the current HLL:

   'name' => ['foo';'bar'] # same as ['foo';'bar']

Lookup a class relative to a foreign HLL:

   'hll' => 'lang', 'name' => ['foo';'bar']

Lookup a class relative to any arbitrary namespace object:

   'namespace' => $P0, 'name' => 'foo'

   'namespace' => $P0, 'name' => ['foo';'bar']

Lookup a class relative to a namespace by key or name (looked up 
relative to the current HLL):

   'namespace' => 'my', 'name' => 'foo'

   'namespace' => ['my';'favorite'], 'name' => 'foo'

Lookup a class relative to a foreign HLL, with a namespace key or name:


   'hll' => 'lang', 'namespace' => 'my', 'name' => 'foo'

   'hll' => 'lang', 'namespace' => ['my';'favorite'], 'name' => 'foo'



Someone is probably going to say "but creating a Hash to pass as an 
initializer is a pain in PIR". Yes, it is. It always has been a pain. 
And it's a pain that isn't unique to PMC initialization, but true of all 
hash creations everywhere. Making a list is really easy with 
['foo';'bar'] or 'split', but making a hash is just a pain. The only 
place creating something hash-like isn't a pain is in a method call. 
Okay, so maybe this is a good problem to solve once for everyone.

What if we reuse the parsing for that method call syntax to create a 
Hash (or Capture)? And make it legal anywhere a PMC argument is legal? 
So, that pseudocode above becomes the actual code:

   $P0 = newclass ('hll'=>'lang', 'namespace'=>'my', 'name'=>'foo')

Or, just creating a Hash:

   $P0 = new 'Hash', ('foo' => 1, 'bar' => 2)

Or maybe even:

   $P0 = ('foo' => 1, 'bar' => 2)

I used parens for the parallel with method calls, but the contexts are 
different enough that it may be a bad parallel. It could equally well 
use '|...|' or some other bracketing characters. I would avoid '[...]' 
for the sake of confusion, it does something completely different. But, 
it's important to be consistent on the syntax inside for "named lists", 
that is, key/value pairs.


This feels flexible, it feels dynamic, and it doesn't feel hackish. 
Thoughts, comments, variations on a theme?

Allison


More information about the parrot-dev mailing list