Question
· Apr 2

What is the Difference Between do $Increment and if $Increment?

I'm currently making some changes to legacy code and I've noticed that it uses "i $i("  all over the place. Testing in terminal seems like this does the same thing as "do $i()". Is there a difference between these two (and if not is there some interesting history around this)?

Discussion (7)5
Log in or sign up to continue

In older versions, trying to run "do $i(a)" would throw a <SYNTAX> error. You could instead use "if $i(a)" or "set a = $i(a)" to do the same thing. The "do $i(a)" was added with IRIS 2019.1 because it's a nicer-looking syntax. So you can treat them as identical, and the only reason to care either way is if you want to write code that is backwards-compatible with older Caché / IRIS versions.

It's not a "slight difference", it's a real difference, because you are using two different commands (a DO and an IF command)

set a = -1        // sets the variable a to -1
do $increment(a,1) zw "test" // increments <a> by 1, <a> is now 0
                             // the $increment() returns (the value of <a>)
                             // but the DO command do not expects a return value
                             // so the returned 0 is disposed
                             // hereinafter the next command on the line (zw) is executed
if $increment(a,1) zw "test" // increments <a> by 1, <a> is now 0
                             // the $increment() returns (the value of <a>) which is 0
                             // the IF command takes the returned value (0) but the value is
                             // "FALSE", hence the rest of the line is skipped (old style IF)
                             

If yo want to use the IF command and want both commands to be executed and have them on one line then:

// you have several options, a few of them
//
if $increment(a,1) { } zw "test" // empty IF-statement
if $increment(a,1)!1 zw "test"   // an IF with a forced outcome
if $increment(a,1)=a zw "test"   // if a=$increment(a,1) WON'T WORK !!!
//
// The only limit is only your imagination...

By the way, it's not a good idea using commands/functions with abbrevations and at the same time using mixed cases. In your examples I had to take a second look to realize, the one is a capital "i" and not a lowercase "L"

if $I(a,1) // increment a by 1
if $l(a,1) // return the subfieldcount from <a>, delimited by the character "1"

In other words, it's a kind of performance optimization when using $increment

I was surprised when discovered that $increment with locals is not so well optimized as it can be and as it is for globals. A small proof:

USER> set top=1E7,^||a=0,t=$zh for i=1:1:top {set ^||a=$get(^||a)+1} w $fn($zh-t*1E6/top,"",3)
0.265
USER> set top=1E7,^||a=0,t=$zh for i=1:1:top {do $i(^||a)} w $fn($zh-t*1E6/top,"",3)
0.176
USER> set top=1E7,a=0,t=$zh for i=1:1:top {set a=$get(a)+1} w $fn($zh-t*1E6/top,"",3)
0.050
USER> set top=1E7,a=0,t=$zh for i=1:1:top {do $i(a)} w $fn($zh-t*1E6/top,"",3)
0.056

I intentionally inserted $get() call just to make samples functionality closer to each other.

It's rather difficult to get for what reason $i(a) is not just the same as `set a=$get(a)+1` as it's nothing to do with TP and other globals related stuff here?

Maybe nobody was interested in deeper optimization of $i() in this context...

$increment is (or used to be) unique in that it was the only function that changed its argument. It reminded me of learning about "destructive functions" in LISP a long time ago. No matter where/how you use it, it increments. So "set a = $increment(a)" is redundant, but still OK to use. As you saw, developers started to use "if $increment(a)" alone, because that was shorter but also works fine, even thought it looks strange. I wasn't aware of "do $increment(a)" being allowed, which does look nicer, so I also learned something new from this thread, thanks.

And let's not forget to mention the popular and useful "set a($increment(a)) =  something"

You can use the if $i to do some stuff within loops too. For example, if you enter the following to commands in a terminal:

set a = 5
for{if $i(a,-1){w a,!}else{quit}}

This will subtract 1 from a and write its value until it reaches 0, then quit the loop. Of course you could just as easily use for a=4:-1:1 {w a,!} to produce the same output a little more nicely, so you don't see that as much.