" +=" operator does string concatenation for integer variables

Bug #1857702 reported by jvdh
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
mksh
Fix Released
Wishlist
Unassigned

Bug Description

consider

typeset -i x=0; x+=1; echo $x # → 1 (as in ksh/bash/zsh)

but

typeset -i x=1; x+=1; echo $x # → 11 (rather than 2 as in the other shells)

I believe mksh should honour the integer declaration and interpret `+=' accordingly. currently, it does not even consistently use string concatentation (since the first example does not yield `01' ...).

Revision history for this message
Thorsten Glaser (mirabilos) wrote :

Erm… that’s right, += is string concatenation.

Write “let” before the line to make it integer addition.

Revision history for this message
jvdh (jvdh) wrote : Re: [Bug 1857702] Re: " +=" operator does string concatenation for integer variables

On 27.12.19 17:02, Thorsten Glaser wrote:
> Erm… that’s right, += is string concatenation.

ok, I got it that this seems to be the idea here, but

1.
what about

    typeset -i x=0; x+=1; echo $x # → 1 (as in ksh/bash/zsh)

if += categorically does string concat no matter what, should this not yield "01"?

2.
the trio ksh93/bash/zsh all adjust the meaning of += to denoting integer addition/increment if the
variable is declared integer. do you consider this "evil" and intentionally do not do it? it bit me
when porting a somewhat elaborate script from ksh93 to mksh: suddenly 1+=1 yielded 11 rather than 2.

I'm not sure what the "mission statement" of mksh is (if any) but I see that you come closer to
ksh93 than bash in some regards (e.g. `set -A' and '${... ;}' command substitution are provided)
and presume it is intended to emulate ksh93 where the latter is not manifestly broken? meaning:
should mksh not follow the other shells (notably ksh) in how they handle += for integer variables?

>
> Write “let” before the line to make it integer addition.

understood. thanks for pointing this out. I never so far hat any use for `let' ;)

Revision history for this message
Thorsten Glaser (mirabilos) wrote :

01 in an integer variable is still 1 on output (010 may be 10 or 8 depending on the posix flag)

more later

Revision history for this message
Thorsten Glaser (mirabilos) wrote :

and it’s most definitely not emulation of ksh93

some ksh88 and little parts of ksh93, but e.g. no float and other crap or complicated things

Revision history for this message
jvdh (jvdh) wrote :

On 27.12.19 23:02, Thorsten Glaser wrote:
> and it’s most definitely not emulation of ksh93
>
> some ksh88 and little parts of ksh93, but e.g. no float and other crap

I've never used ksh88. so I do not know the intersection with ksh93. but my experience so far is
that it seems easier to port a ksh93 script to mksh than to bash. so ...

> or complicated things

out of curiosity: what's on your "crap" list? what's on the "complicated" list regarding ksh93
(beyond compound variables ... ;))?

personally, I wouldn't count ability of a "general purpose" scripting language to do floating point
arithmetic as "crap". admittedly, I don't use that very often in ksh93 but it's good that it's there
if needed (and calls to awk or whatever can be avoided).

Revision history for this message
Thorsten Glaser (mirabilos) wrote :

As discussed heavily on IRC, other shells can use ((…)) or let to work like mksh, and the mksh behaviour is semantically correct. I’ve documented this in more detail in the manual page and the mksh FAQ now but kept the behaviour as to not break older scripts written in mksh.

You might wish to open bugs with the other shells to make behaviour match mksh, or warn when the underlying variable is an integer.

Changed in mksh:
importance: Undecided → Wishlist
status: New → Fix Committed
Revision history for this message
jvdh (jvdh) wrote :

thanks for making this discrepant behaviour of mksh more explicit in the manpage/FAQ. I believe this is helpful (as, generally, a "(in)compatibility table" comparing all relevant shells would be...).

regarding opening bugs all over the place in (at least) 3 other shells for this issue: funny ;).

