zsh-users
 help / color / mirror / code / Atom feed
* for loop 'bad math expression'
@ 2024-01-30  3:39 Ray Andrews
  2024-01-30  3:46 ` Ray Andrews
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2024-01-30  3:39 UTC (permalink / raw)
  To: Zsh Users

Been reviewing and deleting old email backups but saving some:


for bb in *.eml~save*; do    # Error msg. points to this line.

     thunderbird -file $bb

     echo "\nFile: $bb: Press 's' to save, 'd' to delete or '^C' to quit."
     read -sk1 key

     case $key in
         d ) rm -v $bb ;;
         s ) mv -v $bb save-$bb ;;    # Rename so not viewed again.
         * ) errormsg "skipping file ..." ;;
     esac
done

... it's been working fine, done thousands.  But just now it threw me an 
error:

     global:20: bad math expression: operator expected at `CDF8.eml'

.... there's no such file.  They all have eight characters then '.eml':

    607 [2013-01-16--18:57] 48EE0E21.eml*
     694 [2013-01-16--18:57] 48ECE166.eml*
   10115 [2013-01-16--18:57] 48E4BB08.eml*

... like that.  And if saved:

    2842 [2013-01-16--18:57] save-48137E34.eml*
    3135 [2013-01-16--18:57] save-4812320B.eml*
    2278 [2013-01-16--18:57] save-48122AEC.eml*

Does anyone have the slightest clue what's going on here?




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

* Re: for loop 'bad math expression'
  2024-01-30  3:39 for loop 'bad math expression' Ray Andrews
@ 2024-01-30  3:46 ` Ray Andrews
  2024-01-30  4:04   ` Bart Schaefer
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2024-01-30  3:46 UTC (permalink / raw)
  To: zsh-users


On 2024-01-29 19:39, Ray Andrews wrote:
>
>
> Does anyone have the slightest clue what's going on here?
>
>
BTW here's a hint: with 'set -x' I see this:

+global:20:for for>bb=48E3CDF8.eml
global:20: bad math expression: operator expected at `CDF8.eml'

... so somehow it's taking that filename and cutting it down and turning 
it into a math expression.  The file exists and is perfectly normal,



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

* Re: for loop 'bad math expression'
  2024-01-30  3:46 ` Ray Andrews
@ 2024-01-30  4:04   ` Bart Schaefer
  2024-01-30  4:06     ` Bart Schaefer
  0 siblings, 1 reply; 25+ messages in thread
From: Bart Schaefer @ 2024-01-30  4:04 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Mon, Jan 29, 2024 at 7:47 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> +global:20:for for>bb=48E3CDF8.eml
> global:20: bad math expression: operator expected at `CDF8.eml'

% x=48E3CDF8
% echo $x
48E3CDF8
% integer x
zsh: bad math expression: operator expected at `CDF8'

So, something has declared "bb" to be an integer.


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

* Re: for loop 'bad math expression'
  2024-01-30  4:04   ` Bart Schaefer
@ 2024-01-30  4:06     ` Bart Schaefer
  2024-01-30  4:17       ` Ray Andrews
  0 siblings, 1 reply; 25+ messages in thread
From: Bart Schaefer @ 2024-01-30  4:06 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Mon, Jan 29, 2024 at 8:04 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> So, something has declared "bb" to be an integer.

Or a float, or some other numeric type, they all produce that error.


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

* Re: for loop 'bad math expression'
  2024-01-30  4:06     ` Bart Schaefer
@ 2024-01-30  4:17       ` Ray Andrews
  2024-01-30 13:44         ` Ray Andrews
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2024-01-30  4:17 UTC (permalink / raw)
  To: zsh-users


On 2024-01-29 20:06, Bart Schaefer wrote:
> On Mon, Jan 29, 2024 at 8:04 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>> So, something has declared "bb" to be an integer.
> Or a float, or some other numeric type, they all produce that error.

Right you are.  Yeah, some careless use of the variable, I didn't bother 
to declare it local so it's some stray coming from somewhere else.  I 
hate that.  Orphaned variables hanging around waiting to get into 
trouble.  I'll track down the leak.  Thank you Sensei.




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

* Re: for loop 'bad math expression'
  2024-01-30  4:17       ` Ray Andrews
@ 2024-01-30 13:44         ` Ray Andrews
  2024-01-30 14:30           ` Lawrence Velázquez
  2024-02-03 23:52           ` Bart Schaefer
  0 siblings, 2 replies; 25+ messages in thread
From: Ray Andrews @ 2024-01-30 13:44 UTC (permalink / raw)
  To: zsh-users


On 2024-01-29 20:17, Ray Andrews wrote:
>
> On 2024-01-29 20:06, Bart Schaefer wrote:
>> On Mon, Jan 29, 2024 at 8:04 PM Bart Schaefer 
>> <schaefer@brasslantern.com> wrote:
>>> So, something has declared "bb" to be an integer.
>> Or a float, or some other numeric type, they all produce that error.
>
> Right you are.  Yeah, some careless use of the variable, I didn't 
> bother to declare it local so it's some stray coming from somewhere 
> else.  I hate that.  Orphaned variables hanging around waiting to get 
> into trouble.  I'll track down the leak.  Thank you Sensei.

