Re: declare [-+]n behavior on existing (chained) namerefs

2016-05-26 Thread Piotr Grzybowski
On 26 May 2016, at 21:03, Chet Ramey wrote:

> On 4/27/16 3:26 PM, Grisha Levit wrote:
>> |declare -n name=value|, when |name| is already a nameref, shows the
>> following presumably inconsistent behavior:
> 
> There's a fairly compelling argument -- and I think Piotr made it -- that
> `declare -n' shouldn't follow the nameref chain at all.  If it does, you
> have to do something clumsy like removing the nameref attribute or
> unsetting and recreating it to change the value assigned to a nameref.
> ksh93 doesn't follow the chain, or does so inconsistently.

 Frankly, I have no idea who made it but I do think that declare -n should not 
follow anything, and that is what I would expect when I type declare -n rea=a;
 Concerning the namerefs I would keep things as simple as they can be and above 
all else: consistent. This thread gets longer than the whole implementation, 
including patches from crazy people (like me).

 cheers,
pg




Re: declare [-+]n behavior on existing (chained) namerefs

2016-05-26 Thread Chet Ramey
On 4/27/16 3:26 PM, Grisha Levit wrote:
> |declare -n name=value|, when |name| is already a nameref, shows the
> following presumably inconsistent behavior:

There's a fairly compelling argument -- and I think Piotr made it -- that
`declare -n' shouldn't follow the nameref chain at all.  If it does, you
have to do something clumsy like removing the nameref attribute or
unsetting and recreating it to change the value assigned to a nameref.
ksh93 doesn't follow the chain, or does so inconsistently.

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: declare [-+]n behavior on existing (chained) namerefs

2016-05-14 Thread Piotr Grzybowski
On 13 May 2016, at 23:31, Grisha Levit wrote:

> All the behavior inside functions now seems consistent with what is in the 
> docs. But the behavior at global scope still seems strange (sorry if this is 
> still a WIP):
> Each of the following produces different results in global scope and inside a 
> function: [..]

 judging from the comments in declare_internal the behaviour in global scope is 
intentional, while at the same time in function scope, the local variables are 
created unconditionally.
 when I type:

declare -n r=a

I would expect a new variable r with nameref attribute to be created pointing 
to variable of name a, no matter what kind of wicked chains of namerefs Grisha 
created earlier. Concerning 

declare +n r=a

I am not sure, but it would seem as logical to just create a variable r of 
value a.
 After all this is what those command say: declare and assign a variable. If 
you want nameref resolving, declare is not the correct place to do it.
 Both fixes can be easily done in declare_internal, decision being the 
difficult part.

cheers,
pg




Re: declare [-+]n behavior on existing (chained) namerefs

2016-05-13 Thread Grisha Levit
On Thu, May 5, 2016 at 2:22 PM, Chet Ramey  wrote:

> The only buggy behavior when inside of functions (ignoring scope issues)
> > seems to be that `declare -n ref’ unsets the value of $ref if it
> previously
> > pointed to a variable that is unset.
>
> I fixed this as part of making other changes prompted by the discussion.

All the behavior inside functions now seems consistent with what is in the
docs. But the behavior at global scope still seems strange (sorry if this
is still a WIP):

Each of the following produces different results in global scope and inside
a function:

$ unset -n r{1,2}; declare -n r1=r2 r2=x; *declare -n r1=y*; declare -p r{1,2}
declare *-n r1="r2"*
declare *-n r2="y"*

$ f() { !!; }; f
declare -n r1="y"
declare -n r2="x"

$ unset -n r{1,2}; declare -n r1=r2 r2=x; *declare +n r1=y*; declare -p r{1,2}
declare *-n r1="r2"*
declare *-- r2="x"*

$ f() { !!; }; f
declare *--* r1="y"
declare -n r2="x"

Also the following case that does not even involve any chains works
differently:

$ declare -n ref=var; *declare +n ref=foo*; declare -p ref
declare -- ref="*var*"

$ f() { !!; }; f
declare -- ref="*foo*"

​


Re: declare [-+]n behavior on existing (chained) namerefs

2016-05-05 Thread Chet Ramey
On 4/28/16 9:49 PM, Grisha Levit wrote:

> In a slightly different version, with `declare -n r; r=a', the function
> exits with code 1 after the `r=a' statement:
> 
> $ declare -nt r=a; f() { declare a; declare -n r; r=a; declare -p a r; };
> f; echo $?
> 1

In this case, you create a self-referencing local nameref, which ends up
resolving to nothing, which causes an assignment error, which results in
function execution being aborted.  You create the self-referencing local
nameref because bash follows the nameref chain for `r', and resolves it
to `a'.  It's as Piotr surmised: as if you ran `typeset -n a; a=a'.

