Created
February 21, 2012 18:05
-
-
Save skids/1877885 to your computer and use it in GitHub Desktop.
Meandering around Perl6 Capture multi-key semantics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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