BTW Bart, just a post mortem on that: I know there are situations where 
a plain vanilla scalar is promoted to integer when the situation 
requires it.  In the above, I wonder about an automatic demotion.  The 
situation plainly had nothing to do with arithmetic OTOH perhaps there 
could be situations where a for loop like that one really would be doing 
arithmetic there in which case type assumptions would be unwise.  OTOOH 
perhaps automatic 'non demotion' would be possible -- zsh might have 
robust defenses against making a mistake.  Dunno, but as dangerous as 
'obvious' can be, it seems to me that a glob expansion of a bunch of 
filenames is obviously nothing to do with arithmetic.

3 /aWorking/Zsh/Source/Wk 0 % var=abc; var=$(( 1+1 )); echo $var
2

for bb in *.eml~save*; do

... just as var can be automatically turned into an integer so to 
perhaps bb could be clearly understood to be scalar in that situation.  
Again, unless I really might have intended something mathematical there 
which is hard to imagine.






>
>
>


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

* Re: for loop 'bad math expression'
  2024-01-30 13:44         ` Ray Andrews
@ 2024-01-30 14:30           ` Lawrence Velázquez
  2024-02-03 23:52           ` Bart Schaefer
  1 sibling, 0 replies; 25+ messages in thread
From: Lawrence Velázquez @ 2024-01-30 14:30 UTC (permalink / raw)
  To: zsh-users

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

> On Jan 30, 2024, at 8:50 AM, Ray Andrews <rayandrews@eastlink.ca> wrote:
> 
> BTW Bart, just a post mortem on that: I know there are situations where a plain vanilla scalar is promoted to integer when the situation requires it.

In what situations is the integer attribute automatically given to an existing variable that did not previously have it?

> In the above, I wonder about an automatic demotion.  The situation plainly had nothing to do with arithmetic

Under no circumstances should zsh take it upon itself to automatically remove the integer attribute. If you don’t want it to enforce the integer constraint, don’t assign the attribute. Nothing requires you to use it.

> OTOOH perhaps automatic 'non demotion' would be possible -- zsh might have robust defenses against making a mistake.

This is wishful thinking.

-- 
vq
Sent from my iPhone

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

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

* Re: for loop 'bad math expression'
  2024-01-30 13:44         ` Ray Andrews
  2024-01-30 14:30           ` Lawrence Velázquez
@ 2024-02-03 23:52           ` Bart Schaefer
  2024-02-04  1:14             ` Ray Andrews
  1 sibling, 1 reply; 25+ messages in thread
From: Bart Schaefer @ 2024-02-03 23:52 UTC (permalink / raw)
  To: zsh-users

On Tue, Jan 30, 2024 at 5:44 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> BTW Bart, just a post mortem on that: I know there are situations where
> a plain vanilla scalar is promoted to integer

As Lawrence also suggested, I don't believe that happens.  If a
parameter is created inside a math expression it will be assigned an
appropriate numeric type, but the type of an existing scalar is not
changed.

Note "created" here includes the case where the parameter was declared
but later unset and then assigned again in math context.

Parameters may also be converted to and from arrays by assignment, and
that includes converting from an array to a numeric type when assigned
in math context.  Maybe that's what you're thinking of.

> I wonder about an automatic demotion.  The
> situation plainly had nothing to do with arithmetic

Context-awareness doesn't extend that far.  Globbing is already done
and gone by the time "for" assigns its loop variable, nothing tells
"for" where the loop values came from, and shell words on a command
line carry no type information.

> perhaps automatic 'non demotion' would be possible -- zsh might have
> robust defenses against making a mistake.

You might try setopt warn_create_global to detect cases of names "leaking".


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

* Re: for loop 'bad math expression'
  2024-02-03 23:52           ` Bart Schaefer
