Daniel Ruoso wrote:
>
> Hi,
>
> As smop and mildew now support ControlExceptionReturn (see
> v6/mildew/t/return_function.t), an important question raised:
>
> sub plural { return 1,2 }
> sub singular { return 1 }
> my @a = plural();
> my $b = plural();
> my @c = singular();
> my $d = singular();
>
> What should @a, $b, @c and $d contain?
>
> Note that the spec says explicitly that a Capture should be returned,
> delaying the context at which the value will be used, this allows
>
> sub named { return :x<1> }
> my $x := |(named);
>
> So, this also means that assigning
>
> my @a = plural();
> my @c = singular();
>
> forces list context in the capture, which should return all positional
> parameters, as expected. But
>
> my $b = plural();
> my $d = singular();
>
> would force item context in the capture, and here is the problem, as a
> capture in item context was supposed to return the invocant.
If item context is supposed to return the invocant, then it would seem
to me that returning a single value from a sub would put that value
into the capture object's invocant. This would mean that the problem
crops up under 'my @c = singular()' instead of 'my $b = plural()'.
The idea in the spec is that the capture object can hold an item, a
distinct list, and a distinct hash all at once. The problem that
we're encountering here is that there are times when the difference
between an item and a one-item list is fuzzy. We _could_ kludge it by
saying that when a sub returns an item $x, it gets returned as a
capture object ($invocant := $x: $param1 := $x) or some such; but this
_is_ a kludge, which has the potential for unexpected and unsightly
developments later on.
Another option would be to change the way that applying item context
to a capture object works in general, to allow for the possibility
that a single-item list was actually intended to be a single item: if
there's no invocant, but there is exactly one positional parameter,
return the positional parameter instead:
$a = |("title": 1)
$b = |("title":)
$c = |(1)
$x = item $a; # $x == "title"
$x = item $b; # $x == "title"
$x = item $c; # $x == 1
$x = list $a; # $x == [1]
$x = list $b; # $x == []
$x = list $c; # $x == [1]
With this approach, return values would return values as positional
parameters unless a conscious effort was made to do otherwise.
But let's say that you really wanted to get the invocant of a capture
object. You can still do so:
|($x:) = $a; # $x == "title"
|($x:) = $b; # $x == "title"
|($x:) = $c; # $x == undef
Likewise, you could specify that you want the first positional
parameter of the capture object by saying:
|($x) = $a; # $x == 1
|($x) = $b; # $x == undef
|($x) = $c; # $x == 1
This isn't as clean as a straight mapping of invocant to item,
positional to list, and named to hash; but I think that it's got
better dwimmery.
--
Jonathan "Dataweaver" Lang