When asked to create a local variable that shadows a nameref from a
different context, declare needs to throw away the results of that nameref
chain search and just create a local variable.

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: declare [-+]n behavior on existing (chained) namerefs

2016-05-05 Thread Chet Ramey
On 5/2/16 1:55 PM, Piotr Grzybowski wrote:
> Hi,
> 
>  I hope the attached patch does not break to much; it addresses the masking:
> 
>> declare -nt r=a; f() { declare a; declare -n r=a; declare -p a r; }; f
> 
> as per Grisha's report; it tries to enlighten make_local_variable to the 
> existence of nameref by returning existing local nameref in scope (declare -n 
> r=PATH; declare -n r; returns r with value of PATH) and by (hopefully) 
> correctly making existing nameref take precedence over the dereferenced value.
> 
>  Would you please consider it?

Thanks, this is a good fix.

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: declare [-+]n behavior on existing (chained) namerefs

2016-05-05 Thread Chet Ramey
On 4/29/16 12:50 PM, Grisha Levit wrote:

> The only buggy behavior when inside of functions (ignoring scope issues)
> seems to be that `declare -n ref’ unsets the value of $ref if it previously
> pointed to a variable that is unset.
> 
> |$ f() { unset var; declare -n ref=var; declare -n ref; declare -p ref; }; f
> declare -n ref # why did the value of ref disappear? $ f() { local var;
> declare -n ref=var; declare -n ref; declare -p ref; }; f declare -n ref="var" 
> |

I fixed this as part of making other changes prompted by the discussion.


-- 
``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: declare [-+]n behavior on existing (chained) namerefs

2016-05-02 Thread Piotr Grzybowski
Hi,

 I hope the attached patch does not break to much; it addresses the masking:

> declare -nt r=a; f() { declare a; declare -n r=a; declare -p a r; }; f

as per Grisha's report; it tries to enlighten make_local_variable to the 
existence of nameref by returning existing local nameref in scope (declare -n 
r=PATH; declare -n r; returns r with value of PATH) and by (hopefully) 
correctly making existing nameref take precedence over the dereferenced value.

 Would you please consider it?

cheers,
pg





masking_nameref_with_local_vars.patch
Description: Binary data


On 29 Apr 2016, at 03:49, Grisha Levit wrote:

> There is also an issue when doing something like `declare -n r=a' in a 
> function if the same has been done in a higher scope.  Instead of creating a 
> new variable r in the function's scope, it modifies the local `a' to be a 
> self-referencing nameref..
> 
> $ declare -nt r=a; f() { declare a; declare -n r=a; declare -p a r; }; f
> declare -n a="a"# ??
> declare -nt r="a"   # note the -t.  this is the outer $r, a new one was not 
> created
> 
> In a slightly different version, with `declare -n r; r=a', the function exits 
> with code 1 after the `r=a' statement:
> 
> $ declare -nt r=a; f() { declare a; declare -n r; r=a; declare -p a r; }; f; 
> echo $?
> 1



Re: declare [-+]n behavior on existing (chained) namerefs

2016-04-30 Thread Piotr Grzybowski

 after discussion with Grisha, the reason to different behaviour between:

f() { declare -n ref=var; declare -n ref; declare -p ref; }; f

and

f() { local var; declare -n ref=var; declare -n ref; declare -p ref; }; f

is:

in function context declare built-in always calls make_local_variable. this 
routine has no idea that the second declare re-declares already declared 
reference, and calls make_new_variable. the difference is: make_local_variable 
will not create a local variable when there is already one, hence everything 
seems fine. make_local_variable should check find_variable_noref(name) and act 
accordingly.
 It seems half-intended.

pg

On 30 Apr 2016, at 22:24, Grisha Levit wrote:

