This is relevant to my interests! So first off, the circular reference problem with "declare -n" apparently doesn't exist in Korn Shell: If you "typeset -n x=$1", and $1 is "x", it's not a circular reference. The nameref seems to take the origin of the name into account when creating the nameref: If $1 is used to provide the name for a nameref within a function, then the nameref refers to a variable in the scope of the function's caller. But if the name for the nameref is taken from another parameter, or a string literal, then the variable is drawn from the scope of the function itself. It seems a little "black magic" in a way but it has the benefit of neatly matching some important common use-cases. I think Bash should either adopt something similar, or provide another mechanism to exclude function-local variables from nameref construction.
...And I could be wrong here (as I haven't used namerefs much in bash) but it seems you can't use a nameref to change the type of a variable... For instance if "x" is local to f1, and f1 calls "f2 x", and f2 declares a nameref that resolves to its argument "x", f2 cannot then change "x" to an associative array, for instance. The caller has to declare the variable with the proper type before passing it into the function as a nameref. Regarding return values, there's a couple ways of looking at this: First, a common way of dealing with the situation is to have functions emit their results to stdout, and then capture the data with command substitution. This is a bit problematic because command substitution occurs in a subshell environment. (This is actually mandated in Posix, it seems - which is unfortunate, because there's actually no need for it to be a subshell environment! In Korn Shell, it's not... Command substitution is evaluated in the main shell environment - which struck me as odd at first, but it actually makes sense for these kinds of scenarios, where you want to run something that has a side-effect, and capture its output.) This means a function call or built-in can't create side-effects in the shell environment (setting environment variables or open/close files) AND emit a result on stdout for capture. It's strictly one or the other. Second, with namerefs in the picture, one could use them to tell a function where to store its return value. It doesn't look "functional" but it gets the job done, right? But again, there's the various problems with namerefs in Bash presently. Name collisions can lead to circular references, and the type of the var can't be changed using the nameref. Finally, of course... Functions could simply "return" values by populating a variable in the caller's scope. I don't think it's a great solution And finally, with respect to creating Bash "libraries" of functions: The problem of namespace pollution could be largely solved by supporting some form of namespaces to contain the declarations that are needed only locally. (Current versions of ksh have a whole OO system, meaning a library's footprint in global namespace can be very small!) ----- Original Message ----- From: "Greg Wooledge" <wool...@eeg.ccf.org> To:"bug-bash" <bug-bash@gnu.org> Cc: Sent:Wed, 14 Jun 2017 08:43:14 -0400 Subject:Re: RFE: Please allow unicode ID chars in identifiers On Tue, Jun 13, 2017 at 04:58:59PM -0700, L A Walsh wrote: > Forgive me if I'm misremembering, but hasn't Greg argued against > the ability to supply "libraries" of re-usable scripts due to > the ease with which names could conflict with each other and cause > script incompatibilities? Namespace collisions are certainly an issue, yes. But my primary argument against trying to write "libraries" in bash has always been the limitations of bash's functions. 1) You can't return values from them (making them more like "commands" than actual functions). 2) You can't pass variables by reference. Therefore: 3) You can't pass the name of a variable in which you'd like to receive a value from the function, to work around point 1. 4) You can't pass an array by name. You have to pass every single array element separately, losing the indices in the process. "declare -n" looks like it should address point 2, but it doesn't do so safely. It only works if you magically choose a name (within the function) that the caller does NOT choose (outside the function). In fact, the caller's variable name must not match ANY local variable of the function, or it breaks. See examples at <http://mywiki.wooledge.org/BashProgramming#Functions>. If your function is recursive (is its own caller), then you're simply doomed -- you can't avoid having the same name used in the caller and callee, because they're both the same piece of code. You might be able to hack up a global indexed array of return values, and then each instance of the recursive function can use its recursion depth as an index into this array to retrieve its return value. That's the best I can think of.