@ 2024-02-04  1:14             ` Ray Andrews
  2024-02-04  2:05               ` Lawrence Velázquez
  2024-02-04 14:43               ` Mark J. Reed
  0 siblings, 2 replies; 25+ messages in thread
From: Ray Andrews @ 2024-02-04  1:14 UTC (permalink / raw)
  To: zsh-users

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


On 2024-02-03 15:52, Bart Schaefer wrote:
> As Lawrence also suggested, I don't believe that happens.  If a
> parameter is created inside a math expression it will be assigned an
> appropriate numeric type, but the type of an existing scalar is not
> changed.

0 /usr/share/info 0 % var=abc; let var+=2; echo $var

2

... it looks like the shell is simply throwing away 'abc' and starting 
afresh with an integer and then incrementing it. And in the manual:

Note that assignment may implicitly change the attributes of a 
parameter. For example, assigning a number to a variable in arithmetic 
evaluation may change its type to integer or float, and with GLOB_ASSIGN 
assigning a pattern to a variable may change its type to an array.

> Context-awareness doesn't extend that far.  Globbing is already done
> and gone by the time "for" assigns its loop variable, nothing tells
> "for" where the loop values came from, and shell words on a command
> line carry no type information.

Sure.  I'm hardly surprised it wouldn't be practical, it was the most 
speculative sort of question.  And there really is no foul since my 
variable shouldn't have been an integer.  Actually, philosophically I'm 
opposed to most hand-holding anyway.  With experience I'd probably 
instantly detect what was going on there. But when you first bump into 
it, it seems inexplicable.

>
> You might try setopt warn_create_global to detect cases of names "leaking".
>
Never played with that.  Sounds useful.  As always my 'C-brain' tells me 
that indiscipline with variables is intolerable.



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

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

* Re: for loop 'bad math expression'
  2024-02-04  1:14             ` Ray Andrews
@ 2024-02-04  2:05               ` Lawrence Velázquez
  2024-02-04  4:20                 ` Bart Schaefer
  2024-02-04 15:51                 ` Ray Andrews
  2024-02-04 14:43               ` Mark J. Reed
  1 sibling, 2 replies; 25+ messages in thread
From: Lawrence Velázquez @ 2024-02-04  2:05 UTC (permalink / raw)
  To: zsh-users

On Sat, Feb 3, 2024, at 8:14 PM, Ray Andrews wrote:
> On 2024-02-03 15:52, Bart Schaefer wrote:
>> As Lawrence also suggested, I don't believe that happens.  If a
>> parameter is created inside a math expression it will be assigned an
>> appropriate numeric type, but the type of an existing scalar is not
>> changed. 
> 0 /usr/share/info 0 % var=abc; let var+=2; echo $var
>
> 2
> ... it looks like the shell is simply throwing away 'abc' and starting 
> afresh with an integer and then incrementing it.

No, that's not what happens.  Within arithmetic expressions, the
contents of variables undergo recursive arithmetic evaluation, so
the value of "var", "abc", is interpreted as another variable name,
which is itself evaluated.  Since there is no "abc" variable, its
arithmetic value is taken to be zero, so the result is 0 + 2 = 2.
(The result would be the same if "abc" were set to an empty value.)

A less trivial example should make this clearer:

	% var=abc

	% unset abc
	% print -- $((var))
	0

	% abc=1
	% print -- $((var))
	1

	% abc=1+1
	% typeset -p abc
	typeset abc=1+1
	% print -- $((var))
	2

	% abc='1.0 * PPID / SECONDS - RANDOM'
	% typeset -p abc
	typeset abc='1.0 * PPID / SECONDS - RANDOM'
	% print -- $((var))
	-10080.313725490196

-- 
vq


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

* Re: for loop 'bad math expression'
  2024-02-04  2:05               ` Lawrence Velázquez
@ 2024-02-04  4:20                 ` Bart Schaefer
  2024-02-04 16:08                   ` Ray Andrews
  2024-02-04 15:51                 ` Ray Andrews
  1 sibling, 1 reply; 25+ messages in thread
From: Bart Schaefer @ 2024-02-04  4:20 UTC (permalink / raw)
  To: zsh-users

On Sat, Feb 3, 2024 at 6:06 PM Lawrence Velázquez <larryv@zsh.org> wrote:
>
> On Sat, Feb 3, 2024, at 8:14 PM, Ray Andrews wrote:
> > 0 /usr/share/info 0 % var=abc; let var+=2; echo $var
> >
> > 2
> > ... it looks like the shell is simply throwing away 'abc' and starting
> > afresh with an integer and then incrementing it.
>
> No, that's not what happens.  Within arithmetic expressions, the
> contents of variables undergo recursive arithmetic evaluation

This has been a very thorough description of the arithmetic process in
zsh, but I think misses one important detail:

% var=abc
% typeset -p var
typeset var=abc
% let var+=2
%  typeset -p var
typeset var=2

Note that var has NOT acquired the "-i" (integer) attribute, despite
having been assigned a number value.


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

* Re: for loop 'bad math expression'
  2024-02-04  1:14             ` Ray Andrews
  2024-02-04  2:05               ` Lawrence Velázquez
@ 2024-02-04 14:43               ` Mark J. Reed
  2024-02-04 16:37                 ` Ray Andrews
  1 sibling, 1 reply; 25+ messages in thread
From: Mark J. Reed @ 2024-02-04 14:43 UTC (permalink / raw)
  To: zsh-users

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

On Sat, Feb 3, 2024 at 8:14 PM Ray Andrews <rayandrews@eastlink.ca> wrote:

> 0 /usr/share/info 0 % var=abc; let var+=2; echo $var
> 2
>
> ... it looks like the shell is simply throwing away 'abc' and starting
> afresh with an integer and then incrementing it.
>

