Name references were added first to ksh93 in the initial release in late 1993.
They are essential there because ksh93 implements static variable scoping¹ (and to this day, it's still the only shell that does unless you want to consider zsh's private variables), as a function cannot access the local variables of its caller otherwise.
AFAIK, the first shell to copy the feature was mksh in 2009 (first in the R39b release). It is cruder there in that it doesn't attempt to make sure the nameref points to the variable of the caller, so you still need to namespace your local variables (including the nameref variable itself) to make sure the nameref doesn't end up referencing them (or itself recursively).
mksh, the shell of MirBSD and Android is based on the sh/ksh of OpenBSD, itself based on pdksh from the late 80s, itself based on the Forsyth shell (a clone of the Bourne shell) and intended as a public domain clone of ksh88¹. mksh has gradually been adding more and more features from ksh93 so contrary to pdksh it may no longer be seen as a ksh88 clone. Like ksh88, it does dynamic scoping like most shells, and I don't believe there's any plan to switch to static scoping.
bash (also with dynamic scoping) copied namerefs, with the same limitations as in mksh in 4.3 (2014).
zsh (also with dynamic scoping except for its private variables) added it first in 2023 along with a new zsh/ksh93 module with more features from ksh93, though as of writing it's still work in progress and there hasn't been a full release yet. It tries to be a bit more faithful to the ksh93 implementation, and avoids the variable clashing issues seen in mksh/bash in most cases.
To demonstrate the issues:
$ ksh93 -c 'function f { typeset -n a=$1; typeset b=2; a=3; }; b=1; f b; echo "$b"' 3 $ mksh -c 'function f { typeset -n a=$1; typeset b=2; a=3; }; b=1; f b; echo "$b"' 1 $ bash -c 'function f { typeset -n a=$1; typeset b=2; a=3; }; b=1; f b; echo "$b"' 1 $ zsh -c 'function f { typeset -n a=$1; typeset b=2; a=3; }; b=1; f b; echo "$b"' 3
$ ksh93 -c 'function f { typeset -n a=$1; a=2; }; a=1; f a; echo "$a"' 2 $ mksh -c 'function f { typeset -n a=$1; a=2; }; a=1; f a; echo "$a"' E: f: typeset: a: expression recurses on parameter 2 $ bash -c 'function f { typeset -n a=$1; a=2; }; a=1; f a; echo "$a"' environment: line 1: typeset: warning: a: circular name reference environment: line 1: warning: a: circular name reference environment: line 1: warning: a: circular name reference 2 $ zsh -c 'function f { typeset -n a=$1; a=2; }; a=1; f a; echo "$a"' 2
local itself is from the Almquist shell and the ksh equivalent (which predates the Almquist shell) is typeset (which as noted above, in ksh93 only introduces a local (static) scope in functions declared with the function fname { ...; } syntax; without the typeset, variables refer to the global scope, not the scope of the caller).
In any case, pdksh, at the time it was still maintained, like ksh88 never had support for name references.
But like in bash/zsh/mksh/ash..., it's not as needed as it is in ksh93 as those shells do dynamic scoping, so functions can readily access variables of their caller as long as they don't shadow them with their own local variables. In mksh or bash, namerefs can be seen as syntactic sugar to avoid having to use eval.
For instance, instead of:
function myfun { typeset -n __var="$1" typeset __local_var=whatever __var=$(cmd that computes new value)$__local_var } myfun myvar
(note the __ prefix to reduce the risk of clash in mksh/bash).
You can do:
function myfun { typeset __var="$1" typeset __local_var=whatever eval "$__var="'$(cmd that computes new value)$__local_var' } myfun myvar
Note the need to put the $(... inside single quotes so it's passed literally to eval³. Failing to do so is a sure way to introduce command injection vulnerabilities. namerefs help you with that as they make it easier to make sure only the referenced variable name is subject to evaluation (there's still a potential for ACE vulnerability if you don't sanitise the variable name though).
Using a temporary variable and limiting yourself to eval "$__var"'=$__tmp' to reduce the chance of mistake is good practice as in:
function myfun { typeset __var="$1" __var_value typeset __local_var=whatever eval "__var_value=\${$__var}" printf '%s\n' "$__var initially contained $__var_value" __var_value=$(cmd that computes new value)$__local_var printf '%s\n' "new value to be $__var_value" eval "$__var"'=$__var_value' } myfun myvar
¹ when using ksh-style functions (defined with function fname { ...; }), there's no scoping at all in Bourne-style functions (defined with fname() command).
² which was closed source and expensive; and still is closed source contrary to ksh93 whose source was released circa 2000, though nowadays you can find code of some of its versions on archive.org and elsewhere.
³ and the double quotes around $__var to prevent split+glob as usual.
zshmight be too much for one's taste (and to bash-y from a ksh user POV), but isn't99/07/13the build date? I tried building pdksh-5.2.14 on my system, and it does seem to a lot of patching to even build with a C99 compiler on Linux. The configure misdetects the signal handler types (which defintely haven't changed, hm), the generation of a signal list (which should have been done at configure, not at compile time) falls on its face because, well,2+is not an integer) and so on. Maybe you want to use a …