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 |