zsh-users
 help / color / mirror / code / Atom feed
* unexpected unmodified variable
@ 2022-10-06 19:07 Ray Andrews
  2022-10-06 19:28 ` Peter Stephenson
  0 siblings, 1 reply; 9+ messages in thread
From: Ray Andrews @ 2022-10-06 19:07 UTC (permalink / raw)
  To: Zsh Users


func2 ()
{
count=2
echo from func2: $count
}

func1 ()
{
local count=1
func2
echo from func1: $count
count=1
var=$( func2 )
echo from func1: $count
echo var is: $var
}

$ func1
from func2: 2
from func1: 2
from func1: 1
var is: from func2: 2

... This catches me by surprise; when " var =$( func2 ) " happens I'm 
expecting 'func2' to do everything it does including reset 'count' to 
'2'.  Why doesn't it, and is there any way to solve that?  Hacking around:

func1 ()
{
local count=1
func2 > /dev/null

func2

}

... performs as I'm wanting it to but it's a bit disgusting.







^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: unexpected unmodified variable
  2022-10-06 19:07 unexpected unmodified variable Ray Andrews
@ 2022-10-06 19:28 ` Peter Stephenson
  2022-10-06 21:58   ` Ray Andrews
  0 siblings, 1 reply; 9+ messages in thread
From: Peter Stephenson @ 2022-10-06 19:28 UTC (permalink / raw)
  To: Zsh Users

On Thu, 2022-10-06 at 12:07 -0700, Ray Andrews wrote:
> ... This catches me by surprise; when " var =$( func2 ) " happens I'm 
> expecting 'func2' to do everything it does including reset 'count' to 
> '2'.  Why doesn't it, and is there any way to solve that?

$(...) causes a shell to be forked --- it runs in a different process,
prints its output to somewhere that's collected by the main shell,
then exits.  So the internal effects disapper.

There's no simple workaround if you want the output directly other than
what you tried.

You can make the function set a variable instead.

% foo() { typeset -g $1="this is returned from foo"; }
% foo myvar
% print $myvar
this is returned from foo

The -g in the typeset tells it not to create a local scope within foo.

Returning stuff in a sane way is a real weakness in shells.

pws



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: unexpected unmodified variable
  2022-10-06 19:28 ` Peter Stephenson
@ 2022-10-06 21:58   ` Ray Andrews
  2022-10-07  0:36     ` Bart Schaefer
  0 siblings, 1 reply; 9+ messages in thread
From: Ray Andrews @ 2022-10-06 21:58 UTC (permalink / raw)
  To: zsh-users


On 2022-10-06 12:28, Peter Stephenson wrote:

> $(...) causes a shell to be forked --- it runs in a different process,
> prints its output to somewhere that's collected by the main shell,
> then exits.  So the internal effects disapper.
>
>
> Returning stuff in a sane way is a real weakness in shells.
>
> pws

Thanks Peter, I sorta suspected it was one of those subshell issues.  I 
must have gotten the invocation wrong cuz I had no luck making the 
variable global.  I ended up sending the output to a bleeding file and 
then rereading that.  There otta be a better way.


>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: unexpected unmodified variable
  2022-10-06 21:58   ` Ray Andrews
@ 2022-10-07  0:36     ` Bart Schaefer
  2022-10-07  1:37       ` Ray Andrews
  0 siblings, 1 reply; 9+ messages in thread
From: Bart Schaefer @ 2022-10-07  0:36 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Thu, Oct 6, 2022 at 2:59 PM Ray Andrews <rayandrews@eastlink.ca> wrote
>
> On 2022-10-06 12:28, Peter Stephenson wrote:
>
> > Returning stuff in a sane way is a real weakness in shells.

Shrug; shells were originally designed to facilitate text processing
by small independent single-purpose applications.  Everything else is
a bolt-on.

> I ended up sending the output to a bleeding file and
> then rereading that.  There otta be a better way.

if you're only dealing with numbers, then the bolted-on math-function
capability can do "real" return values with locally-visible
side-effects.

func2 ()
{
(( count=2 ))  # math op defines return value
echo set by func2: $count
}
func1 ()
{
local count=1
func2
echo got from func2: $count
count=1
var=$(( func2() ))  # note parens
echo seen from func1: $count
echo var is: $var  # now integer not text
}
functions -M func2


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: unexpected unmodified variable
  2022-10-07  0:36     ` Bart Schaefer
