> On Jan 19, 2021, at 12:18 PM, Brian Duggan <bdug...@matatu.org> wrote:
> 
> Hi Folks,
> 
> I ran into this situation today, which seems counterintuitive:
> 
> my @one = 1,2,3;
> my @two = 4,5,6;
> my @both = @one,@two;
> my @first = @both[0];
> say @one.raku;
> say @first.raku;
> 
> output:
> 
>       [1, 2, 3]
>       [[1, 2, 3],]
> 
> I was expecting @first and @one to be the same.

I agree that @first not equalling @one is a bit counterintuitive, since the 
formation of @both as a two-element array, and the extraction of its first 
element, seems to be exact opposite operations.
In fact, let’s make it even more exactly opposite:
        my @one = 1,2,3;
        my @both;
        @both[0] = @one;        # Stuff it into first element
        my @first = @both[0];  # Yank it out of first element
        say @one.raku;
        say @first.raku;
This produces the same output as your original code, even though the two 
commented lines appear to cancel (like in algebra) to produce an identical 
result.

But wait! This version makes this issue clearer (at least to my Raku-accustomed 
eyes).
The first commented line is a version of this:
        $scalar_var = @some_array;
, in which $scalar_var _captures_ @some_array during the assignment. (Similar 
to “references" in Perl: `$z = \@y;`)
To exactly invert, we need to also counteract the capturing in the second 
commented line.
(continued below)

> I discovered that I could instead write either of these --
> 
>  my (@first) = @both[0];
>  my @first := @both[0];
> 
> or I could change the @both assignment to be
> 
>       my @both := @one, @two;

To discuss those three alternatives, let’s extend your original code:
        my @one = 1,2,3;
        my @two = 4,5,6;
        my @both = @one,@two;
        my @first = @both[0];
        say @one.raku;
        say @first.raku;

        my (@a) = @both[0];
        my @b  := @both[0];
        my @both_bound := @one,@two;
        my @c  := @both_bound[0];
        say .raku for @a, @b, @c; # They all look right, but only because 
nothing wrote to them.
        @a[1] = 7; say @one;      # [1 2 3] , independent as expected
        @b[1] = 8; say @one;      # [1 8 3] , bound/aliased!
        @c[1] = 9; say @one;      # [1 9 3] , bound/aliased!

The first form, `my (@array) = …`, I read as quite clever (as in “I didn’t 
think of it myself”). it does what I think you intended.
Our community is still in the idiom-forming phase, but this would not be a 
preferred form for me.
I think that is (mostly?) due to it being a LHS-manipulation, so it cannot 
easily work as part of a larger expression without some temp array on the 
left-hand side.
[
        I admit that part of my dislike is because it looks too much like this 
from Perl:
                my ($only_want_the_first_element) = @some_array;
        , and having a @-sigiled variable inside that expression looks like a a 
redundant use of parens.
        Please give zero weight to that biased part of my assessment.
]

The second and third forms both use “binding”, which would be fine if “live 
links” between @one and @first was your need and intention, but would be a 
source of bugs otherwise.
Your original code looks like you want @first to contain independent copies of 
the @one elements.
If I were refactoring your code, I would not assume that changing assignment to 
binding would be OK to do.
(I suspect that you already knew that, and were just showing us all of the 
variants that “worked”)

> ..but I wonder if there's an idiomatic approach -- or
> way of thinking about this -- that makes this flow more
> intuitive.

(continued from above)
I would probably write it as:
        my @first = @both[0].list;
, but for this exact case I might instead say:
        my @first = @( @both[0] );
. They do the same thing here, and both look idiomatic to me,
but .list looks like an action/command to @both[0],
and @(...) is the List Contextualizer,
so which one I would use would depend on the surrounding code,
and who I expected to be reading the code.
        https://docs.raku.org/type/Any#index-entry-@_list_contextualizer

So, I recommend .list or @(…) as more intuitive, maybe even *sufficiently* 
intuitive :^)

> thanks
> Brian

— 
Hope this helps,
Bruce Gray (Util of PerlMonks)

Reply via email to