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

Re: Up-scope named references, vs. ksh



2024-03-03 11:04:03 -0800, Bart Schaefer:
[...]
> >   typeset -n var=$1
> >   typeset    value=$2
> 
> 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. 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).

> if you try to
> create an array using "var" you run into baffling stuff like this:
> 
> assign:3: value: attempt to assign array value to non-array
> 

assign() {
  if [[ -v $1 ]]; then
    typeset -n var=$1
  else
    eval "$1="
    typeset -n var=$1
    unset var
  fi
  typeset value=$2
  var=(var now set with value $value)
}
assign value x
typeset -p value


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

It segfaults with zsh -x though

$ ./Src/zsh  ~/a
typeset -a value=( var now set with value x )
$ gdb -q --args ./Src/zsh -x  ~/a
Reading symbols from ./Src/zsh...
(gdb) r
Starting program: /home/chazelas/install/cvs/zsh/Src/zsh -x /home/chazelas/a
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
+/home/chazelas/a:12> assign value x
+assign:1> [[ -v value ]]
+assign:4> eval 'value='
+(eval):1> value=''
+assign:5> typeset -n var=value
+assign:6> unset var
+assign:8> typeset value=x

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7cfb3fe in __GI___libc_free (mem=0x555555600) at ./malloc/malloc.c:3368
3368    ./malloc/malloc.c: No such file or directory.
(gdb) bt
#0  0x00007ffff7cfb3fe in __GI___libc_free (mem=0x555555600) at ./malloc/malloc.c:3368
#1  0x00005555555d5105 in zsfree (p=0x555555600 <error: Cannot access memory at address 0x555555600>) at mem.c:1878
#2  0x0000555555625482 in freearray (s=0x555555683d88) at utils.c:4100
#3  0x00005555555ea0e6 in arrsetfn (pm=0x555555683da0, x=0x555555683f40) at params.c:3996
#4  0x00005555555e5691 in setarrvalue (v=0x7fffffffc360, val=0x555555683f40) at params.c:2889
#5  0x00005555555e8537 in assignaparam (s=0x7ffff7fac733 "", val=0x555555683f40, flags=6) at params.c:3538
#6  0x00005555555943f7 in addvars (state=0x7fffffffcda0, pc=0x55555567d508, addflags=0) at exec.c:2631
#7  0x000055555559639b in execcmd_exec (state=0x7fffffffcda0, eparams=0x7fffffffc9b0, input=0, output=0, how=18, last1=2, close_if_forked=-1) at exec.c:3363
#8  0x00005555555926c8 in execpline2 (state=0x7fffffffcda0, pcode=643, how=18, input=0, output=0, last1=0) at exec.c:2016
#9  0x000055555559125c in execpline (state=0x7fffffffcda0, slcode=10242, how=18, last1=0) at exec.c:1741
#10 0x000055555559049e in execlist (state=0x7fffffffcda0, dont_change_job=1, exiting=0) at exec.c:1495
#11 0x000055555558fabe in execode (p=0x55555567d3f0, dont_change_job=1, exiting=0, context=0x5555556310da "shfunc") at exec.c:1276
#12 0x000055555559e87a in runshfunc (prog=0x55555567d3f0, wrap=0x0, name=0x7ffff7fac170 "assign") at exec.c:6164
#13 0x000055555559dd8a in doshfunc (shfunc=0x55555567d570, doshargs=0x7ffff7fb7b18, noreturnval=0) at exec.c:6010
#14 0x000055555559ca1d in execshfunc (shf=0x55555567d570, args=0x7ffff7fb7b18) at exec.c:5548
#15 0x0000555555598a9c in execcmd_exec (state=0x7fffffffdad0, eparams=0x7fffffffd6e0, input=0, output=0, how=18, last1=2, close_if_forked=-1) at exec.c:4075
#16 0x00005555555926c8 in execpline2 (state=0x7fffffffdad0, pcode=835, how=18, input=0, output=0, last1=0) at exec.c:2016
#17 0x000055555559125c in execpline (state=0x7fffffffdad0, slcode=5122, how=18, last1=0) at exec.c:1741
#18 0x000055555559049e in execlist (state=0x7fffffffdad0, dont_change_job=0, exiting=0) at exec.c:1495
#19 0x000055555558fabe in execode (p=0x7ffff7fb7a30, dont_change_job=0, exiting=0, context=0x555555632b86 "toplevel") at exec.c:1276
#20 0x00005555555b7cb0 in loop (toplevel=1, justonce=0) at init.c:212
#21 0x00005555555bc7a9 in zsh_main (argc=3, argv=0x7fffffffddf8) at init.c:1934
#22 0x000055555556c99d in main (argc=3, argv=0x7fffffffddf8) at ./main.c:93
(gdb)

> I think it's much more consistent for dynamic scoping to apply at the
> time $var is referenced or assigned.
> 
> The patch in workers/52650 allows something like this to work:
> 
> assign() {
>   typeset value=$2
>   typeset -nu var=$1 # ignore local $value
>   case ${(t)var} in
>   (*scalar*)  var=$value;;
>   (*array*)  var=( $value );;
>   (*) print -u2 cannot assign;;
>   esac
> }
> declare -a value
> assign value x
> 
> 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.

If the caller does "local var; assign var value", then obviously
they want value to be assigned to their var, not have one
created in the global scope instead. It's easy in a shell with
dynamic scoping as a function sees the local variables of its
caller anyway (for instance, my [[ -v $1 ]] above will see).

That typeset -nu var is useful indeed as it allows one to
declare local variables *before* tying namerefs to variables,
but having namerefs that can't create globals seems like a very
severe limitations to me, all other shells with namerefs can do
it. zsh can do it except for that possible clash with local
variables declared *after* which it seems to me should be
avoidable.

-- 
Stephane




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