> I just re-built bash-20160415 snapshot and am observing the same behavior.  
> To clarify, the first case is the unexpected one -- shouldn't `declare -n 
> ref=var; declare -n ref' be a no-op, no matter if $var is set or not?  It is 
> a no-op when in global scope, but not inside a function.




Re: declare [-+]n behavior on existing (chained) namerefs

2016-04-30 Thread Piotr Grzybowski
On 30 Apr 2016, at 22:24, Grisha Levit wrote:

> I just re-built bash-20160415 snapshot and am observing the same behavior.  
> To clarify, the first case is the unexpected one -- shouldn't `declare -n 
> ref=var; declare -n ref' be a no-op, no matter if $var is set or not?  It is 
> a no-op when in global scope, but not inside a function.

I rebuilt just now, both on mac os x 10.6 and on linux i686, I cannot reproduce 
it:

$ f() { unset var; declare -n ref=var; declare -n ref; declare -p ref; }; f
declare -n ref
$ echo $BASH_VERSION
4.4.0(1)-rc2
$ git log -1 | head -1
commit 3475994a81ce49cf3a50b6ceeb5ad719986aa5f4

could you share your environment, platform, etc?
 I also debugged unset_builtin, it does some unnecessary calls for no existent 
variables, but nothing that would justify this behaviour.

pg




Re: declare [-+]n behavior on existing (chained) namerefs

2016-04-30 Thread Grisha Levit
I just re-built bash-20160415 snapshot and am observing the same behavior.
To clarify, the first case is the unexpected one -- shouldn't `declare -n
ref=var; declare -n ref' be a no-op, no matter if $var is set or not?  It
is a no-op when in global scope, but not inside a function.


Re: declare [-+]n behavior on existing (chained) namerefs

2016-04-30 Thread Piotr Grzybowski
hi,

 this one is not present in current devel, I would consider it fixed already.

pg

On 29 Apr 2016, at 18:50, Grisha Levit wrote:

> I should note also that the behavior when inside a function matches exactly 
> what the manual says.  It’s the global namerefs that have this unexpected 
> behavior of following the chain to the end and and modifying only the last 
> nameref in the chain.
> 
> The only buggy behavior when inside of functions (ignoring scope issues) 
> seems to be that `declare -n ref’ unsets the value of $ref if it previously 
> pointed to a variable that is unset.
> 
> $ f() { unset var; declare -n ref=var; declare -n ref; declare
>  -p ref; }; f
> 
> declare -n ref # why did the value of ref disappear?
> 
> 
> $ 
> f() { local var; declare -n ref=var; declare -n ref; declare
>  -p ref; }; f
> 
> declare -n ref="var"




Re: declare [-+]n behavior on existing (chained) namerefs

2016-04-29 Thread Grisha Levit
I should note also that the behavior when inside a function matches exactly
what the manual says. It’s the global namerefs that have this unexpected
behavior of following the chain to the end and and modifying only the last
nameref in the chain.

The only buggy behavior when inside of functions (ignoring scope issues)
seems to be that `declare -n ref’ unsets the value of $ref if it previously
pointed to a variable that is unset.

$ f() { unset var; declare -n ref=var; declare -n ref; declare -p ref;
}; fdeclare -n ref # why did the value of ref disappear?

$ f() { local var; declare -n ref=var; declare -n ref; declare -p ref;
}; fdeclare -n ref="var"

​


Re: declare [-+]n behavior on existing (chained) namerefs

2016-04-29 Thread Piotr Grzybowski

On 29 Apr 2016, at 03:49, Grisha Levit wrote:

> There is also an issue when doing something like `declare -n r=a' in a 
> function if the same has been done in a higher scope.  Instead of creating a 
> new variable r in the function's scope, it modifies the local `a' to be a 
> self-referencing nameref..
> 
> $ declare -nt r=a; f() { declare a; declare -n r=a; declare -p a r; }; f
> declare -n a="a"# ??
> declare -nt r="a"   # note the -t.  this is the outer $r, a new one was not 
> created

 yes, the "reference masking" is not done properly, the fix seems easy, it is a 
bug in my opinion.

> In a slightly different version, with `declare -n r; r=a', the function exits 
> with code 1 after the `r=a' statement:
> 
> $ declare -nt r=a; f() { declare a; declare -n r; r=a; declare -p a r; }; f; 
> echo $?
> 1