That's not qutie what's happening. Arithmetic expressions interpret *all*
variables as numbers, whether the variables are *declared* as integers or
not. If a variable's value doesn't look like a number, it is interpreted as
the *name *of another variable, which is then looked up recursively. If it
gets to a variable that doesn't exist, the value is taken as 0.

So, when you do any sort of assignment inside a *let* or *((*...*))* or
array subscript or any other arithmetic context, the variable being
assigned will *always* come out of it with a numeric value. But unless
you've done a *declare -i *or *typeset -i*, it will not be stored as an
integer; it will be converted back to a string that just happens to be all
digits. What's the difference? Well, let's continue your example:

*zsh%* var=abc; let var+=2; echo $var
*2*
*zsh%* var+=2; echo $var # note: no let
*22*


As you can see, outside of *let*, using *+=* *appended* to the variable
instead of doing arithmetic. Because it's still a string.

If you were to go in and declare it as an integer, then *+= *would have its
arithmetic meaning even outside of explicit arithmetic context:

*zsh% *typeset -i var

*zsh% *var+=2; echo $var
*24*


But that's only because of the *typeset*. It doesn't happen automatically.

-- 
Mark J. Reed <markjreed@gmail.com>

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

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

* Re: for loop 'bad math expression'
  2024-02-04  2:05               ` Lawrence Velázquez
  2024-02-04  4:20                 ` Bart Schaefer
@ 2024-02-04 15:51                 ` Ray Andrews
  2024-02-04 20:48                   ` Lawrence Velázquez
  1 sibling, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2024-02-04 15:51 UTC (permalink / raw)
  To: zsh-users

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



On 2024-02-03 18:05, Lawrence Velázquez wrote:
> 	% var=abc
>
> 	% unset abc
> 	% print -- $((var))
> 	0
>
> 	% abc=1
> 	% print -- $((var))
> 	1
>
> 	% abc=1+1
> 	% typeset -p abc
> 	typeset abc=1+1
> 	% print -- $((var))
> 	2
>
> 	% abc='1.0 * PPID / SECONDS - RANDOM'
> 	% typeset -p abc
> 	typeset abc='1.0 * PPID / SECONDS - RANDOM'
> 	% print -- $((var))
> 	-10080.313725490196
>

That astonishes me.  I've never heard of any such thing.  Nobody tells 
you these things.

% var=abc; print -- $var
abc

% abc=1; print -- $((var))
1

# abc was a string, now it's the name of an integer:
% let abc+=3; print -- $((var))
3

# var still wants to be scalar:
% var+=3; print -- $var
abc3

# So once var has been touched directly the link to abc is broken:
% abc+=2; print -- $((var))
0

% abc=2; print -- $((var))
0

... I suppose there's a good reason for it, but that leaves me dumbfounded.

% Sonnet_1='From_fairest_flowers_we_desire_increase'; print -- $Sonnet_1
From_fairest_flowers_we_desire_increase

% From_fairest_flowers_we_desire_increase=1

% print -- $((Sonnet_1))
1

... ok ...

Anyway, the lesson is just not to assign a glob expansion to an 
integer.  Never, ever.  Sorry for the trouble gentlemen.







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

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

* Re: for loop 'bad math expression'
  2024-02-04  4:20                 ` Bart Schaefer
@ 2024-02-04 16:08                   ` Ray Andrews
  2024-02-04 20:56                     ` Lawrence Velázquez
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2024-02-04 16:08 UTC (permalink / raw)
  To: zsh-users

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



On 2024-02-03 20:20, Bart Schaefer wrote:
> Note that var has NOT acquired the "-i" (integer) attribute, despite
> having been assigned a number value.
I noticed that myself.  I expect that all this goes back to ancient 
history -- arithmetic would have been an add-on at some point and 
integers were never robustly typed, just scalars subject to special 
processing, so  ' $(( )) ' says: "treat me mathematically, even tho I'm 
otherwise just a scalar".  But in my previous post it would seem that 
'abc' IS an integer because it increments like one, but even then 
typeset -p shows it as scalar. It starts as a string assigned to 'var' 
but it would seem it gets 'promoted' to an integer variable.

>

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

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

* Re: for loop 'bad math expression'
  2024-02-04 14:43               ` Mark J. Reed
@ 2024-02-04 16:37                 ` Ray Andrews
  2024-02-04 21:09                   ` Lawrence Velázquez
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2024-02-04 16:37 UTC (permalink / raw)
  To: zsh-users

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



On 2024-02-04 06:43, Mark J. Reed wrote:
>
> That's not qutie what's happening. Arithmetic expressions interpret 
> /all/ variables as numbers, whether the variables are /declared/ as 
> integers or not. If a variable's value doesn't look like a number, it 
> is interpreted as the /name /of another variable, which is then looked 
> up recursively. If it gets to a variable that doesn't exist, the value 
> is taken as 0.
I get that.  $(( abc ..... )) ... abc isn't a number therefore it's the 
name of a variable.  However I did:

