Date: Wed, 28 Feb 2018 10:27:23 -0500 From: Chet Ramey <chet.ra...@case.edu> Message-ID: <ba594d01-b9c4-5cd8-9fa0-2f20fd1d2...@case.edu>
| These are two different cases -- same context vs. a previous context. Your | example is not the same as the original poster's. OK, though I am not sure why that should make a difference. | This was poorly phrased, but I amended it in a subsequent message. Yes, I saw the update - I only quoted that part to make the point that I had not seen (or if I did, it was briefly, and I no longer recall it) the original message. The original problem isn't, or wasn't (still isn't) material to my comment. Quoting from multiple messages is more work, and this was not important, so I just kept the original. | The global var is left unchanged, and satisfies references to $var with v1. The second clause of that is what is brain dead. There should be a simple invariant in all shell contexts, which is unset X Y=$X assigns the null string to Y (except in the case where X is read only, which is not a case of concern here.) Always. No (other) exceptions. None. Similarly the expression ${X-unset} should always produce "unset" if X has been unset and not subsequently given a value. Whatever else is believed about how variables should work, that part should remain true - if we cannot rely upon unset working to create an unset variable, then we're lost. I could almost understand it in the context of the unset being in the same function as the variable was declared local - that is, defining unset to be some kind of unlocal command (though I think it would be a very poor idea to abuse unset that way - if an unlocal is needed, make it something different) but having that happen, in a function that believes that X is just some global variable name is lunacy (where it happens not to be as it was called from another function which had made X local.) | The original poster wanted ... No comment on that, he/she can speak for him/herself if there's anything here relevant to the original message. It sounds from what you are saying that the request was for static scoped variables (what David Korn wanted to have, as I understand it) - the same kind of vars that exist in most compiled programming languages. if so, I agree, that is not what the shell offers (except perhaps ksh when using its "function x" type functions.) Dynamic scoping is far more useful in languages like sh (particularly ones used interactively.) | There is code that implements your preferred interpretation of `removed' | when the `unset' is performed in the same context as the local variable | declaration. When `unset' removes a variable at a previous scope, which | can be a calling function due to dynamic scoping, it just removes the | variable. If there was a justification for different cases, that's backwards. But better to always simply make unset do an unset on whatever the currently visible instance of the variable is, and leave it at that. | There are several behavior choices here. You can simply remove all | instances of the variable back to the global scope until there are no | traces of the name remaining. That would be wrong. The whole point of "local" is so that functions can use variable names without caring whether the same name exists in the caller's scope - changing anything other than the local copy would defeat that purpose. | You can mark any local instances in previous | scopes (or the nearest previous scope that has a local instance of | that variable) with a special `unset' attribute that will cause | references to it to behave as if it were unset, leaving the global | value unchanged. Yes. That's the correct way I believe. One way to implement that is simply to unset (however that is implemented in the case of global vars and no functions at all) the variable - and then when the function that made the variable local returns, replace the previous value/attributes from somewhere they had been saved. Or there can be some ":var is unset" flag. Or probably several other implementation choices. | Or you can remove the instance in the nearest previous | scope in the call chain, leaving other instances alone. Bash chooses | the last. Apparently except when the nearest previous scope is the current scope? I can only imagine that the reason for this is that any other behaviour would generate complaints by the millions - and that there are less in the other cases is merely because it is rare for this to ever actually happen. Are you sure that the original complaint was not just that after "unset X" X was not null (in the scope where the unset was performed) ? Lastly, where does the notion of "remove" come from? unset is unset. There's nothing in POSIX about removing anything, just unsetting the variable (and no longer exporting it). As an implementation technique you might (and probably would) choose to remove the data structs related to a variable that has been unset, just to save memory, but that's purely implementtaion, and should not affect the visible behaviour. If you believe some kind of variable removing command is needed, implement that - just don't call iit unset. kre