this is due to the fact that there is a 

bash: warning: r: circular name reference

as can be seen with slightly modified version of your script:

declare -n r=a; f() { declare a=12; declare -n r=a; r=a; declare -p a r; }; f

also should be fixed.

cheers,
pg





Re: declare [-+]n behavior on existing (chained) namerefs

2016-04-28 Thread Grisha Levit
There is also an issue when doing something like `declare -n r=a' in a
function if the same has been done in a higher scope.  Instead of creating
a new variable r in the function's scope, it modifies the local `a' to be a
self-referencing nameref..

$ declare -nt r=a; f() { declare a; declare -n r=a; declare -p a r; }; f
declare -n a="a"# ??
declare -nt r="a"   # note the -t.  this is the outer $r, a new one was not
created

In a slightly different version, with `declare -n r; r=a', the function
exits with code 1 after the `r=a' statement:

$ declare -nt r=a; f() { declare a; declare -n r; r=a; declare -p a r; };
f; echo $?
1


Re: declare [-+]n behavior on existing (chained) namerefs

2016-04-27 Thread Grisha Levit
> interpret "on the variable" as doing a depth first search (going as deep
as possible over the reference chain) in order to find the variable

Yes, that makes perfect sense, but I think all the issues above don't
concern the search for the variable, but rather modifications to the
references themselves.

This might just be a documentation issue, as the docs state that something
different should be happening:

1. It seems unambiguous from the description that `declare +n ref_1' should
remove the nameref attribute from ref_1, not from any other variable

2. A strict interpretation would also suggest that `declare -n ref_1=foo'
should change the value of the variable referenced by the nameref (or the
chain of references), not the value of ref_N.  I don't know if that's
really the implementation's intention -- perhaps adding a note to the "If a
variable name is followed by =value, the value of the variable ..." section
of the declare builtin's description would help clarify this case.


On Wed, Apr 27, 2016 at 5:54 PM, Piotr Grzybowski 
wrote:

>
>  this one does not seem like a bug to me, rather a decision made by the
> author: to interpret "on the variable" from this:
>
> "All references, assignments, and attribute modifications to name, except
> for changing the -n attribute itself, are performed on the variable
> referenced by name’s value."
>
> as doing a depth first search (going as deep as possible over the
> reference chain) in order to find the variable. The last case you mention
> is discussable: when the leaf is an empty reference should +n do something?
> Probably should do the same as declare +n ref_N; which I think is just to
> leave a variable with identifier ref_N. But then, ref_((N-1)) points to a
> variable and suddenly there is a potentially unexpected change in your
> lovely tree of empty references.
>  One can argue: if you pass the ref_i to some function, and you want to
> modify ref_N how to do it? The choice made seems fairy logical, I am not
> saying that it is the best possible one though.
>
> cheers,
> pg
>
>
>
> On 27 Apr 2016, at 21:26, Grisha Levit wrote:
>
> > declare -n name=value, when name is already a nameref, shows the
> following presumably inconsistent behavior:
> >
> > Given a chain of namerefs like:
> >
> > ref_1 -> ref_2 -> ... -> ref_i ... -> ref_N [-> var]
> >
> >   • If ref_N points to a name that is not a nameref, the operations
> declare -n ref_N=value and declare +n ref_N modify the value/attributes of
> ref_N (this seems to be the desired behavior)
> >   • For i value/attributes of ref_N and not of ref_i
> >   • If ref_N is declared as a nameref but unset, then these
> operations on ref_i have no effect.
> > For example, starting with:
> >
> > unset -n ref{1..3
> > }
> >
> > declare
> >  -n ref1=ref2 ref2=ref3 ref3=var1
> >
> > # declare -n ref1=var2
> > # declare -p ref{1..4}
> > declare -n ref1="ref2"   # unchanged
> > declare -n ref2="ref3"
> > declare -n ref3="var2"   # changed
> > # declare +n ref1
> > # declare -p ref{1..3}
> > declare -n ref1="ref2"   # unchanged
> > declare -n ref2="ref3"
> > declare -- ref3="var1"   # changed, no loner nameref
> > Or alternatively:
> >
> > unset -n ref{1..3
> > }
> >
> > declare
> >  -n ref1=ref2 ref2=ref3 ref3
> >
> > # declare +n ref1
> > # declare -p ref{1..3}
> > declare -n ref1="ref2"   # unchanged
> > declare -n ref2="ref3"   # unchanged
> > declare -n ref3  # unchanged
> > # declare -n ref1=var1
> > # declare -p ref{1..3}
> > declare -n ref1="ref2"
> > declare -n ref2="ref3"
> > declare
> >  -n ref3
> >
> > The man page says:
> >
> > All references, assignments, and attribute modifications to name, except
> for changing the -n attribute itself, are performed on the variable
> referenced by name’s value.
> >
> > This does not appear to be the case, as declare -n ref_N=value changes
> $ref_N, not $value, and declare +n ref_i changes ref_N.
> >
>
>


