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

Reply via email to