I think the strongest argument against changing mksh here is maintaining upward compatibility (old scripts yield same answer with new mksh: that's upward, right?). the same of course holds for the others...

I even would claim that, e.g., x+=1 in an "integer context" as a short hand for ((x+=1)) might be used rather often in bash/ksh93/zsh while it should hardly _ever_ be used on integers in mksh scripts (who wants to get the integer sequence 1, 11, 111, ... in this way, eg.?).

so even if the breaking change were done, it would possibly not be causing much pain, I could imagine.

so I still believe that += either should choke on integers (throw an error) or do the same as the others. getting an error would be quite OK: fixing it via ((...)) would than be trivial. _not_ getting an error but totally different result than in the other shells, _that_ is not so good in my view.

but I understand you do not want this change. so that's that... ;)

Revision history for this message
Thorsten Glaser (mirabilos) wrote :

Warning reporting during running of a script is supremely hard, you cannot use any file descriptors; basically, you have to reserve one with a high number for syslog and do it that way and hope someone reads syslog… so I never did. We really need a linting shell runner or something ☹

Revision history for this message
jvdh (jvdh) wrote :

maybe you can convince the `shellcheck' guys to support mksh ;).

but I was rather thinking of "error" as in "syntax error", i.e. disallow += on integers all together as being then easy to spot and repair. I am somewhat paranoid about shells silently behaving differently, that's all ... :). for the time being I will try to strictly avoid += altogether for arithmetic outside ((...)) in all shells...

Revision history for this message
Martijn Dekker (mcdutchie) wrote :

Op 29-12-19 om 23:55 schreef Thorsten Glaser:
> As discussed heavily on IRC, other shells can use ((…)) or let to work
> like mksh, and the mksh behaviour is semantically correct.

Your position makes no sense, because in mksh (and ksh93, bash, zsh) you
can do things like:

$ typeset -i i
$ i=4+4; echo $i
8
$ i=i+1; echo $i
9

...yet, in mksh:

$ i+=1; echo $i
91

That is clearly inconsistent. 'typeset -i' makes shell assignments
interpret arithmetic expressions (as is documented in the manual page),
and '+=' is just another form of shell assignment, therefore it should
be changing the behaviour of '+=' as well as '='.

ksh93, bash and zsh all act correctly here. mksh is a ksh clone and
should be acting like ksh and all the others that have emulated ksh.

- M.

--
modernish -- harness the shell
https://github.com/modernish/modernish

Revision history for this message
Thorsten Glaser (mirabilos) wrote :

This totally makes sense in mksh only.

$ i=4+4; echo $i

This is an assignment of the string "4+4" to the variable i. The string is then, between assignment and storage, parsed as an arithmetic expression, because i is of integer type. The expression is calculated and the result stored.

$ i=i+1; echo $i

This is an assignment of the string "i+1" to the variable i. The string is then, between assignment and storage, parsed as an arithmetic expression, because i is of integer type. The expression is calculated and the result stored.

This works because i=anything, if i is integer, is precisely the same as i=$((anything)).

$ i+=1; echo $i

This is an assignment of the string “${i}1” to the variable i. The string is first expanded as "11", then evaluated as an arithmetic expression, and the result (the number 10#11) stored. This is the same as: i=$((${i}1)).

“var+=text” is the same as “var=${var}text”. This is the basic tenet, and this is the thing that will not change. (I am now decided.) The other mentioned shells do this wrong. (This is one thing I will not budge for cross-shell consistency.)

It’s much easier to accidentally introduce an error with += forgetting that the target variable is integer (the integer flag may even have been set by a caller!) than not using proper integer arithmetics.

Just write one of these:

$ let i+=1; echo $i
$ (( i += 1 )); echo $i
$ (( ++i )); echo $i
$ echo $((i+=1))

These should work the same in all shells mentioned.

At that: if a *caller* passes you an integer variable, in all other shells you cannot use “+=”, which means you cannot use “+=” in the other shells reliably at all.

function strconcat {
        nameref _strconcat_tgt=$1
        _strconcat_tgt+=$2
}
typeset -i foo=1
strconcat foo 2

Bam!

Changed in mksh:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.