% var=abc
... outside any (()) and the conversion happened 'retroactively' so to 
speak.

% var=path; print -- $var
path
... 'path' is just a string, there's no implicit conversion to a 
variable.  Ergo:

%var=abc
... seems to me the same.  Later on abc becomes an integer name, and the 
string is lost
>
> ... it will be converted back to a string that just happens to be all 
> digits. What's the difference? Well, let's continue your example:
>
>     *zsh%* var=abc; let var+=2; echo $var
>     *2*
>     *zsh%* var+=2; echo $var # note: no let
>     *22*
>
Right, I get that too.  A string of digits is still a string.

Anyway it goes back to my original speculation/question that implicit 
promotions/conversions do happen thus a 'demotion' -- in the case of 
that glob expansion -- is something that might at least be contemplated 
even if in fact the idea is unsound.  As for me I think that taking a 
string and then using it as the name of an integer is a bit strange, but 
it is what it is and I won't crash into that problem again.

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

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

* Re: for loop 'bad math expression'
  2024-02-04 15:51                 ` Ray Andrews
@ 2024-02-04 20:48                   ` Lawrence Velázquez
  2024-02-04 21:09                     ` Bart Schaefer
  2024-02-05  2:10                     ` Bart Schaefer
  0 siblings, 2 replies; 25+ messages in thread
From: Lawrence Velázquez @ 2024-02-04 20:48 UTC (permalink / raw)
  To: zsh-users

On Sun, Feb 4, 2024, at 10:51 AM, Ray Andrews wrote:
> That astonishes me.  I've never heard of any such thing.  Nobody
> tells you these things.

I'm not sure if the zsh manual spells this behavior out explicitly,
but bash and ksh share it.


> # abc was a string, now it's the name of an integer:

These are not mutually exclusive.  The value of var remains "abc"
and does not change at any point.  The important thing is that it
is *interpreted* a certain way *in arithmetic contexts*.


> % let abc+=3; print -- $((var))
> 3

This result does not correlate with the commands you've actually
shown here.

	% var=abc
	% abc=1
	% let abc+=3
	% print -- $((var))
	4


> # var still wants to be scalar:
> % var+=3; print -- $var 
> abc3

It doesn't "want" to be scalar, it IS scalar.  But that's irrelevant.
What's relevant is that it does not have the integer attribute, so
"var+=3" performs string concatenation and not arithmetic incrementing.
You'd see the same thing with "abc", even though it looks like a
number.

	% abc=1
	% abc+=3
	% typeset -p abc
	typeset abc=13

(I don't know why all of a sudden you've switched from using "let"
to not using it.)


> # So once var has been touched directly the link to abc is broken:
> % abc+=2; print -- $((var))
> 0
>
> % abc=2; print -- $((var))
> 0

It's not about "touching", and there is no "link".  You CHANGED its
value to "abc3", and there is no such variable, so its arithmetic
value is recursively taken to be zero.


> ... I suppose there's a good reason for it, but that leaves me dumbfounded.

If you were given these algebraic equations and asked what the value
of "c" is, presumably you'd say "one" and not "the letter 'b'".

	a = 1
	b = a
	c = b

Same thing in shell arithmetic.

	% a=1
	% b=a
	% c=b
	% print -- $((c))
	1


> % Sonnet_1='From_fairest_flowers_we_desire_increase'; print -- $Sonnet_1
> From_fairest_flowers_we_desire_increase

There is no arithmetic context here, so you just get the raw value.


> % From_fairest_flowers_we_desire_increase=1        
>
> % print -- $((Sonnet_1))
> 1
>
> ... ok ...

There *is* an arithmetic context here, so it's interpreted as an
arithmetic expression.  What is confusing about this?  You're
intentionally using unwieldy names, but the principle is the same
as if you'd just used "a" and "b".


> Anyway, the lesson is just not to assign a glob expansion to an
> integer.

The real lesson might be that you should avoid the integer attribute
until you understand shell arithmetic better.


-- 
vq


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

* Re: for loop 'bad math expression'
  2024-02-04 16:08                   ` Ray Andrews
@ 2024-02-04 20:56                     ` Lawrence Velázquez
  0 siblings, 0 replies; 25+ messages in thread
From: Lawrence Velázquez @ 2024-02-04 20:56 UTC (permalink / raw)
  To: zsh-users

On Sun, Feb 4, 2024, at 11:08 AM, Ray Andrews wrote:
> But in my previous post it would seem that 'abc' IS an integer because it increments like one, but even then typeset -p shows it as scalar.

No.  It "increments like one" because you ran "abc=1; let abc+=3",
and the arguments to "let" are interpreted as arithmetic expressions.
If you'd run "abc=1; abc+=3" you would have gotten string concatenation.

> It starts as a string assigned to 'var' but it would seem it gets 'promoted' to an integer variable.

