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