Re: Zsh's and ksh's bang (!) expansion flags have different meanings

Philippe Altherr <[email protected]>
Newsgroups gmane.comp.shells.zsh.devel
Message-ID <CAGdYchuMjkAxfANMofyTT=RSYLki7fbBAdcXbfEguXCq=PKnKg@mail.gmail.com>
My previous message contains two patches:

- Patch 1: Reverts Zsh's emulation of ksh's ${!var} from ${(!k)var}
to ${(k)var}
- Patch 2: Extends ${(k)var} in ksh emulation to be active in more cases

In ksh the ! in ${!var} is always active; ${!var} always expands to
something different than ${var}. Things are different in Zsh. Both the (!)
in ${(!)var} and the (k) in ${(k)var} are only active in some cases. For
instance, ${(!)var} expands to the same as ${var} if var isn't a named
reference and ${(k)var} expands to the same as ${var} if var is neither an
array nor a hashtable.

My rationale against mapping ${!var} to ${(!k)var} and in favor of patch 1
is that when (!k) in ${(!k)var} and (k) in ${(k)var} are active, there are
about the same number of cases (but different ones), where they return the
expected result (or a similar one) but there are many cases where (!k) is
active and returns a bogus result while there are very few (or none,
depending on what you count) for (k). I see (!k) as a dead end because it
bakes in many bogus results, while (k) can be extended to become active in
more cases to return the expected result.

The table below shows in green cases where the result is the same as in
ksh, in orange, cases where it's similar, in blue, cases where ! has no
effect and in pink cases where ! is active but returns a bogus result. We
can disregard the lines for !arr[1,2] and !str[1,2] because ksh doesn't
support multiple subscripts. Let's also ignore cases of chains of
references (the third value in each triplet), which surely will be less
common than plain variables and plain references. Then, there are only 6
cases where (!k) is active and matches ksh (or returns something similar),
the same as for (k), but there are 6 cases where (!k) is active and returns
a bogus result while there are none for (k). My patch 2 shows that it's
possible to extend (k) such that it's active and correct in 6 more cases
and still never actively bogus. Note also that the extended (k) is strictly
better than (!k).

Obviously we could debate how to count cases but there is no denying that
(!k) bakes in bogus results while (k) can be extended to become strictly
better than (!k).


Zsh's ksh emulation

ksh

Zsh's ksh emulation

Zsh's ksh emulation

${!var} <=> ${(!k)var}

${!var} <=> ${(k)var}

${!var} <=> ${(k)var}

+ extend (k) in ksh emulation

!str

!str[1]

!str[1,2]

!str[@]

!arr

!arr[1]

!arr[1,2]

!arr[@]

!hsh

!hsh[1]

!hsh[@]

abc - str0 - str1

b - t - t

bc - tr - tr

abc - str0 - str1

aa - arr0 - arr1

1 - r - r

<error> - rr - rr

aa bb cc - arr0 - arr1

aa - hsh0 - hsh1

1 - s - s

0 1 2 - hsh0 - hsh1

str0 - str0 - str0

str0[1] - str1[1] - str2[1]

str0[1,2] - str1[1,2] - str2[1,2]

0 - 0 - 0

arr0 - arr0 - arr0

arr0[1] - arr0[1] - arr0[1]

arr0[2] - arr0[2] - arr0[2]

0 1 2 - 0 1 2 - 0 1 2

hsh0 - hsh0 - hsh0

hsh0[1] - hsh0[1] - hsh0[1]

0 1 2 - 0 1 2 - 0 1 2

abc - abc - abc

b - b - b

bc - bc - bc

abc - abc - abc

aa - aa - aa

1 - 1 - 1

<error> - <error> - <error>

aa bb cc - aa bb cc - aa bb cc

aa - aa - aa

1 - 1 - 1

0 1 2 - 0 1 2 - 0 1 2

str0 - str0 - str0

b - b - b

bc - bc - bc

abc - abc - abc

arr0 - arr0 - arr0

1 - 1 - 1

<error> - <error> - <error>

aa bb cc - aa bb cc - aa bb cc

hsh0 - hsh0 - hsh0

1 - 1 - 1

0 1 2 - 0 1 2 - 0 1 2

!var

!var

!var

!var

abc: result is the same as ${!var} in ksh

abc: result is similar to ${!var} in ksh

abc: result is the same as ${var}, i.e., the flag had no effect

abc: result is bogus, neither the same as ${!var} in ksh nor as ${var},
i.e., the flag was actively detrimental

Philippe
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.