14 Replies Latest reply on Oct 5, 2015 4:35 PM by user19752

    Loss of variable value in recursive custom functions?

    FrankvanderMost

      The following recursion function called test_recursion with one operator called number will work, i.e. it sums up the range 0+1+2+...number

       

      Let ( $step = number ;

       

          Case (

              $step = 0 ; 0 ;

       

              $step + test_recursion (  $step - 1 )

          )

      )

       

       

      However if instead of '$step + test_recursion (  $step - 1 )' I use 'test_recursion (  $step - 1 ) + $step', it will not work (the result of a function call is always 0).

      In my understanding of recursion both should work since the recursions are stacked.

       

      After some testing, I found out that one recursion forgets its variable value of $step after returning from the recursive call. Try using  "'" & $step & "'" & test_recursion (  $step - 1 ) & "'" & $step & "'"  instead of  $step + test_recursion (  $step - 1 ) 

       

      Does anyone know if this is normal behavior and if so why this is?

       

      I am guessing that it has to do with the fact that FMP's function engine is optimised for tail-recursion, but if regular recursion is possible (even though not optimized) it should work too.

        • 1. Re: Loss of variable value in recursive custom functions?
          user19752

          You use $variable, then it is shared in every recursion. Try without $.

          I don't think it is clearly described, but $variable has scope in

          defined script

          field calculation

          recursive calling

          etc?

          • 2. Re: Loss of variable value in recursive custom functions?
            FrankvanderMost

            Hi user19752

             

            Thank you for your reply and indeed, it does work without $

             

            I started looking for what you said and the scope of $ and $$ variables is mentioned in the documentation of the Let function.

             

            As you also said, it is not clearly described, at least not there.

            The confusing part is that it is not explicitly said (although it is made clear by example) that apparently there is third type of variable that has neither $ nor $$. $ variables are called 'local' but when defined in a calculation the scope is the file (when scripts are not running). This does not sound so local to me.

             

            Anyways, I can move on. thanks again.

            • 3. Re: Loss of variable value in recursive custom functions?
              jbante

              Is that the actual function you're working with, or an example of odd behavior you were troubleshooting? If that really is the function you're working with, there's a more efficient way that's completely non-recursive:

               

              number * ( number + 1 ) / 2

               

              Using a "local" $variable isn't necessary for this function, but don't let it dissuade you from using $variables in custom functions when appropriate. It's the most efficient way to pass data from one recursion to the next without adding parameters to the function. You just have to remember to clear the variables when returning the final result.

               

              The scope of "local" $variables outside a script isn't well documented, but it's nothing particularly complicated. A local $variable declared outside of a script is available in a file-wide "script 0", if you will. As long as no script is running, any reference to the $variable will refer to the script 0 version. Once you start a script, the script 0 version isn't available, and only local $variables declared while that script was running are available. Once all scripts are done, the script 0 version is available again. It's been trustworthy for custom functions for a long time, but I wouldn't get in the habit of using script 0 variables for anything else. We can't count on undocumented features to continue behaving the same way in future versions.

              • 4. Re: Loss of variable value in recursive custom functions?
                FrankvanderMost

                Thank you for your addition, jbante. I'll take your advice and don't make a habit out of using this feature.

                 

                Thank you for your concern about the example function. It wasn't the actual function. I can't remember exactly, but maybe I just wrote the example for the question and perhaps I actually made it to see if I could recreate the behaviour in a different function.

                • 5. Re: Loss of variable value in recursive custom functions?
                  Extensitech

                  jbante alluded to this, but it may be worth noting: If you're in a script when you call this function, you'll set $step in that script. So, for instance, if you call this function within a script loop where you're using $step to count iterations, your custom function will reset the $step you're using to count iterations. Using a generic variable name like $step seems a big risk to me, since you, or another developer, may well use "$step" to mean something else, and end up with results that seem bizarre, and have a hard time telling where the changes to $step are coming from.

                   

                  Some time ago, there seemed to be a trend of using $ variables in custom functions (and other let statements) to clearly identify all the variables. This seems to have passed. I've seen the ~ used for identification of variables jbante's (very useful!) functions, and while I personally find them a bit difficult to read, it makes more sense to me that throwing out a bunch of $variables that could conflict.

                   

                  OTOH, the ability to set a bunch of script variables at once can be useful. I have logbegin and logend functions I use in all my scripts, for instance, where logbegin sets things like script name, user, timestamp and so on at the beginning of every script, and logend reads those variables to create a log parameter at the end of the script. When using this on purpose, though, I do things like including the function name in the variable name, so that I don't inadvertently use the same variable name for something else during my scripts.

                   

                  HTH

                   

                  Chris Cain

                  Extensitech

                  • 6. Re: Loss of variable value in recursive custom functions?
                    beverly

                    I "set" many variables in one Let():

                    Set Variable $sp ;

                    Let (

                    [ $a = 1

                    ; $b = 3

                    ; $c = "abc"

                    ]; 1

                    )

                     

                    in the end $sp, $a, $b & $c will be set. The same would work for setting $$variables.

                     

                    beverly

                    • 7. Re: Loss of variable value in recursive custom functions?
                      Extensitech

                      Likewise. It's a great tool when used intentionally.

                       

                      I've seen some developers do the same just to set $sp, though, not realizing that $a, $b and $c aren't just let variables now, they're $variables that can (and sometimes should) overlap with your script variables. Especially with custom functions, I'd be worried that someone would use $b later as a script variable and go, "hey! where'd that 3 come from?!"

                       

                      It's definitely a powerful tool for setting multiple variables at once, but not if your intent was to just use them in the context of your Let.

                       

                      Chris Cain

                      Extensitech

                      • 8. Re: Loss of variable value in recursive custom functions?
                        beverly

                        But I don't use this method in a custom function, just in a script step in a script that will use the "set" variables from the Let().

                        • 9. Re: Loss of variable value in recursive custom functions?
                          user19752

                          "a bit difficult to read"

                          I tried using UUID for variable name that should be global, so that never conflict others

                          Re: Is it possible in FileMaker v.14 to set a random seed in a script?

                          but looks so bad

                          • 10. Re: Loss of variable value in recursive custom functions?
                            DavidJondreau

                            If you're writing a recursive custom function, it's not easy creating a random $variable name that doesn't simply get reset on every call.

                             

                            It's usually best to use a $variable that has the same name as the custom function itself: $cf_ValuePosition and to be sure to clear it at the end of the recursion.

                            • 11. Re: Loss of variable value in recursive custom functions?
                              FrankvanderMost

                              I'm sure that there are handy and powerful applications of, say, non-local variables, but I would stick to making sure a variable does not exist outside the script or function where I use it. For me finding out that the $variable existed outside the function (better: function call) that declared it was an unwelcome surprise.

                              • 12. Re: Loss of variable value in recursive custom functions?
                                user19752

                                My thought was, using UUID can be some protection for "copy and paster", but anyway function name should be changed if conflict, so using "same name as cf" is good.

                                 

                                I thought using really random name that Get(UUID) function itself is in cf, but containing the name as parameter for recursive call seems a bit foolish

                                • 13. Re: Loss of variable value in recursive custom functions?
                                  DavidJondreau

                                  Ah, I think I understand. You're saying use a hardcoded UUID for $variable names inside a custom function. That could work. But what if you called the same cf more than once in a script? Would that cause problems?

                                   

                                  Aside from defining $variables to be deliberately used outside of the script (per Beverly's post), the only reason I see to use a $variable is to pass information (usually a counter) from one iteration to another instead of using a function parameter. Obviously, using a parameter slot to pass a UUID to encode a $variable doesn't help towards that goal.

                                  • 14. Re: Loss of variable value in recursive custom functions?
                                    user19752

                                    The function (return random number sequence) need keeping value until next time it is called (not only in script), so I used $$variable. (and, the function is not recursive)