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)?
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.
I also found one slight difference between the two:
ED>set a = -1
ED>d $I(a, 1) zw "test"
"test"
ED>zw a
a=0
vs.
ED>set a = -1
ED>i $I(a, 1) zw "test"
ED>zw a
a=0
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"
Often the if command is used for $increment because that is the "cheapest"/lightest way to increment a (local/global) variable.
In other words, it's a kind of performance optimization when using $increment.
Personally I use all the times I use $increment and I don't need the incremented value back.
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:
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.