What?  When you ran "abc=1" *you* created that variable.  And it's
not "an integer variable"; it doesn't have the integer attribute.

-- 
vq


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

* Re: for loop 'bad math expression'
  2024-02-04 20:48                   ` Lawrence Velázquez
@ 2024-02-04 21:09                     ` Bart Schaefer
  2024-02-04 21:23                       ` Bart Schaefer
  2024-02-05  2:10                     ` Bart Schaefer
  1 sibling, 1 reply; 25+ messages in thread
From: Bart Schaefer @ 2024-02-04 21:09 UTC (permalink / raw)
  To: zsh-users

On Sun, Feb 4, 2024 at 12:49 PM Lawrence Velázquez <larryv@zsh.org> wrote:
>
> (I don't know why all of a sudden you've switched from using "let"
> to not using it.)

I believe he's expecting assignments to work the same way on "numbers"
whether or not they are declared as integers.  This goes back to
expecting arithmetic to promote strings to integers.

For the rest of the audience ...

Using
  % let var=value
always applies math context, just as ((...)) and  $((...)) and $[...] do.

Bare assignments
  % var=value
apply math context only when "var" already has a numeric type.
Otherwise, the more usual case, it's string assignment (ignoring
arrays here).

Using typeset, declare, or local applies math context when an integer
option (-i, -F, etc.) is provided OR when var already has a numeric
type.

> > ... I suppose there's a good reason for it, but that leaves me dumbfounded.

Historically, I expect this results from lack in the base "sh" of
user-defined math functions.  That is, you can write

  func="a+b*c"
  let a=2 b=3 c=5
  print $((func))

to get 17.


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

* Re: for loop 'bad math expression'
  2024-02-04 16:37                 ` Ray Andrews
@ 2024-02-04 21:09                   ` Lawrence Velázquez
  0 siblings, 0 replies; 25+ messages in thread
From: Lawrence Velázquez @ 2024-02-04 21:09 UTC (permalink / raw)
  To: zsh-users

On Sun, Feb 4, 2024, at 11:37 AM, Ray Andrews wrote:
> I get that.  $(( abc ..... )) ... abc isn't a number therefore it's the 
> name of a variable.  However I did:
>
> % var=abc
> ... outside any (()) and the conversion happened 'retroactively' so to speak. 
>
> % var=path; print -- $var
> path
> ... 'path' is just a string, there's no implicit conversion to a 
> variable.

Of course there isn't, because there is no arithmetic context there.
If you'd run

	print -- $((var))

then "path" would have been referenced recursively.  (And you almost
certainly would have seen an error because the contents of "path"
are unlikely to form a valid arithmetic expression.)


> Ergo:
>
> %var=abc 
> ... seems to me the same.  Later on abc becomes an integer name, and 
> the string is lost

The string is never lost.  Inspect the raw value of "var"; it does
not change from "abc" unless you change it yourself.


> Anyway it goes back to my original speculation/question that implicit 
> promotions/conversions do happen

You still haven't demonstrated any situations where this occurs.
All your examples have been broken, and your conjectures confused.


-- 
vq


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

* Re: for loop 'bad math expression'
  2024-02-04 21:09                     ` Bart Schaefer
@ 2024-02-04 21:23                       ` Bart Schaefer
  0 siblings, 0 replies; 25+ messages in thread
From: Bart Schaefer @ 2024-02-04 21:23 UTC (permalink / raw)
  To: zsh-users

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

On Sun, Feb 4, 2024 at 1:09 PM Bart Schaefer <schaefer@brasslantern.com>
wrote:

>
> Historically, I expect this results from lack in the base "sh" of
> user-defined math functions.
>

Also perhaps to replicate the behavior of /bin/expr, though that's iffy-er.

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

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

* Re: for loop 'bad math expression'
  2024-02-04 20:48                   ` Lawrence Velázquez
  2024-02-04 21:09                     ` Bart Schaefer
@ 2024-02-05  2:10                     ` Bart Schaefer
  2024-02-05  2:43                       ` Mikael Magnusson
  2024-02-05 15:21                       ` Ray Andrews
  1 sibling, 2 replies; 25+ messages in thread
From: Bart Schaefer @ 2024-02-05  2:10 UTC (permalink / raw)
  To: zsh-users

On Sun, Feb 4, 2024 at 12:49 PM Lawrence Velázquez <larryv@zsh.org> wrote:
>
> I'm not sure if the zsh manual spells this behavior out explicitly,
> but bash and ksh share it.

"Arithmetic Evaluation" says (pretty far down after the discussion of
operators):
===
Named parameters and subscripted arrays can be referenced by name within
an arithmetic expression without using the parameter expansion syntax.
For example,
     ((val2 = val1 * 2))
assigns twice the value of $val1 to the parameter named val2.

=(and later)=

Scalar variables can hold integer or floating point values at different
times; there is no memory of the numeric type in this case.

If a variable is first assigned in a numeric context without previously
being declared, it will be implicitly typed as integer or float and
retain that type either until the type is explicitly changed or until
the end of the scope.  This can have unforeseen consequences.
===

It doesn't explicitly say how "the value of $val1" is determined, but
if it were expanded with $val1 you'd get the whole text string which
would then be interpreted as arithmetic, so expanding without the $
works the same.


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

* Re: for loop 'bad math expression'
  2024-02-05  2:10                     ` Bart Schaefer
