From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28141 invoked by alias); 30 Jun 2012 17:32:20 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 30551 Received: (qmail 4388 invoked from network); 30 Jun 2012 17:32:17 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 Received-SPF: none (ns1.primenet.com.au: domain at closedmail.com does not designate permitted sender hosts) From: Bart Schaefer Message-id: <120630103128.ZM30227@torch.brasslantern.com> Date: Sat, 30 Jun 2012 10:31:28 -0700 In-reply-to: <20120630050512.GA87092@redoubt.spodhuis.org> Comments: In reply to Phil Pennock "Re: 4.3.17 unset RPS1 vs RPROMPT" (Jun 29, 10:05pm) References: <20120629094045.GA96213@redoubt.spodhuis.org> <20120629195254.5dba2156@pws-pc.ntlworld.com> <20120630050512.GA87092@redoubt.spodhuis.org> X-Mailer: OpenZMail Classic (0.9.2 24April2005) To: zsh-workers@zsh.org Subject: Re: 4.3.17 unset RPS1 vs RPROMPT MIME-version: 1.0 Content-type: text/plain; charset=us-ascii On Jun 29, 10:05pm, Phil Pennock wrote: } } If the name could be rebound to another variable and no longer be magic, } the current approach would be sane, but it seems that perhaps the } correct behaviour should be to ensure that whatever the state of one } name, the other name should be in the same state: set, unset, empty, } with-content, whatever. There's some precedent for this; although $#, $@ and $* are read-only variables, if you "unset argv" you erase $* and $@, and $# becomes 0. On the other hand, argv has its own weird semantics (see below) which probably exempts it from this analogy. } Perhaps I've become contaminated with the Pythonic approach of being } distinct about the binding of a name to a variable versus the changing } of the value of a variable. I think this comes down to a scoping issue. Shell variables have a form of dynamic scoping that's somewhat different from that of any other interpreted language. In the first shells, all variables were environment variables. Then shell variables became a separate thing and the idea of exporting them into the environment was introduced, but there was still only one global scope. Then local scopes were introduced, but to retain the semantics of the former global scope, the local scopes became dynamic, based on runtime call heirarchy rather than code structure. Once a shell variable has a scope, unsetting the variable does not delete it from that scope. If you re-use the name, it returns in the same scope where it was originally defined, unless you are declaring it in a new dynamic scope. You can't change the magic binding in the original scope; that's what it means for the variable to be "special". But you can rebind them in any scope other than the global one, and thus in all dynamically nested scopes, with e.g. "local -h RPROMPT". Weird semantics: Although argv is seems implicitly to be local in all scopes, unsetting without first actually declaring it local causes it to disappear in all scopes, which breaks the connection to $* et al. torch% showargv() { print -l "argv: $argv" "*: $*" } torch% noargv() { print -l "argv: $argv"; unset argv; print "*: $*" } torch% showargv one two three argv: one two three *: one two three torch% noargv four five six argv: four five six *: torch% showargv seven eight nine argv: *: seven eight nine torch% noargv gone gone gone argv: *: gone gone gone torch% Resetting it brings it back with full magic intact: torch% argv=() torch% showargv seven eight nine argv: seven eight nine *: seven eight nine torch% Of course I say "seems" to be local in all scopes because really it's the special binding to $@ and $* that makes it local; the name itself and its properties are still defined in the global scope.