In the prior post (String Optimization. How does it work?) I described an optimization of how the Assignment statement calls the expression evaluator for string concatenation statements.  There are certain limitations with this optimization. For example, if you use a Public variable and call a routine that can modify the variable, you might get unexpected results.

 

            MyPublicVar = MyPublicVar + MyRoutine(MyPublicVar)

 

Another example is passing the variable by reference:

            MyVar = MyVar + MyRoutine(@MyVar)

 

This kind code is very hard to read and does not seem deterministic. Also, in C++, you can write identical constructs, which have undefined meaning.

 

A legitimate case is recursion. Over the last 8 years, we’ve had very few reports of customers running into this problem.

 

Try running the code below, and you’ll get 2 different results.

Why?

The optimization modifies the compiled code to evaluate the addend:

 

            x = x + <something recursive>

is modified to be

            x = “” + <something recursive>

and then the result is evaluated.

The recursive call will see only the modified code, which doesn’t do the append of the addend.

 

There are several easy workarounds:

            y=<something recursive>

            x = x + y

or

            x = “” + x + <something recursive>

 

This has been fixed for the next release.

 

 

 

 

ndepth=3

cResult=recur(ndepth,.t.)

?"Opt=.t. Len="+TRANSFORM(LEN(cResult)),"Result=",cResult

?"Now doing valid res"

cResult=recur(ndepth,.f.)

?"Opt=.f. Len="+TRANSFORM(LEN(cResult)),"Result=",cResult

 

PROCEDURE recur(nLev,fOpt) as String

      LOCAL cstr,i

      IF nlev=1

            RETURN "1"

      ENDIF

      cstr=REPLICATE("_",110)

      IF fOpt

            cstr=   cstr+TRANSFORM(nLev)+"  "+recur(nLev-1,fOpt)

      ELSE

            cstr=""+cstr+TRANSFORM(nLev)+"  "+recur(nLev-1,fOpt)

      ENDIF

      ?nlev,"L="+TRANSFORM(LEN(cstr)),cstr

      RETURN cstr