@ 2024-02-05  2:43                       ` Mikael Magnusson
  2024-02-05  2:50                         ` Bart Schaefer
  2024-02-05 15:21                       ` Ray Andrews
  1 sibling, 1 reply; 25+ messages in thread
From: Mikael Magnusson @ 2024-02-05  2:43 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-users

On 2/5/24, Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Sun, Feb 4, 2024 at 12:49 PM Lawrence Velázquez <larryv@zsh.org> wrote:
>>
>> I'm not sure if the zsh manual spells this behavior out explicitly,
>> but bash and ksh share it.
>
> "Arithmetic Evaluation" says (pretty far down after the discussion of
> operators):
> ===
> Named parameters and subscripted arrays can be referenced by name within
> an arithmetic expression without using the parameter expansion syntax.
> For example,
>      ((val2 = val1 * 2))
> assigns twice the value of $val1 to the parameter named val2.
>
> =(and later)=
>
> Scalar variables can hold integer or floating point values at different
> times; there is no memory of the numeric type in this case.
>
> If a variable is first assigned in a numeric context without previously
> being declared, it will be implicitly typed as integer or float and
> retain that type either until the type is explicitly changed or until
> the end of the scope.  This can have unforeseen consequences.
> ===
>
> It doesn't explicitly say how "the value of $val1" is determined, but
> if it were expanded with $val1 you'd get the whole text string which
> would then be interpreted as arithmetic, so expanding without the $
> works the same.

This last bit is not 100% true, a parameter will combine into its
context with $ but not without:
% a=3+2
% echo $(( 5 / a )) # 5/5
1
% echo $(( 5 / $a )) # 5/3 + 2
3

I think effectively you can think of foo as ($foo), at least in all
cases I can think of to try.

-- 
Mikael Magnusson


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

* Re: for loop 'bad math expression'
  2024-02-05  2:43                       ` Mikael Magnusson
@ 2024-02-05  2:50                         ` Bart Schaefer
  0 siblings, 0 replies; 25+ messages in thread
From: Bart Schaefer @ 2024-02-05  2:50 UTC (permalink / raw)
  To: zsh-users

On Sun, Feb 4, 2024 at 6:43 PM Mikael Magnusson <mikachu@gmail.com> wrote:
>
> I think effectively you can think of foo as ($foo), at least in all
> cases I can think of to try.

Excellent point.


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

* Re: for loop 'bad math expression'
  2024-02-05  2:10                     ` Bart Schaefer
  2024-02-05  2:43                       ` Mikael Magnusson
@ 2024-02-05 15:21                       ` Ray Andrews
  2024-02-05 15:48                         ` Mark J. Reed
  1 sibling, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2024-02-05 15:21 UTC (permalink / raw)
  To: zsh-users

Gentlemen:

I'm a bit behind here. I hadn't expected this to thread to get so 
involved.  We may have a bit of a mishmash here, thanks for your 
patience as I try to sort it out:

 > Did you see my followup? The variable does not get "promoted"; it's 
still a string,  as you can tell by the fact that += appends to it 
instead of adding.

Right, 'var' isn't fiddled with.  It just seem that taking the value of 
var and using it as the name of a brand new variable seems a bit strange 
to me.  Who cares?  Even I don't care, all that matters is that I'm 
aware of the situation.  I don't like German grammar either but the 
Germans don't care.  At this point all that remains 'open' is that I 
think 'abc' should 'typedef -p' as an integer.  And it seems, as I said, 
that any direct assignment to 'var' breaks the relationship with 'abc'.

 > When I wrote "x+=d", it was not inside arithmetic context, so the 
shell did not interpret either x or d as a number; it just appended the 
literal value "d" onto the end of the string held in x.

Right.  My own post included a demonstration of that.  I get it. Dunno, 
maybe the shell's internal machinery requires the creation of 'abc' as a 
new variable in order to perform the arithmetic.  ... Come to think of 
it, that makes sense.  I'd just not expect the new variable to be 
visible but that's a trivial matter.


     % var="abc+def"
     % abc=2
     % def=3
     % echo $(( var ))
     5

... that stretches my mind yet again.  Interesting that 'var' is 
completely passive as to what "abc+def" might possibly mean until such 
times as an answer is demanded by the echo.

     % var="abc+def"; echo $var
     abc+def

... what must be a simple string when written becomes an addition of two 
variables retroactively.  Ok ... if that's the way it is then that's the 
way it is.  Yeah ... within the $(()) the string 'abc+def' NOW becomes 
an addition of two variables.  Sure ... interpreted ... not C ... not 
retroactive either. more like indeterminate.

 > and this interpretation came about quite naturally from some 
incremental improvements in the shell's ability to do arithmetic.

Right, as I said, arithmetic would have accreted onto the shell at some 
point, so had to be merged in with existing data types.  Sorta like an 
associative array is 'really' just a normal array under the hood, but 
given a different interpretation. Thus the way an A array is easy to 
break if you aren't careful.

 > See, the shell has never really had data types like other programming 
languages.

Exactly.  But it takes deep surgery to cut the C-think out of the 
brain.  "abc+def" looks like a string is a string is a string.

 > ... BASIC got the name from the way you introduce names for things in 
a math proof or paper.

The depth of your historical knowledge astonishes me Mark.

 >Ok, not quite shut up yet.  One note:

     % z=`expr $x + $y`

... actually it's these tortures that are exactly the sort of therapy I 
need.  Too bad there wasn't some document: "Shell programing for folks 
who are used to strongly typed languages."

 > No.  It "increments like one" because you ran "abc=1; let abc+=3",
and the arguments to "let" are interpreted as arithmetic expressions.
If you'd run "abc=1; abc+=3" you would have gotten string concatenation.

RIGHT!  Got it.

 > Using
 >  % let var=value
 > always applies math context, just as ((...)) and  $((...)) and $[...] do.

... it's another gotcha ... I know and expect that $((()) has its 
internal grammar.  But 'let' seems ... naked ... for lack of a better 
word and it's a strain on grammatical rigor that it gets special, 
invisible favors.  Don't like it.  But it's one of those ancient 
traditions that's written in stone, I take it.

 > All your examples have been broken, and your conjectures confused.

Yes.  One tries to form an inner model of what's going on.  Seems 
there's no Phlogiston after all ;-)

 > ... This can have unforeseen consequences.

HA! Yes, that's a little bit of comfort for poor wretches like myself.  
Like trying to get somewhere in Mexico City traffic, one simply needs to 
be very careful.  I expect if we had history to do over again, shells 
would have proper typing and all of this would be 10X simpler.

Thanks guys.



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

* Re: for loop 'bad math expression'
  2024-02-05 15:21                       ` Ray Andrews
