Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Up-scope named references, vs. ksh



On Sun, Mar 3, 2024 at 12:27 PM Stephane Chazelas <stephane@xxxxxxxxxxxx> wrote:
>
> 2024-03-03 11:04:03 -0800, Bart Schaefer:
> >
> > If the parameter is magically created "in advance" (at the point of
> > "typeset -n") then it only works for global scalars
>
> Why would we need it for any other scope? If the parameter is
> not found in any scope, then it must be created in global scope.
>
> That's what "read var" does.

The word "scalar" is just as important in that sentence as the word
"global" -- "read" and "zstat" can specify whether the variable is
scalar or array, you can't do that with a nameref.  Furthermore, if
there's a local in scope at the point where "read var" is called, it
assigns to the local, even if the local is unset.  The scope is
determined at the point of assignment.

Locals consume the space allocated in the parameter table for the
corresponding name.  This is a longstanding, conscious decision in the
parameter implementation, I even quoted a code comment to that effect
in the thread about unsetting tied parameters.  With -u, a nameref can
skip over one local, but it can't "make room" for a global that didn't
already exist. I've tried several different ways to explain this, so
I'm just going to ignore this going forward.

> Many if not most of the usages of
> namerefs I've come across were to implement "read"-like commands
> that return or can return something in a variable whose name is given by the
> caller (and that can create the variable if needed).

There's nothing in the current implementation that prevents you from
doing that if you choose your local names appropriately (and if
nothing above you in the call chain hasn't already co-opted the name).

> Where an approximation of what I'm suggesting is implemented in
> zsh seems to work fine (with your patch applied).

But that approach doesn't work in the general case!  If you move
  typeset value=$2
to above the [[ -v $1 ]], then it either bombs, or assigns to the
"wrong" $value.

There's no way to magically get this right in the internal
implementation, it has to be handled in shell code.

> It segfaults with zsh -x though

I'll have a look at that later, thanks.

> > If a function wants to be able to actually add things to its calling
> > scope without fear of name clashes, it has to use unique local names
> > (e.g., a namespace).  But with dynamic scoping it remains the case
> > that you can't add a name to the global scope if any function in the
> > call chain has pre-empted that name -- named references don't change
> > this basic rule.
>
> I really don't follow, dynamic scoping should make things easier
> here.

Consider the case where your function is called 2 or more levels
removed from the global scope.

> but having namerefs that can't create globals seems like a very
> severe limitations to me

It's the same limitation as
() {
  local foo
  unset foo
  () { foo=bar }
}
which despite the appearance of the assignment in the nested function,
doesn't create a global foo, it resurrects the caller's local foo.
Ksh has static local scope (and an entirely different internal
representation of parameters) so the local foo makes no difference to
the nested function.




Messages sorted by: Reverse Date, Date, Thread, Author