@ 2022-10-07  1:37       ` Ray Andrews
  2022-10-07  4:36         ` Bart Schaefer
  0 siblings, 1 reply; 9+ messages in thread
From: Ray Andrews @ 2022-10-07  1:37 UTC (permalink / raw)
  To: zsh-users


On 2022-10-06 17:36, Bart Schaefer wrote:
> Shrug; shells were originally designed to facilitate text processing
> by small independent single-purpose applications.  Everything else is
> a bolt-on.

Yes, the ultimate example of accretion.

Playing with that, it seems the last math operation gets to be the rv 
unless you set a return value, which seems to not go away:

functions -M func2

func2 ()
{
echo func2 here!
count=2
#return 3
}
func1 ()
{
local count=1
var=$(( func2() ))
echo var is: $var, count is $count
}

$  func1
func2 here!
var is: 3, count is 2

... I had : "return 3" active, but commenting it out didn't seem to 
change anything which is puzzling.  Anyway, it seems that 'count' can be 
a normal variable just so long as 'func2' is called mathematically.  
It's not very intuitive but an interesting party trick just the same.   
Or am I missing something as usual?




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: unexpected unmodified variable
  2022-10-07  1:37       ` Ray Andrews
@ 2022-10-07  4:36         ` Bart Schaefer
  2022-10-07 15:28           ` Ray Andrews
  0 siblings, 1 reply; 9+ messages in thread
From: Bart Schaefer @ 2022-10-07  4:36 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Thu, Oct 6, 2022 at 6:37 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> Playing with that, it seems the last math operation gets to be the rv
> unless you set a return value

Yes, that's documented.  Interpreting the argument of "return" counts
as a math operation, so the math value of a "functions -M" function
really is always the last math operation.

> ... I had : "return 3" active, but commenting it out didn't seem to
> change anything which is puzzling.

I think you must have typo'd something somewhere.  Add "functions -t
func2" so you can see a trace of what's executing.

>  Anyway, it seems that 'count' can be
> a normal variable just so long as 'func2' is called mathematically.

That's not exactly the point ... what kind of variable "count" is, in
this case, doesn't matter.  What matters is that $(( func2() )) runs
in the current shell, not in a subshell.

In case it wasn't obvious, $(( func2 )) treats func2 as the name of a
variable, not a function, so it doesn't run func2 at all.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: unexpected unmodified variable
  2022-10-07  4:36         ` Bart Schaefer
@ 2022-10-07 15:28           ` Ray Andrews
  2022-10-07 20:00             ` Bart Schaefer
  0 siblings, 1 reply; 9+ messages in thread
From: Ray Andrews @ 2022-10-07 15:28 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 4418 bytes --]


On 2022-10-06 21:36, Bart Schaefer wrote:
> Yes, that's documented. Interpreting the argument of "return" counts
> as a math operation, so the math value of a "functions -M" function
> really is always the last math operation.

Bart, can you point me to something where I can read up on this 
'functions -M', I was just using it on faith and because things broke 
without it.  I've never used that before and never seemed to miss it.  
In the manual I read:

By default the function is implemented by a shell function of the same 
name; if
shellfn  is specified it gives the name of the corresponding shell func‐ 
tion
while mathfn remains the name used in  arithmetical expressions.   The name
of  the  function in $0 is mathfn (not shellfn as would usually be the 
case),
provided the option FUNCTION_ARGZERO is in  effect.   The positional
parameters  in  the shell function correspond to the arguments of the 
mathe‐
matical function call.  The result of the last arithmetical expression 
eval‐
uated inside the shell function (even if it is a form that normally only 
re‐
turns a status) gives the result of the mathematical function.

... which might just be the most impenetrable bit of computer bafflegab 
I've ever read, I can't get past the first sentence. You have to be 
Peter to understand that.


> I think you must have typo'd something somewhere.  Add "functions -t
> func2" so you can see a trace of what's executing.

No typo, everything is copied and pasted without edit:

