zsh-users
 help / color / mirror / code / Atom feed
* indirect array element assignment?
@ 2022-07-02 10:33 Anthony Heading
  2022-07-02 18:13 ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Anthony Heading @ 2022-07-02 10:33 UTC (permalink / raw)
  To: zsh-users

What's the best zsh way of doing an indirect array element assignment?   This works quite nicely in bash: 

#!/bin/bash 
fruits=("apple" "banana" "carrot")
# but a carrot is not a fruit
var="fruits"
declare -n v=$var
v[2]="cherry"
echo ${fruits[@]}
=> apple banana cherry

Everything in zsh I've tried around  ${${(P)v}[2]::=cherry}  with misc different bracketing gets "not an identifier", suggesting maybe the ::= form doesn't support subscripting.   Is there something better than 'eval' for this?


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: indirect array element assignment?
  2022-07-02 10:33 indirect array element assignment? Anthony Heading
@ 2022-07-02 18:13 ` Bart Schaefer
  2022-07-02 18:23   ` Bart Schaefer
  2022-07-03  2:28   ` Anthony Heading
  0 siblings, 2 replies; 6+ messages in thread
From: Bart Schaefer @ 2022-07-02 18:13 UTC (permalink / raw)
  To: Anthony Heading; +Cc: Zsh Users

On Sat, Jul 2, 2022 at 3:34 AM Anthony Heading <ajrh@ajrh.net> wrote:
>
> What's the best zsh way of doing an indirect array element assignment?

fruits=("apple" "banana" "carrot")
v=fruits
typeset "${v}[3]"=cherry

There really isn't a good solution if you're trying to do array
slices, i.e., a parenthesized list on the right of the "=".

> Everything in zsh I've tried around  ${${(P)v}[2]::=cherry}  with misc different bracketing gets "not an identifier", suggesting maybe the ::= form doesn't support subscripting.

It's not that it doesn't support subscripting, it's that it doesn't
support parameter expansions of any kind on the left:

% echo ${${grape}::=raisin}
zsh: not an identifier:

I'm not sure why the error isn't more specific.

The syntax, if it worked, would be ${(P)v[3]::=cherry}, because
${(AP)=v::=apple banana carrot} works, but although ${(P)v} gets you a
reference to $fruits, as soon as you subscript it as ${(P)v[x]} you
end up assigning to a copy of the x'th field of $fruits instead,
because zsh doesn't create indirect references to array elements, it
substitutes them by value.

You can do it this way:

z="${v}[3]"
echo ${(P)z::=cherry}


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: indirect array element assignment?
  2022-07-02 18:13 ` Bart Schaefer
@ 2022-07-02 18:23   ` Bart Schaefer
  2022-07-03  2:28   ` Anthony Heading
  1 sibling, 0 replies; 6+ messages in thread
From: Bart Schaefer @ 2022-07-02 18:23 UTC (permalink / raw)
  To: Anthony Heading; +Cc: Zsh Users

On Sat, Jul 2, 2022 at 11:13 AM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> The syntax, if it worked, would be ${(P)v[3]::=cherry}

I'm sorry, I just realized that's wrong.  $v is a scalar, so v[3] is
the letter "u" (third character of "fruits") and this assigns to the
variable $u.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: indirect array element assignment?
  2022-07-02 18:13 ` Bart Schaefer
  2022-07-02 18:23   ` Bart Schaefer
@ 2022-07-03  2:28   ` Anthony Heading
  2022-07-03  3:41     ` Bart Schaefer
  1 sibling, 1 reply; 6+ messages in thread
From: Anthony Heading @ 2022-07-03  2:28 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh Users

On Sat, Jul 2, 2022, at 2:13 PM, Bart Schaefer wrote:
> You can do it this way:
>
> z="${v}[3]"
> echo ${(P)z::=cherry}

Wow. Thank you!  I didn't think of that at all.

> It's not that it doesn't support subscripting, it's that it doesn't
> support parameter expansions of any kind on the left:
>
> % echo ${${grape}::=raisin}
> zsh: not an identifier:

Ah, that makes sense.  Though hmm...  there's some lhs expansion, no?
${grape[$#grape]::=raisin} for example.
Is it a necessary error by design?  I see why the (P) flag
is needed for rhs expansion because shell ${${${...}}} defines
nesting to mean something different,  but for lhs ::= I wonder
why ${${X}::=...} couldn't have well-defined natural meaning.

> There really isn't a good solution if you're trying to do array
> slices, i.e., a parenthesized list on the right of the "=".

You're referring to the typeset style solution here, maybe?
Your later solution seems to work great for all sorts of array splicing.

fruits=(apple banana carrot calamansi cherry cantaloupe durian)
# hunt down the errant vegetable and all its friends
v="fruits"
z="${v}[(r)c*,(R)c*]"
: ${(PA)z::=$signals[10,11]}
echo $fruits
% apple banana KILL USR1 durian



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: indirect array element assignment?
  2022-07-03  2:28   ` Anthony Heading
@ 2022-07-03  3:41     ` Bart Schaefer
  2022-07-03 16:43       ` Anthony Heading
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2022-07-03  3:41 UTC (permalink / raw)
  To: Anthony Heading; +Cc: Zsh Users

On Sat, Jul 2, 2022 at 7:28 PM Anthony Heading <ajrh@ajrh.net> wrote:
>
> On Sat, Jul 2, 2022, at 2:13 PM, Bart Schaefer wrote:
> > It's not that it doesn't support subscripting, it's that it doesn't
> > support parameter expansions of any kind on the left:
> >
> > % echo ${${grape}::=raisin}
> > zsh: not an identifier:
>
> Ah, that makes sense.  Though hmm...  there's some lhs expansion, no?
> ${grape[$#grape]::=raisin} for example.

Subscripting does expansion inside the [ ], but that's not the same
context as ${${...}}.

> Is it a necessary error by design?  ... for lhs ::= I wonder
> why ${${X}::=...} couldn't have well-defined natural meaning.

For that to work, ${${X}} would have to mean the same as ${(P)X}.  As
a general rule nested expansions are processed innermost-leftmost, and
substitute rvalues rather than lvalues.  The (P) is what forces the
current level of expansion to turn into an lvalue, but that doesn't
apply to either the surrounding or the surrounded levels.

So ${(P)${X}::=thing} actually does work as long as ${X} returns a
valid identifier that can be treated as an lvalue.  Without the (P) it
remains an rvalue and you get the "not an identifier" error.

(I'm glossing over a lot of what actually goes on underneath here, but
if you're familiar with the concepts of lvalues and rvalues this is a
pretty good way to think about it.)

That does in fact mean that this works too, now that I think of it:

${(P)${:-${v}[2]}::=mango}

> > There really isn't a good solution if you're trying to do array
> > slices, i.e., a parenthesized list on the right of the "=".
>
> You're referring to the typeset style solution here, maybe?

Yes.

> Your later solution seems to work great for all sorts of array splicing.

Sure, but you also have to do your own array splitting, as e.g.
${(AP)=v::=apple banana carrot}, if attempting to assign a plain list
of words.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: indirect array element assignment?
  2022-07-03  3:41     ` Bart Schaefer
@ 2022-07-03 16:43       ` Anthony Heading
  0 siblings, 0 replies; 6+ messages in thread
From: Anthony Heading @ 2022-07-03 16:43 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh Users

On Sat, Jul 2, 2022, at 11:41 PM, Bart Schaefer wrote:
> That does in fact mean that this works too, now that I think of it:
>
> ${(P)${:-${v}[2]}::=mango}

Even better!   Though gosh it does start to cry out for dedicated
assignment syntax/parsing.  I always though it was rather a pity that
some predecessor (ksh maybe?) claimed 'let' for arithmetic so it's
not free:   let ${v}[2] ?= (peach apricot)   etc  would be easier
to deal with.   But perhaps this was the thought-process that
unleashed csh on the world, so maybe not.

> For that to work, ${${X}} would have to mean the same as ${(P)X}.  As
> a general rule nested expansions are processed innermost-leftmost, and
> substitute rvalues rather than lvalues.

Yes.  It didn't seem *too* far off, but I traced it now with gdb
through paramsubst() and I follow what you mean.



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-07-03 16:45 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-02 10:33 indirect array element assignment? Anthony Heading
2022-07-02 18:13 ` Bart Schaefer
2022-07-02 18:23   ` Bart Schaefer
2022-07-03  2:28   ` Anthony Heading
2022-07-03  3:41     ` Bart Schaefer
2022-07-03 16:43       ` Anthony Heading

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).