10 Replies Latest reply on Apr 12, 2012 1:55 AM by OllyGroves

    debug custom function Ways to

    ian.moree

      Hello Everyone;

       

      I am attempting to debug some Cf's i am working on and it really takes time in the data viewer, but putting an evaluate field on a layout helps a bit .

       

      I was wondering if any one has other tips / techniques on how to debug custom functions or is it mostly putting in break points within the function to return certain variables

      before other item is called?

       

      thanks in advance for any help

       

      thank you,

       

      -ian

        • 1. Re: debug custom function [Ways to]
          datastride

          Ian,

           

          If your function is somewhat complicated, try writing a script to do the same thing. Scripts are a lot easier and quicker to debug. (I often just insert a Show Custom Dialog at interesting points to see what's going on.) Once the script runs exactly as you like, converting to a custom function is usually pretty easy.

           

          Or sometimes I just change the custom function (temporarily) to return some intermediate result, which often helps me spot errors very quickly. Once I fix the bad code, I change the function back so it returns the intended result.

          • 2. Re: debug custom function [Ways to]
            ch0c0halic

            Ian may want a custom fit,

             

            My custom functions all use the Let() function. I copy the CF to the Data Viewer and then add data entry definitions in front of the 'normal' variable definitions.

             

            For example in this CF I'd add extra definitions for field1 and field2 before the normal CF definitions. This can be two real fields or just sample data.

             

            CF = comparefield ( field1 ; field2 )

             

            /*

            comparefield ( field1 ; field2 )

            Compare two fields from related tables

            The field name in variables "field1" and "field2" must include the relationship name

            Must have a relationship between tables.

            */

            Let ( [

            //added definitions for field1 and field2 here when debugging, not part of CF

            field1 = company::company_name ;

            field2 = customer::company_name ;

             

            source1 = TextColor ( GetField ( field1 ) ; RGB ( 0 ; 150 ; 0 ) ) ;

            source2 = TextColor ( GetField ( field2 ) ; RGB ( 150 ; 0 ; 0 ) )

            ] ;

             

            Case (

            source1 = source2 ;

            "" ;

            TextStyleAdd ( Right ( field1 ; Length ( field1 ) - Position ( field1 ; "::" ; 1 ;1 ) -1 ) ; DoubleUnderline ) &

            source1 & TextColorRemove ( " - has changed to - " ) & source2

            )

             

            )

             

             

            Note that I added the field1 and field2 definitions to the CF but in reality they would not be there.

            • 3. Re: debug custom function [Ways to]
              PeterGort

              Generally speaking if it's a complex custom function, I build it in stages (using Let()), testing each stage in the data viewer, then assemble.  The result is that my functions look like this:

               

              let([

              v1 = something1;

              v2 = something2;

              v3 = something3

              ];

              conclusion

              )

               

              The other technique I use for troubleshooting is to set intermediate values into global variables using Let(), then evaluate your function in the data viewer.  The global variables will be created and persist with the values assigned to them as the function executed.  This is a good way to follow the logic of your function, but only works where your function isn't recursive of course!  Unfortunately I have the type of mind that tends to create recursive function solutions, so I don't use this technique as much.

              • 4. Re: debug custom function [Ways to]
                Malcolm

                I was wondering if any one has other tips / techniques on how to debug custom functions

                 

                Assemble large functions from components which are known to work. You may even discover that you'll write a lot of small functions that are then called to perform the more complex function.

                 

                Malcolm

                • 5. Re: debug custom function [Ways to]
                  DrewTenenholz

                  Ian --

                   

                  Are you talking about a recursive custom function or a single iteration function?  I don't really have trouble with either in the data viewer, but the since recursion only happens in the CF engine, you can't see the complete result of recursive functions until you load them as custom functions (and some of the calculation you write just can't be done in the data viewer).

                   

                  That said, I have a pretty rigid format for working in the data viewer that makes it pretty easy to get intermediate results and debug individual elements.  Here's a simple conversion from a timestamp that FMPro doesn't read properly into one that it does:

                   

                  Let ([

                  text= "2012-03-11 7:45 PM EDT"  // or I can use a field reference here

                   

                  /* Get the info for the Date */

                  ; year = Middle ( text ; 1 ; 4 )

                  ; month= Middle ( text ; 6 ; 2 )

                  ; day= Middle ( text ; 9 ; 2 )

                   

                  /* Get the info for the Time */

                  ; hours= Middle ( text ; 12 ; 2 )

                  ; minutes= Middle ( text ; 15 ; 2 )

                  ; seconds= Middle ( text ; 18 ; 2 )

                   

                  ; result= Timestamp ( Date ( month ; day ; year ) ; Time ( hours ; minutes ; seconds ) )

                  ];

                  result

                  ) // end Let

                   

                  I don't have to break things down into such small 'atoms', but it certainly makes it easier to understand once I've forgotten how I got a particular result. 

                   

                  Putting the semicolons at the beginning of every new line means that I can easily // comment out something that isn't working.

                   

                  Putting every part of the calculation before the ]; means that I can easily swap out the final 'result' for any of the intermediate values.

                   

                  You can actually have multiple copies of a calculation variable throughout a calculation e.g.:

                  ...

                  ; return= Char (13)

                  ; result= something

                  ; result= Sustitute (something ; return ; "," )

                  ];

                  result

                  ) // end Let

                   

                  I also sometimes use BBEdit (on my Mac) to edit really long & complicated calculations.  It has code coloring (JavaScript is close enough), and helps make sure you've closed your parentheses correctly.

                   

                  Hope this Helps,

                  Drew Tenenholz

                  • 6. Re: debug custom function [Ways to]
                    Malcolm

                    Use BBEdit (on my Mac) to edit really long & complicated calculations.  It has code coloring (JavaScript is close enough), and helps make sure you've closed your parentheses correctly.

                     

                    This is a great tip.

                    • 7. Re: debug custom function [Ways to]
                      ian.moree

                      Takes more time, but i definately see the benefit here..

                      • 8. Re: debug custom function [Ways to]
                        ian.moree

                        This is what i have been doing as well.

                        • 9. Re: debug custom function [Ways to]
                          ian.moree

                          I am talking about recursive , Iterative and normal. Even tail recursion.

                           

                          What i am noticing is that CF's need to eliminate certain criteria in order to continue instead of wasting time; i guess

                          that means one has to draw the idea out first. Which i tend not to do and end up wasting loads of time.

                           

                          Eg:

                           

                          by: * Agnès Barouh - Janvier 2008 

                          ///start

                          Let ( [

                           

                          Portal = PortalName ; Object = ObjectName ;

                          LineHeight = GetAsNumber ( GetLayoutObjectAttribute ( Object ; "Top" ; 1 ; 2 ) - GetLayoutObjectAttribute ( Object ; "Top" ; 1 ; 1 ) ) ;

                          Tolerance = Case ( IsEmpty ( TolerancePixel ) ; GetAsNumber ( Ceiling ( ( LineHeight / 4 ) / 2 ) ) ; TolerancePixel )

                           

                          ] ;

                          Case (

                          Tolerance + 1 ≥ 1 and Tolerance ≤ ( LineHeight - 3 ) and

                          ValueCount ( FilterValues ( LayoutObjectNames ( Get ( FileName )  ; Get ( LayoutName  ) ) ; Portal  & ¶ & Object ) ) ≥ 2 ;

                          Let ( [

                           

                          Agnés has declarations in 1st Let statement ; then she does a check with Case to make sure that we have at least 2 values ( a portal & an object) as well as checking for tolerance . then she goes on to get to the nitty gritty of the function.

                           

                           

                          Recursion: when to use

                          Tail Recursion: when to use ( filemaker engine has limit)

                          Those two i am still trying to understand fully ...Even if they are necessary at times?

                          • 10. Re: debug custom function [Ways to]
                            OllyGroves

                            Chap in UK built free tool few years which help's debug CFs

                             

                            Can't say I've used it a lot but its good stuff.

                             

                            http://www.firstcontactsolutions.co.uk/CFExplorer.aspx