The file 'test1':

    #!/usr/bin/zsh

    functions -M func2
    func2 ()
    {
    functions -t func2
    echo func2 here!
    count=2
    #return 3
    }
    func1 ()
    {
    functions -t func2
    local count=1

    var=$(( func2() ))

    # Count = 1, no effect:
    #var=$( func2 )

    echo var is: $var, count is $count
    }


The run:

0 /aWorking/Zsh/Source/Wk 3 $ . test1; func1
+func2:2:>functions -t func2
+func2:3:>echo func2 'here!'
func2 here!
+func2:4:>count=2
var is: 0, count is 2                          <<< With 'return 3' 
commented out.

0 /aWorking/Zsh/Source/Wk 3 $ . test1; func1
+func2:2:>functions -t func2
+func2:3:>echo func2 'here!'
func2 here!
+func2:4:>count=2
+func2:5:>return 3
var is: 3, count is 2                         <<< With 'return 3' active.

0 /aWorking/Zsh/Source/Wk 3 $ . test1; func1
+func2:2:>functions -t func2
+func2:3:>echo func2 'here!'
func2 here!
+func2:4:>count=2
var is: 3, count is 2                        <<< With 'return 3' 
commented out again.

> this case, doesn't matter.  What matters is that $(( func2() )) runs
> in the current shell, not in a subshell.

Right, I understand that.  So long as there's math involved, there's no 
subshell.

BTW, if I modify func2:

func2 ()
{
functions -t func2
echo func2 here!
#integer count=2
#return 3
}

... the same pattern results:

'# integer count=2':  and count is unchanged in func1, var = 0.

'integer count=2':  and count is unchanged in func1 but var = 2. I force 
it to be a math op.  The 'integer count' seems to be a new variable so 
the original is unchanged, that's clear.

'# integer count=2':  and var is '2'.  func2 retains the previous return 
value even thou the active line is commented out (again). Unless I'm 
making some kind of mistake, it seems buggy to me, the rv of func2 is 
floating unchanged somewhere.  When I explicitly change it, it changes, 
but then the new value floats there too. I've done it a dozen times, I 
don't think I'm wrong.  I have to start a new shell to erase that rv.  
Or is this some bizarre local issue here?

Tho I do wonder why '$(( ))' is 'local' and '$( )' spawns a subshell, 
dunno, maybe there's a good reason for that but one might wish for some 
method of asking '$( )' to run 'local' too, so that my original issue 
wouldn't come up.  I appreciate that this kind of thing is so deep in 
the way the shell runs that it might be next to impossible even if 
anyone but me was interested in it. Still: "setopt NO_SUBSHELL" might be 
very useful.




>
> In case it wasn't obvious, $(( func2 )) treats func2 as the name of a
> variable, not a function, so it doesn't run func2 at all.

Yes, that's clear.  '$(( func2() ))' is a math operation -- grab the 
return value, which is whatever the last math operation was. '$(( func2 
))' is ... basically nothing.


>