@ 2024-02-05 15:48                         ` Mark J. Reed
  0 siblings, 0 replies; 25+ messages in thread
From: Mark J. Reed @ 2024-02-05 15:48 UTC (permalink / raw)
  To: zsh-users

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

> I know and expect that $((()) has its
internal grammar.  But 'let' seems ... naked ... for lack of a better word
and it's a strain on grammatical rigor that it gets special, invisible
favors.

Well, it doesn't, really. Grammar-wise, let is treated as a normal command,
which is why you need quoting to use special characters or white space with
it. The ((...)) construct was added to the shell (and described in the
KornShell book) as effectively a version of let that is quoted for you -
that's where the special parsing comes in. let itself doesn't have that.

It does evaluate its arguments in an arithmetic context, and is one of the
main ways to achieve that effect, but it's not the only one, or even the
only one outside ((...)).  You've seen it kick in for variables declared as
integers; it also shows up in array subscripts:

zsh% ary=(a b c d e); i=2; j=1; k="i + j"
zsh% echo $ary[$k]
c


--
Mark J. Reed <markjreed@gmail.com>

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

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

end of thread, other threads:[~2024-02-05 15:48 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-30  3:39 for loop 'bad math expression' Ray Andrews
2024-01-30  3:46 ` Ray Andrews
2024-01-30  4:04   ` Bart Schaefer
2024-01-30  4:06     ` Bart Schaefer
2024-01-30  4:17       ` Ray Andrews
2024-01-30 13:44         ` Ray Andrews
2024-01-30 14:30           ` Lawrence Velázquez
2024-02-03 23:52           ` Bart Schaefer
2024-02-04  1:14             ` Ray Andrews
2024-02-04  2:05               ` Lawrence Velázquez
2024-02-04  4:20                 ` Bart Schaefer
2024-02-04 16:08                   ` Ray Andrews
2024-02-04 20:56                     ` Lawrence Velázquez
2024-02-04 15:51                 ` Ray Andrews
2024-02-04 20:48                   ` Lawrence Velázquez
2024-02-04 21:09                     ` Bart Schaefer
2024-02-04 21:23                       ` Bart Schaefer
2024-02-05  2:10                     ` Bart Schaefer
2024-02-05  2:43                       ` Mikael Magnusson
2024-02-05  2:50                         ` Bart Schaefer
2024-02-05 15:21                       ` Ray Andrews
2024-02-05 15:48                         ` Mark J. Reed
2024-02-04 14:43               ` Mark J. Reed
2024-02-04 16:37                 ` Ray Andrews
2024-02-04 21:09                   ` Lawrence Velázquez

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).