Skip to content

Instantly share code, notes, and snippets.

@skids
Created February 21, 2012 18:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save skids/1877885 to your computer and use it in GitHub Desktop.
Save skids/1877885 to your computer and use it in GitHub Desktop.
Meandering around Perl6 Capture multi-key semantics
Notes from my drive-time meditations...
Two semantics for Associative with multiple identical keys.
( :a<foo>, :a<bar> )
#1 #2
a => bar or a => ( foo, bar )
What Perl5 users expect In regexp/Match for multiple <name>
Used to amend defaults In Hash.invert
Signature/Capture hybrid semantic (S06:807)
might allow different behavior for different keys
(but there's some debate -- and cruft -- there)
Match is essentially a mutable Capture.
Match might be replaced with something else due to Failure/Nil refactor
Having a mutable Capture-like construct that is not special purpose
like Match might be handy. It does the thing that PHP users crave,
and more.
Might be time to consider that construct, with the replacement for
Match being a subclass of it with the additional special from/to/ast keys.
Problem:
When arrays spring to life where scalars were, unexpected things happen.
Also, when values are overridden, unexpected things happen.
Consider in the context of laziness:
( a => [ 1, 2, 3 ], # time passes
a => [ 4, 5, 6 ] )
This is of course fine for code that wants a List of Pair semantic, but for
parameter processing it requires us to be less lazy than we could,
and if we ever did want to index into such a construct while it was
lazily consolidating the named parameters, that would suck:
In semantic #1, {a}[0] changes from 1 to 4. and we do not know correct value until feed is tapped out.
In semantic #2, {a}[0] changes from 1 to [1, 2, 3], and now it has to be subscripted differently
In code that effectively implements the equivalent of semantic #2, where
instead of laziness the structure is unknown for other reasons, this has
always been a cause of ugliness, e.g. testing ref({a}[0]) ~= /Array/ in perl5,
but the automatic, builtin nature of it makes things worse.
Most deplorably, in semantic #2 we cannot really differentiate between a key fed a
positional, and a key fed multiple values which then become a positional:
(:a<foo,bar>) vs (:a<foo>,:a<bar>) when using Semantic #2
In some use-cases we DO want this distinction, sometimes we DO NOT.
Investigation:
Throw multidimensionality at the problem?
What if semantic #2 were changed such that:
$a = \(:a<foo>, :a<bar>); # means instead
$a{a;0} = "foo"; # let's pretend the second index is not a Hash key but a positional subscript
$a{a;1} = "bar";
So do both levels of distinction fall out naturally then?
...before explosion
$a = :a<foo> or $a = (:a<foo>);
$a<a> # is 'foo'
$a<a>[0] # is still 'foo'
$a{'a';0} # too many dimensions error? or 'foo'?
$a{'a';0}[0] # too many dimensions error? or 'foo'?
$b = \(:a(1,2,3));
$b<a> # is (1,2,3)
$b<a>[0] # is 1
$b{'a';0} # too many dimensions error? or (1,2,3)?
$b{'a';0}[0] # too many dimensions error? or 1?
And after:
$a = \(:a<foo>, :a<bar>);
$a<a> # is $a{'a';} zen slice is ('foo','bar') -- non-distinctive
$a<a>[0] # is 'foo'
$a{'a';0} # is 'foo' -- distinctive vs $b{'a',0} above, if we do not error out.
$a{'a';0}[0] # is 'foo'
$b = ( a => (1, 2, 3), a => (4, 5, 6) );
$b<a> # is ((1,2,3),(4,5,6)) collapses as item to (1,2,3),(4,5,6)
$b<a>[0] # is (1,2,3)
$b{'a';0} # is (1,2,3)
$b{'a';0}[0] # is 1
This leaves a door open to having:
$foo{$mykey;$occurence}; # use when you want to be specific
and
$foo{$mykey}[$occurence_or_subscript]; # use when you want things sloppy
...depending on how heavily we value sanity warnings/errors on dimensionality...
of course that's really up to individual .postcircumfix:<{ }>'s to decide so
this behavior could be class/role specific.
There is some ugliness here (other than it just being ugly on its face) because
really we are talking about a multidimensional construct which is Arrays under
a Hash, not Hashes under Hashes. This isn't a notational problem for the usual
treed-objects structure, and the above subscripting isn't all that abusive,
but we have no notation for defining a proper mixed Positional/Associative
multidimensional construct.
Example use case:
# we have to imagine mutable Capture where []'s used. Tried to hack a working
# version using Match, but it's missing some methods/features.
use SVG;
my $svg = svg => [
width => '20%', height => '25%',
defs => [ path => [:id<p1>, :d('M 0 0 H 1 L 1 Z')],
path => [:id<p2>, :d('M 0 0 H 1 L 1 Z')],
g => [ path => [:id<p1> :d('M 0 0 H 1 L 1 Z')], :id<g1>]
]
];
# some other file, some other author wants to modify before emitting
$svg<svg><defs><path>.push: [:id<p2> :d('M 0 0 H 1 L 1 Z')] # OK, add to list of paths
$svg<svg><defs>.push: path => [:id<p2> :d('M 0 0 H 1 L 1 Z')] # Same thing, mostly
$svg<svg><defs><g><path>.push: [:id<p2> :d('M 0 0 H 1 L 1 Z')] # not OK, pushes into path's attributes
$svg<svg><defs>{'path';0}.push: :color<red> # OK, if we want to do that
$svg<svg><defs><path>[0].push: :color<red> # OK, change first path's attribute
$svg<svg><defs><g><path>[0].push: :color<red> # not OK, tries to push into nonexistent first positional
$svg<svg><defs><g>{'path';0}.push: :color<red> # this would work consistently over here, too
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment