Syntax error in a Map/Hash initializer -- why isn't this supported?

1 view
Skip to first unread message

L A Walsh

unread,
Aug 10, 2020, 5:57:14 PM8/10/20
to bug-...@gnu.org
I wanted to use a map that looked like this:

declare -A switches=([num]=(one two three)), where '(one two three)'
is an associated list. Ideally, I could access it like other arrays:
for types in ${switches[num][@]}; do...
or
switches[num]=(one two three) #gives:
-bash: switches[num]: cannot assign list to array member
or
echo ${switches[num][0]} (="one").

I defaulted to going around it by making it a string, like:
switches[num]="one|two|three"
or
switches[num]="(one two three)" but why? It seems obvious that bash
knows what I'm trying to do, so why not just do it?

Some nested constructs seem to work:
> b=(1 2 3)
> a=(4 5 6)
> echo ${a[${b[1]}]}
6

but more often than not, they don't. Is there a reason to disallow such?

Eli Schwartz

unread,
Aug 10, 2020, 6:44:25 PM8/10/20
to bug-...@gnu.org
On 8/10/20 5:56 PM, L A Walsh wrote:
> I wanted to use a map that looked like this:
>
> declare -A switches=([num]=(one two three)), where '(one two three)'
> is an associated list. Ideally, I could access it like other arrays:
> for types in ${switches[num][@]}; do...
> or
> switches[num]=(one two three) #gives:
> -bash: switches[num]: cannot assign list to array member
> or
> echo ${switches[num][0]} (="one").
>
> I defaulted to going around it by making it a string, like:
> switches[num]="one|two|three"

Correct, bash does not implement multidimensional arrays and its syntax
error if you try anyway, implements the minimum heuristics necessary to
convey that fact to you.

> or
> switches[num]="(one two three)" but why? It seems obvious that bash
> knows what I'm trying to do, so why not just do it?

.. I'm sorry, did you just state your disapproval at bash for not
implementing something, but having a useful error message in the
process? Would you prefer "bash: error: an unknown error occurred"?

> Some nested constructs seem to work:
>> b=(1 2 3)
>> a=(4 5 6)
>> echo ${a[${b[1]}]}
> 6

This is not a multidimensional array, obviously. It is two
single-dimensional arrays, with a value lookup in one array that is then
reused as the input key to perform another lookup in the second array.

> but more often than not, they don't. Is there a reason to disallow such?

Today's session of "Linda Walsh is year-by-year terrible at asking
questions".

Instead of asking:

"Can bash please implement multidimensional arrays as I think they're
nifty and would like to use them."

We are getting:

"Bash supports multidimensional arrays because $HACK but it doesn't let
me do them in X Y Z manner, is there a reason to arbitrarily forbid them
or can this pointless restriction be lifted."

This is a variant of http://catb.org/~esr/faqs/smart-questions.html#symptoms

Please read the whole article, but pay particular attention to the
section on "don't describe your problem in terms of the incorrect
diagnostic theory you've already decided is the real problem".

--
Eli Schwartz
Arch Linux Bug Wrangler and Trusted User

signature.asc

Lawrence Velázquez

unread,
Aug 10, 2020, 7:01:04 PM8/10/20
to Eli Schwartz, bug-...@gnu.org
> On Aug 10, 2020, at 6:44 PM, Eli Schwartz <esch...@archlinux.org> wrote:
>
> Instead of asking:
>
> "Can bash please implement multidimensional arrays as I think they're
> nifty and would like to use them."

Some prior art:

https://lists.gnu.org/archive/html/bug-bash/2011-09/msg00061.html
https://lists.gnu.org/archive/html/bug-bash/2012-11/msg00048.html

It seems that Chet has never been interested, and no one else has
stepped up to contribute.

vq

Greg Wooledge

unread,
Aug 11, 2020, 7:35:28 AM8/11/20
to bug-...@gnu.org
> > "Can bash please implement multidimensional arrays as I think they're
> > nifty and would like to use them."
> It seems that Chet has never been interested, and no one else has
> stepped up to contribute.

A large reason for this is because bash is a shell, not a programming
language. Another reason is that there are already ways to work
around the "issue".

The standard way to implement something that works like a multidimensional
array is to use an associative array, and construct a key string out of
your multiple indices, using some delimiter character that can't appear
in any of the indices.

For example, if your indices are integers, you could use a comma
as the delimiter. Then:

declare -A grid=( [0,0]=foo [0,1]=bar [0,2]=baz )
x=0 y=2
echo "${grid[$x,$y]}"

This prints "baz" as expected.

Another way which *only* works when your indices are small non-negative
integers is to use a sparse indexed array, and construct a key index
of the form i + (A)j + (A^2)k + ... where A is some suitably large
constant chosen for your particular problem. For example, to store
up to a 100x100 grid, we can choose A = 100, and let the individual
indices run from 0 to 99.

unset grid
grid=( [0+100*0]=foo [0+100*1]=bar [0+100*2]=baz )
x=0 y=2
echo "${grid[x+100*y]}"

This has the advantage of working in bash versions 2 and 3 which lack
associative arrays, and the disadvantages of requiring numerical indices,
and a strict up-front limit on the dimensions of your matrix.

If you can't abide using "hacks" to implement your own multidimensional
arrays, then bash isn't the right language for your project. Choose a
different one.

Reply all
Reply to author
Forward
0 new messages