Re: declare [-+]n behavior on existing (chained) namerefs

2016-04-27 Thread Piotr Grzybowski

 this one does not seem like a bug to me, rather a decision made by the author: 
to interpret "on the variable" from this:

"All references, assignments, and attribute modifications to name, except for 
changing the -n attribute itself, are performed on the variable referenced by 
name’s value."

as doing a depth first search (going as deep as possible over the reference 
chain) in order to find the variable. The last case you mention is discussable: 
when the leaf is an empty reference should +n do something? Probably should do 
the same as declare +n ref_N; which I think is just to leave a variable with 
identifier ref_N. But then, ref_((N-1)) points to a variable and suddenly there 
is a potentially unexpected change in your lovely tree of empty references.
 One can argue: if you pass the ref_i to some function, and you want to modify 
ref_N how to do it? The choice made seems fairy logical, I am not saying that 
it is the best possible one though.

cheers,
pg



On 27 Apr 2016, at 21:26, Grisha Levit wrote:

> declare -n name=value, when name is already a nameref, shows the following 
> presumably inconsistent behavior:
> 
> Given a chain of namerefs like:
> 
> ref_1 -> ref_2 -> ... -> ref_i ... -> ref_N [-> var]
> 
>   • If ref_N points to a name that is not a nameref, the operations 
> declare -n ref_N=value and declare +n ref_N modify the value/attributes of 
> ref_N (this seems to be the desired behavior)
>   • For i value/attributes of ref_N and not of ref_i
>   • If ref_N is declared as a nameref but unset, then these operations on 
> ref_i have no effect.
> For example, starting with:
> 
> unset -n ref{1..3
> }
> 
> declare
>  -n ref1=ref2 ref2=ref3 ref3=var1
> 
> # declare -n ref1=var2
> # declare -p ref{1..4}
> declare -n ref1="ref2"   # unchanged
> declare -n ref2="ref3"
> declare -n ref3="var2"   # changed
> # declare +n ref1
> # declare -p ref{1..3}
> declare -n ref1="ref2"   # unchanged
> declare -n ref2="ref3"
> declare -- ref3="var1"   # changed, no loner nameref
> Or alternatively:
> 
> unset -n ref{1..3
> }
> 
> declare
>  -n ref1=ref2 ref2=ref3 ref3
> 
> # declare +n ref1
> # declare -p ref{1..3}
> declare -n ref1="ref2"   # unchanged
> declare -n ref2="ref3"   # unchanged
> declare -n ref3  # unchanged
> # declare -n ref1=var1
> # declare -p ref{1..3}
> declare -n ref1="ref2"
> declare -n ref2="ref3"
> declare
>  -n ref3
> 
> The man page says:
> 
> All references, assignments, and attribute modifications to name, except for 
> changing the -n attribute itself, are performed on the variable referenced by 
> name’s value.
> 
> This does not appear to be the case, as declare -n ref_N=value changes 
> $ref_N, not $value, and declare +n ref_i changes ref_N.
> 




declare [-+]n behavior on existing (chained) namerefs

2016-04-27 Thread Grisha Levit
declare -n name=value, when name is already a nameref, shows the following
presumably inconsistent behavior:

Given a chain of namerefs like:

ref_1 -> ref_2 -> ... -> ref_i ... -> ref_N [-> var]

   - If ref_N points to a name that is not a nameref, the operations declare
   -n ref_N=value and declare +n ref_N modify the value/attributes of ref_N
   (this seems to be the desired behavior)
   - For i