[-- Attachment #2: Type: text/html, Size: 6702 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: unexpected unmodified variable
  2022-10-07 15:28           ` Ray Andrews
@ 2022-10-07 20:00             ` Bart Schaefer
  2022-10-07 21:59               ` Ray Andrews
  0 siblings, 1 reply; 9+ messages in thread
From: Bart Schaefer @ 2022-10-07 20:00 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Fri, Oct 7, 2022 at 8:28 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> By default the function is implemented by a shell function of the same name; if
> shellfn  is specified it gives the name of the corresponding shell function
> while mathfn remains the name used in  arithmetical  expressions.

As with widgets, you can have a math function named X that's
implemented by a shell function named Y.  The default is that if the
shell function is Y, then the math function is also Y.

> The name
> of  the  function in $0 is mathfn (not shellfn as would usually be the case),
> provided the option FUNCTION_ARGZERO is in  effect.

This is just explaining how $0 works in case you're trying to have a
function that references itself by name.

> The  positional
> parameters  in  the shell function correspond to the arguments of the mathe‐
> matical function call.

If you write $(( func2(a,b,c) )) then inside func2, $1 == a, $2 == b, $3 == c

"Positional parameters" always means $1, $2, etc., that's not
math-function-specific, it's just shell terminology.

> The result of the last arithmetical expression eval‐
> uated inside the shell function (even if it is a form that normally only re‐
> turns a status) gives the result of the mathematical function.

The parenthetical refers to the fact that some math operations are
true/false, e.g. (( x > 12)) "is a form that only returns a status".
Omitting that, the rest of the sentence should be clear.

> ... which might just be the most impenetrable bit of computer bafflegab I've ever read, I can't get past the first sentence.

Seriously?  This is all using phrases that refer to concepts appearing
elsewhere throughout the zsh manual.

> You have to be Peter to understand that.

Well, he did write it.

> No typo, everything is copied and pasted without edit:

Oh.  Given the way you wrote func2, if you remove the return statement
there are NO math expressions in func2 at all, so $(( func2() )) is
[except for side-effects] a no-op, and the assignment in var=$((
func2() )) is just skipped, leaving the previous value of $var
unchanged.  If you turn the count=2 assignment into a math expression,
either by your "integer count=2" test or by using (( count=2 )), then
$(( func2() )) returns the value from that.

It is a bit weird that var=$((...)) does nothing at all in that
circumstance, I would have expected it either to assign empty string
to $var or to have a nonzero $? as a result.  Unanticipated edge case,
possible bug.

> Tho I do wonder why '$(( ))' is 'local' and '$( )' spawns a subshell

$(...) spawns a subshell because stdin/stdout text is passed from one
process to another using pipes, and if a process has a pipe to itself
it can deadlock trying to read something it hasn't written yet (or
write something there isn't room for because not enough has been read
yet).

$((...)) looks that way by analogy to ((...)), not by analogy to $(...).

> one might wish for some method of asking '$( )' to run 'local' too

"Local" text substitution is what ordinary $param references are for
... $(...) specifically means to use processes and pipes.  That said,
a still-missing feature in zsh is the ability to tie a function to a
variable so that referencing the variable as $foo invokes the function
that's tied to it, to produce the effect you're asking for.  Ksh has a
syntax for that.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: unexpected unmodified variable
  2022-10-07 20:00             ` Bart Schaefer
@ 2022-10-07 21:59               ` Ray Andrews
  0 siblings, 0 replies; 9+ messages in thread
From: Ray Andrews @ 2022-10-07 21:59 UTC (permalink / raw)
  To: zsh-users


On 2022-10-07 13:00, Bart Schaefer wrote:
> ... which might just be the most impenetrable bit of computer 
> bafflegab I've ever read, I can't get past the first sentence.
> Seriously?  This is all using phrases that refer to concepts appearing
> elsewhere throughout the zsh manual.
True ... which makes the manual hard to understand.  It's a language 
unto itself.   What would be helpful is some sort of introduction to 
zsh-speak.  Mind, I expect all the shells have about the same jargon.  
But believe me, when you don't know the lingo it's impenetrable.
>
> Oh.  Given the way you wrote func2, if you remove the return statement
> there are NO math expressions in func2 at all, so $(( func2() )) is
> [except for side-effects] a no-op, and the assignment in var=$((
> func2() )) is just skipped, leaving the previous value of $var
> unchanged.

Ah! ... yes, why would it change? nothing has touched it.  I was 
expecting func2 to somehow cough up a null value setting 'var=0' but 
it's not illogical that it coughs up ... nothing ... therefore there is 
no assignment and 'var' does not change.  I get it.


> "Local" text substitution is what ordinary $param references are for
> ... $(...) specifically means to use processes and pipes.  That said,
> a still-missing feature in zsh is the ability to tie a function to a
> variable so that referencing the variable as $foo invokes the function
> that's tied to it, to produce the effect you're asking for.  Ksh has a
> syntax for that.
>
Well you'd know.  Anyway as usual the functionality I was looking for is 
there even if it didn't look like I expected.  By now I should have a 
permanent understanding of this stuff not keep relapsing.




^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-10-07 21:59 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-06 19:07 unexpected unmodified variable Ray Andrews
2022-10-06 19:28 ` Peter Stephenson
2022-10-06 21:58   ` Ray Andrews
2022-10-07  0:36     ` Bart Schaefer
2022-10-07  1:37       ` Ray Andrews
2022-10-07  4:36         ` Bart Schaefer
2022-10-07 15:28           ` Ray Andrews
2022-10-07 20:00             ` Bart Schaefer
2022-10-07 21:59               ` Ray Andrews

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).