Re: unset does not act as expected on namerefs
On Tue, Jun 2, 2015 at 7:31 AM, Greg Wooledge wool...@eeg.ccf.org wrote: There's declare -i, but no sane person USES that, so we can ignore it. While in bash `-i` likely either has no effect or slows things down very slightly, in ksh93 and probably zsh it's a huge performance win because it prevents integers and floats from being automatically coerced to and from a string on every operation. It also guarantees (after the attribute is set) that the value will never be anything other than the right type unless the attribute is explicitly removed. It's perfectly sane to use it for values that are always guaranteed correct by construction or by validation. (Use the `integer' and `float' aliases in ksh, which are preset to use the largest currently available type). So long as you always remember to initialize the variable you can't really go wrong with it.
Re: unset does not act as expected on namerefs
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On 6/1/15 9:59 PM, Shawn Wilson wrote: Top posting as I'm kinda going out of band of the thread here; Having read the discussion, I guess the issue I brought up really isn't a bug (though Greg's points probably should be considered bugs). I'll preface this by saying I'm not an expert in bash by any means. However, most languages have a garbage collection facility which cleans up anonymous refs with nothing pointing to it and most high level languages make it easier to make a soft or symbolic reference than making hard references. But also, when you 'undef'/delete()/whatever the variable or the pointer, handle both and avoid this issue. While I do like the idea of pointers for bash variables, I would much prefer being able to create references. Also, whatever happens, I think there should also be a way to test for variable type (either another test flag or something like perl's ref() ). I think it's a case of mismatched expectations. There are a couple of ways to go with this, and I went with the way Korn specified `unset'. I initially implemented namerefs in bash without any special changes to unset, but ended up adding it for compatibility. Bash's dynamic scoping also drove some of the decisions. Just as you can follow the call chain to get different instances of a variable named `x', for example, you get the same kind of variable resolution with namerefs when you use `soft' symbolic references rather than `hard' pointer references. You absolutely have to be careful when you do this; this part of the shell is a sharp instrument. It's like I told Greg: dynamic scoping is fundamental to how bash works, and namerefs don't change that. (Bash-4.3 has a way to test whether or not a variable is a nameref: `test -R'.) There's no need to flame anyone about this. It's fair to discuss the rationale for design decisions. Chet - -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/ -BEGIN PGP SIGNATURE- Version: GnuPG v2 Comment: GPGTools - http://gpgtools.org iEYEARECAAYFAlVzIgoACgkQu1hp8GTqdKufHQCeL4Z0v8l9Au7hWJbr/lnT3NxI SOsAn1gDxHDXkshb8mfRaANy8dFyhOlh =bZx+ -END PGP SIGNATURE-
Re: unset does not act as expected on namerefs
On 6/2/15 11:37 AM, Greg Wooledge wrote: Ksh's nameref is completely different. With one of ksh's two different kinds of functions, you actually CAN use ksh nameref to pass a value back to the caller without variable name collisions. In my opinion, the most interesting thing about ksh93's namerefs is that they change ksh to allow dynamic scoping and give funtions access to a calling function's local variables. ksh93 doesn't normally allow that, and David Korn was very vocal about the superiority of ksh93's static scoping. -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: unset does not act as expected on namerefs
On Mon, Jun 01, 2015 at 09:59:51PM -0400, Shawn Wilson wrote: I'll preface this by saying I'm not an expert in bash by any means. However, most languages have a garbage collection facility C does not. Bash (all shells, really) is very strongly influenced by C. and most high level languages make it easier to make a soft or symbolic reference than making hard references. Bash is not a high-level language. Also, whatever happens, I think there should also be a way to test for variable type (either another test flag or something like perl's ref() ). Bash is not a strongly typed language. You've got strings, and indexed arrays, and associative arrays. That's all. (There's declare -i, but no sane person USES that, so we can ignore it.) You might be trying to do things that Bash is simply not designed to do. It's a shell.
Re: unset does not act as expected on namerefs
On Tue, Jun 02, 2015 at 11:16:27AM -0400, Shawn Wilson wrote: I would argue that a nameref is a variable type. I suppose you're right, insofar as it has its own special rules that you have to know about. A lot of people wanted declare -n to be more than it is. It's really just syntactic sugar that doesn't actually let you do anything you couldn't do already (with printf -v for assignment, and ${!foo} or eval for reference). So, like declare -i, it's something you can completely disregard if you're writing new scripts, and not maintaining other people's scripts. Ksh's nameref is completely different. With one of ksh's two different kinds of functions, you actually CAN use ksh nameref to pass a value back to the caller without variable name collisions. $ bash -c 'f() { local x=from_f; g x; }; g() { declare -n x=$1; echo $x; }; f' bash: warning: x: circular name reference $ ksh -c 'f() { typeset x=from_f; g x; }; g() { typeset -n x=$1; echo $x; }; f' ksh: typeset: x: invalid self reference $ ksh -c 'function f { typeset x=from_f; g x; }; function g { typeset -n x=$1; echo $x; }; f' from_f
Re: unset does not act as expected on namerefs
On +2015/06/02 08:31:57, Greg Wooledge wrote: Also, whatever happens, I think there should also be a way to test for variable type (either another test flag or something like perl's ref() ). Bash is not a strongly typed language. You've got strings, and indexed arrays, and associative arrays. That's all. (There's declare -i, but no sane person USES that, so we can ignore it.) You might be trying to do things that Bash is simply not designed to do. It's a shell. I would argue that a nameref is a variable type. pgpmvsk0XMiMp.pgp Description: PGP signature
Re: unset does not act as expected on namerefs
On 5/27/15 8:25 AM, Greg Wooledge wrote: 1) It doesn't cross scopes. It's not like Tcl's upvar at all. It only refers to a variable in the same scope (which, following the standard bash rules, means it'll recursively search upward until it finds a matching variable by name). This isn't about namerefs; namerefs don't change bash's scoping rules. 2) It allows arbitrary code execution, just like eval: imadev:~$ f() { declare -n foo=$1; echo $foo; } imadev:~$ f 'x[i=0$(date 2)]' Wed May 27 08:07:35 EDT 2015 So, given the nameref assignment, these two things are equivalent: echo ${x[i=0$(date 2)] echo $foo You might have a beef with the subscript in an array reference undergoing the usual set of word expansions, but this isn't anything nameref- specific. Here's another surprise, that I didn't know until now. Given the above, if we follow it up with another declaration of foo, it hides the nameref. But the nameref declaration is still there, lurking, waiting. imadev:~$ declare -A foo imadev:~$ foo[jug]=brown imadev:~$ declare -p foo somevariable declare -A foo='([jug]=brown )' bash: declare: somevariable: not found imadev:~$ unset foo imadev:~$ declare -p foo somevariable declare -n foo=somevariable bash: declare: somevariable: not found Thanks, this is an actual problem. The 'declare -A foo' doesn't look up foo for assignment, it looks up foo as if it were being referenced as $foo. I'll see what I need to do to fix it. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: unset does not act as expected on namerefs
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On 5/26/15 10:31 AM, Shawn Wilson wrote: swilson@swlap1:~/temp$ bash --version GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) swilson@swlap1:~/temp$ cat t.txt $ome text !n a file| swilson@swlap1:~/temp$ unset t swilson@swlap1:~/temp$ t=$( ./t.txt) swilson@swlap1:~/temp$ echo $t bash: $ome text !n a file|: invalid variable name for name reference This is pretty obviously not the entire story, since you've never assigned `t' the nameref attribute. If you run `declare -n t' after the unset, you'll see that error, but your transcript doesn't show you doing that. If you can show me a complete transcript I can tell you what's happening. It may be that you've discovered a bug, but it's hard to say. Chet - -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/ -BEGIN PGP SIGNATURE- Version: GnuPG v2 iEYEARECAAYFAlVl0ygACgkQu1hp8GTqdKspagCfXwqF2uqmwtMhs2vKHevGSJu2 1EAAn01FXqjv+RpKlilPQn7TxJRg1dMt =PQ5D -END PGP SIGNATURE-
Re: unset does not act as expected on namerefs
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On 5/26/15 5:02 PM, Shawn Wilson wrote: On +2015/05/26 18:05:18, Geir Hauge wrote: On Tue, May 26, 2015 at 11:00:45AM -0500, Eduardo A. Bustamante López wr ote: # Here we 'unset ref', which actually unsets 'var'. Then, we assign 'va r' to # 'ref', but since 'ref' is still a nameref, it instead assigns 'var' t o 'var'. dualbus@hp:~$ unset ref; ref=var; echo $ref; declare -p ref var declare -n ref=var dualbus@hp:~$ declare -p var declare -- var=var Ah, that explains it! Mystery solved, and no longer surprising behavior. If there's no good reason to keep this as is (some use case where this might be wanted and breaking backward compatibility - I can't see anyone actually *wanting* it this way) shouldn't it be changed? A behavior can be documented and still be bad. What behavior do you want? That namerefs should act transparently (that is, use the nameref variable's non-null value as the variable name to operate on) in all contexts *except* unset? - -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/ -BEGIN PGP SIGNATURE- Version: GnuPG v2 iEYEARECAAYFAlVl1JQACgkQu1hp8GTqdKudNQCeJn533z6DE//zfQLMVFctElOg DXkAniyUQHTEfGXcYJTqWHBJDgTOW4pG =Jrw3 -END PGP SIGNATURE-
Re: unset does not act as expected on namerefs
On Tue, May 26, 2015 at 11:24:57AM -0400, Shawn Wilson wrote: On +2015/05/26 11:04:38, Greg Wooledge wrote: On Tue, May 26, 2015 at 10:31:34AM -0400, Shawn Wilson wrote: swilson@swlap1:~/temp$ bash --version GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) swilson@swlap1:~/temp$ cat t.txt $ome text !n a file| swilson@swlap1:~/temp$ unset t swilson@swlap1:~/temp$ t=$( ./t.txt) swilson@swlap1:~/temp$ echo $t bash: $ome text !n a file|: invalid variable name for name reference swilson@swlap1:~/temp$ var=foo; declare -n t; t=var; unset t; echo $t bash: $ome text !n a file|: invalid variable name for name reference As surprising as that is, have a look at help unset: So current behavior should stand? I would think that unset (with no options) should DWIM. This behavior also seemed to surprise most on #bash IRC. This is not a bug for lack of documentation or not understanding the results after looking at the doc, but a wow, this is surprising - maybe this could behave in a manner so it's not so surprising. The surprising part is that it keeps the -n flag, but partially loses the nameref ability: $ var=foo; declare -n ref $ ref=var $ printf '%s - ' $ref; declare -p ref foo - declare -n ref=var $ unset ref $ ref=var $ printf '%s - ' $ref; declare -p ref var - declare -n ref=var $ ref=baz baz - declare -n ref=var -- Geir Hauge
Re: unset does not act as expected on namerefs
On Tue, May 26, 2015 at 05:47:30PM +0200, Geir Hauge wrote: [...] The surprising part is that it keeps the -n flag, but partially loses the nameref ability: $ var=foo; declare -n ref $ ref=var $ printf '%s - ' $ref; declare -p ref foo - declare -n ref=var $ unset ref $ ref=var $ printf '%s - ' $ref; declare -p ref var - declare -n ref=var $ ref=baz baz - declare -n ref=var I'm not so sure about that. Let's see it, step by step: # Here, we setup the whole thing, and everything works as expected. 'ref' points to 'var', and the value printed is that of 'var'. dualbus@hp:~$ var=foo; declare -n ref=var; echo $ref; declare -p ref foo declare -n ref=var # Here we 'unset ref', which actually unsets 'var'. Then, we assign 'var' to # 'ref', but since 'ref' is still a nameref, it instead assigns 'var' to 'var'. dualbus@hp:~$ unset ref; ref=var; echo $ref; declare -p ref var declare -n ref=var dualbus@hp:~$ declare -p var declare -- var=var # Here you assign 'baz' to 'var', through 'ref'. It works as documented. dualbus@hp:~$ ref=baz; echo $ref; declare -p ref var baz declare -n ref=var declare -- var=baz -- Eduardo Bustamante https://dualbus.me/
Re: unset does not act as expected on namerefs
On +2015/05/26 18:05:18, Geir Hauge wrote: On Tue, May 26, 2015 at 11:00:45AM -0500, Eduardo A. Bustamante López wrote: # Here we 'unset ref', which actually unsets 'var'. Then, we assign 'var' to # 'ref', but since 'ref' is still a nameref, it instead assigns 'var' to 'var'. dualbus@hp:~$ unset ref; ref=var; echo $ref; declare -p ref var declare -n ref=var dualbus@hp:~$ declare -p var declare -- var=var Ah, that explains it! Mystery solved, and no longer surprising behavior. If there's no good reason to keep this as is (some use case where this might be wanted and breaking backward compatibility - I can't see anyone actually *wanting* it this way) shouldn't it be changed? A behavior can be documented and still be bad. pgpOwZAk14bLp.pgp Description: PGP signature
unset does not act as expected on namerefs
swilson@swlap1:~/temp$ bash --version GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) swilson@swlap1:~/temp$ cat t.txt $ome text !n a file| swilson@swlap1:~/temp$ unset t swilson@swlap1:~/temp$ t=$( ./t.txt) swilson@swlap1:~/temp$ echo $t bash: $ome text !n a file|: invalid variable name for name reference swilson@swlap1:~/temp$ var=foo; declare -n t; t=var; unset t; echo $t bash: $ome text !n a file|: invalid variable name for name reference pgpk4Cwu_mrnZ.pgp Description: PGP signature
Re: unset does not act as expected on namerefs
On Tue, May 26, 2015 at 10:31:34AM -0400, Shawn Wilson wrote: swilson@swlap1:~/temp$ bash --version GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) swilson@swlap1:~/temp$ cat t.txt $ome text !n a file| swilson@swlap1:~/temp$ unset t swilson@swlap1:~/temp$ t=$( ./t.txt) swilson@swlap1:~/temp$ echo $t bash: $ome text !n a file|: invalid variable name for name reference swilson@swlap1:~/temp$ var=foo; declare -n t; t=var; unset t; echo $t bash: $ome text !n a file|: invalid variable name for name reference As surprising as that is, have a look at help unset: unset: unset [-f] [-v] [-n] [name ...] Unset values and attributes of shell variables and functions. For each NAME, remove the corresponding variable or function. Options: -ftreat each NAME as a shell function -vtreat each NAME as a shell variable -ntreat each NAME as a name reference and unset the variable itself rather than the variable it references
Re: unset does not act as expected on namerefs
On +2015/05/26 11:04:38, Greg Wooledge wrote: On Tue, May 26, 2015 at 10:31:34AM -0400, Shawn Wilson wrote: swilson@swlap1:~/temp$ bash --version GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) swilson@swlap1:~/temp$ cat t.txt $ome text !n a file| swilson@swlap1:~/temp$ unset t swilson@swlap1:~/temp$ t=$( ./t.txt) swilson@swlap1:~/temp$ echo $t bash: $ome text !n a file|: invalid variable name for name reference swilson@swlap1:~/temp$ var=foo; declare -n t; t=var; unset t; echo $t bash: $ome text !n a file|: invalid variable name for name reference As surprising as that is, have a look at help unset: So current behavior should stand? I would think that unset (with no options) should DWIM. This behavior also seemed to surprise most on #bash IRC. This is not a bug for lack of documentation or not understanding the results after looking at the doc, but a wow, this is surprising - maybe this could behave in a manner so it's not so surprising. unset: unset [-f] [-v] [-n] [name ...] Unset values and attributes of shell variables and functions. For each NAME, remove the corresponding variable or function. Options: -ftreat each NAME as a shell function -vtreat each NAME as a shell variable -ntreat each NAME as a name reference and unset the variable itself rather than the variable it references pgpTDG5rNHwS4.pgp Description: PGP signature
Re: unset does not act as expected on namerefs
On Tue, May 26, 2015 at 11:00:45AM -0500, Eduardo A. Bustamante López wrote: # Here we 'unset ref', which actually unsets 'var'. Then, we assign 'var' to # 'ref', but since 'ref' is still a nameref, it instead assigns 'var' to 'var'. dualbus@hp:~$ unset ref; ref=var; echo $ref; declare -p ref var declare -n ref=var dualbus@hp:~$ declare -p var declare -- var=var Ah, that explains it! Mystery solved, and no longer surprising behavior. -- Geir Hauge