Showing posts with label Custom Function. Show all posts
Showing posts with label Custom Function. Show all posts

Tuesday, December 4, 2012

Working with Constants in FileMaker Pro

In most programming languages there are something called Constants which, as the name implies, are  constant values that never can change during runtime. If your not used to coding using constants I´m sure you feel a bit uncertain on why they are useful and I encourage you to keep on reading. A constant differs from a variable because a variable can change during the application runtime while a constant can not. A variable can also be set during runtime and then get unset, destroyed or released (whatever term you prefer) so that it not longer exist. Typically a constant will be declared when the application launch and live throughout the the entire runtime, unchanged. 

In object oriented languages a constant it not necessarily declared at application launch and it can be subject to object scope just as a variable can but luckily that is not something we need to bother with in FileMaker Pro.

So what is the whole point of setting a named value that can never change? One big advantage is readability and reliability in comparisons and when passing parameters. The value is readable like a string but can carry a numeric value safely used in comparisons or as parameters. 

An example is sort order. We can sort records ascending or descending using a script and a script parameter tells us which order to use. The most common practice is to send string parameter such as "asc" or "ascending" to the script which of course works just fine. However what we just did was to hardcode a value that possibly can change inside the script in the future. There is also a risk of a miss-typing sending a parameter value to the script the will not work. 

If you instead declare constants for sortorders such as SORT_ASC and SORT_DESC you will not need to pass them as strings and FileMaker will instantly tell you of you typed a letter incorrect. You will also be using the same constants for this action throughout you entire solution and consistency is a very important aspect when programmering!
The two constants SORT_ASC and SORT_DESC can represent simple values as 1 and 2.

Inside the script you will use the constants again. Most lightly you will have a IF-statement checking which sortorder was passed to the script. The value passed is just a simple 1 or 2 but because you want to sustain readability you will us your constants again. Look at the two screenshots below, the one on the left is the parameters passed to the script and the one on the right is the comparison inside the script. Please note that there are no quotes surrounding the parameters, the are NOT strings and thus NOT hardcoded!  



The advantage of coding with constants as shown above is that it is both readable, safer, adds consistency and theoretically is better in a performance point of view.

In the FileMaker community very few developers make use of the easy way given to us to declare constants. Simply create a custom function named to whatever your constants name should be. Then simply make it return a simple value, preferably a numeric value. In my example SORT_ASC return 1 and SORT_DESC returns 2.

For some reason constants are often written in capital case letters which is a good practice to use in FileMaker as well.

To give you one more example when working with constants is a good ide we can look at ExecuteSQL. When using ExecuteSQL we are required to specify a separator for records and a separator for fields. To use simple one character separators like linebreak and semicolon is not very safe since the probability that these characters exist inside the returned fields is high. Instead try to use a more complex separator is is unlikely to exist inside any field, something like #%@@%# .
This is a great time to use constants. Declare one constant as a record separator and one as row separator. 

Example:
COL_SEPARATOR = #%@@%#
ROW_SEPARATOR = #%@!@%#

This way things get much more readable and you can be confidant you will always use the same separators in every query. This also makes it easier to safely extract values from the query result.

So, don´t be afraid to use custom functions as constants. It can be a great tool when developing with FileMaker Pro! 

Thursday, November 15, 2012

Working with multiple script parameters

When writing scripts in FileMaker Pro I feel that it is important to make as many reusable scripts as possible. A reusable script is not just a script that can be called from, say a list- and detail-view of the same table occurrence. According to me a fully reusable script is a script that can be called from wherever and whenever. The developer calling the script should not have to worry about what layout or context the user is in, not even which mode the current window is set to (browse, find or browse). It is also important to make it easy to understand if the script calls any GUI elements and if there is a silent mode for delicate processes or scheduled server scripts and the WPE.

This blogpost is not a lesson in writing reusable scripts, it is a guide to one of the ways to work with multiple script parameters. Being able to declare more then one script parameter in a fast and secure way and also to fetch those parameter values inside the script is a key element of writing reusable scripts. Everything inside the script that is configurable should be possible to set using script parameters.

One of the simplest ways of passing many parameters to a script is by simply using a list of values (values separated with line break). Inside the script the values is separated using getValue(). This however fails as soon as you want to pass a value that could contain line breaks.

The more complex way to do it is by defining your own separator or sending values in a XML like format or simular.  That would fix the line break issue but not the issue of storing the values inside script variables and not without using quite a lot of lines in the beginning of the script.

I wanted be able to declare several script parameters, named and ready to use, on the single textline that is available for us for passing a parameter to a script. Also I wanted to avoid making my script super long only because the need to divide string values into script variables. After thinking about it for a while I came up with two custom functions. One takes care of binding a value to a parameter name and the other takes care of defining the named parameters as script variables.

There are many ways to do this or things simluar to this and what I will show you here is just my way of doing it. It is fast, reliable and I use is all the time. It handles declaring both one- and two-dollar-variables and even repeated variables. You don´t have to worry about forbidden characters or patterns since there are none. It even works when returning values from a finish script kind of like using multiple script results.

The two custom functions looks like this

RegisterParam ( name ; value )


Let([
n = Substitute( name; ["¶";""]; [" ";""];["$";""];["-";""];[".";""];["+";""];["-";""];["*";""];["/";""];["\\";""];["\"";""];["'";""];["!";""];["#";""];["€";""];["%";""];["&";""];["(";""];[")";""];["{";""];["}";""];[",";""];["<";""];[">";""];["?";""];["´";""];["`";""];["=";""];[",";""];["§";""];["°";""]);

$$_RegisterParamController = Case(
PatternCount( "¶"&$$_RegisterParamController&"¶"; "¶"&n&"¶")<1 and Length(Value)>0; $$_RegisterParamController & n&"¶";
PatternCount( "¶"&$$_RegisterParamController&"¶"; "¶"&n&"¶")>0 and Length(Value)<1; Let($$_RegisterParamController[ValueCount(Left($$_RegisterParamController; Position("¶"&$$_RegisterParamController&"¶"; "¶"&n&"¶"; 0; 1))) + 1] ="";Replace($$_RegisterParamController; Position("¶"&$$_RegisterParamController&"¶"; "¶"&n&"¶"; 0; 1); Length(n)+1; "¶"));
$$_RegisterParamController);

r = ValueCount(Left($$_RegisterParamController; Position("¶"&$$_RegisterParamController&"¶"; "¶"&n&"¶"; 0; 1))) + 1;

$$_RegisterParamController[r] = If(r>1; value; $$_RegisterParamController[r])

];"")



RegisterParamsAsVariables ( )


Let([

n = GetValue($$_RegisterParamController; ValueCount($$_RegisterParamController));

e = If(n="";"";Evaluate("let($" & n & "=$$_RegisterParamController[ValueCount($$_RegisterParamController)+1];\"\")"));

$$_RegisterParamController[ValueCount($$_RegisterParamController)+1] = "";

$$_RegisterParamController = LeftValues ( $$_RegisterParamController; ValueCount($$_RegisterParamController)-1)

];

If(ValueCount($$_RegisterParamController)>0; RegisterParamsAsVariables;"")

)


I will not spend time explaining the syntax of the calculations. If you feel curious I´m sure you are able to reverse engineer the syntax and understand what is going on. I will however show you how to use the functions.

First of you need to create the two functions in your FileMaker file. Goto the Manage Custom Functions Dialog and add two new functions. The first one must be named RegisterParams and have two parameters, "name" and "value".
The second function must be called RegisterParamsAsVariables and it uses no parameters. You can simply copy and paste the syntax from above the the two functions.


You are now ready to go. To testdrive the two functions you can do the following. Create a button on your layout and make it perform a script. As parameter to the script pass the following example:

RegisterParam ( "test1" ; "Hello World" ) & 
RegisterParam ( "test2" ; "We love FileMaker" ) &
RegisterParam ( "test3" ; "Matt Petrowsky is a funny guy" ) &
RegisterParam ( "test4" ; "Brian Dunning got > 100 Custom Functions" )



As you might figure out this will pass four different parameters to your script (no offense ment to Matt or Brian!). Before you can use them though you must perform the second function called RegisterParamsAsVariables inside your script. How you perform it does not matter, the simplest way is to set a dummy script variable to the result of the metod. Since RegisterParamsAsVariables does not return any values the dummy variable will never exist. A simple test script looks like this


The first line is all we really need but to be able to show you in the Data Viewer what happens I also added a second script step after setting the dummy variable.
When stepping trough the script before setting the dummy variable the Data Viewer looks like this.


But after running the RegisterParamsAsVariables function (setting the dummy variable) the proper script variables has been set and are ready to use.



If you want to set a two-dollar-variable or repeated variable simple prepend your parameter name with a dollar sign or append brackets with the preferred repetition number, or both =)


RegisterParam ( "normalValue" ; "Hello World" ) & 
RegisterParam ( "$twoDollarVar" ; "We love FileMaker" ) &
RegisterParam ( "normalValueRepeated[5]" ; "Matt Petrowsky is a funny guy" ) &
RegisterParam ( "$twoDollarVarRepeated[5]" ; "Brian Dunning got > 100 Custom Functions" )


I hope you can use these functions for something good, they work well for me! Time for lunch!

Tuesday, November 6, 2012

Writing recursive Custom Functions

Custom Functions has been around since versions 7 of FileMaker. For specific problems a custom function can be a real life saver. The most common area of use is string handling and manipulation. Before we hade GT, GTE, LT and LTE operators in relations one very common use was generating intervalls of dates or numbers for showing a range of records in portals or related valuelists.

Today, with current version FileMaker 12, the use of custom functions hade changed somewhat. I would say that the most common use today is data gathering or parsing using either ExecuteSQL or getNthRecord. The need to make subqueries for data without bothering about the current context seem bigger then ever.

In many cases one or more aspects of a task for a Custom Function is dynamic. For example a list of values can be sent as parameter and your functions task is to sort the values or perhaps filter unique values. In this case you more or less must apply recursion to your Custom Functions.

The method for recursion available to us is called tail recursion. As the name implies it means calling the function from within itself, usually in the end of the calculation (at its tail). It is not very hard to write a recursive custom function. The one important thing one must keep in mind is some sort of controller that keeps track of when the Custom Function is done executing. If we just keep calling the function from within itself it will continue to run forever, or rather until the callstack is full.
A controller can be anything from a numeric counter that should reach a predetermined value, to a list of values that should be parsed and one value removed until the list is empty. Anything we can catch using a If-statement can act as a controller.

The very simplest recursive custom function can look like this
There is one parameter to this function and that is the counter that keeps track of how many times the function shall call itself. In this case the If-statement will be true when the counter is greater then 10. When that happens it will return the value of the counter, else it will call itself with the value of counter plus 1 as parameter.
If you call this function in a calculation and set the counter parameter to 1 the result will be 11 because the function will call itself 10 times. 1 + 10 equals eleven.

Now to what I really wanted to blog about. The method above works just fine but there is, according to me, a better way to pass values between the recursive calls. Instead of using parameters I prefer to store my values in two-dollar-variables (persistant variables). That does not make things much more complex but it do require that we use the Let-function (or Let-statement if you prefer to call it that). The Let-statement allows us to set and unset variables with three types of scope.

  • Local variable - Only accessible inside the current Let-statement
  • One-dollar-variable - Accessible in the current script during runtime, not really useful in this case
  • Two-dollar-variable - Accessible in the entire database until we unset it
The benefit of using two-dollar-variable in this case is that we only need to define parameters that the developer must worry about setting. If we want to pass more then one value between recursions the function is in risk of being difficult to use because some parameters are required and some are just data carriers between recursions. A good rule of thumb is to mimic FileMaker Incs way of naming functions and parameters. Make the developers that will use you function feel right at home.
FileMaker uses upper camel case for function names  and lower camel case for parameters.

Example (notice the lower case in the first char in lower camel case)
  • UpperCamelCase
  • lowerCamelCase
FileMaker does not use underscore or other special characters so neither should you.

Of course you can argue that you can reuse a parameter by concatenating strings and then divide them again in the following function call but I would not recommend this since it tends to make your calculation harder to read and force it to do a lot of unnecessary work.

Now to the fun part, how to store the values in two-dollar-variables. We need two let-statements for this. One that contains the entire calculation and one that simply clears the two-dollar-variables when done. First, here is a screenshot of a recursive custom function that filters out unique values from a list of values.

Lets break that down into parts


// Initiate the Let statement
Let([

// Set a two-dollar-var that acts as value counter, when this 
// is equal or greater to the amount of values in the list
// the function will no longer call itself but instead return
// a list of unique values. On the first call this value will
// not be set so we make sure it is set to 1
$$counter = If$$counter < 1; 1$$counter );


// Set a two-dollar-var that stores the current value that we
// are testning. We use the counter to get the next value from 
// the list
$$currentValue = GetValue(ListOfValues$$counter);

// Set a two-dollar-var that holds the list of values to 
// return when everything is done. This list holds the 
// unique values found and is added to when a new value is
// encountered. The If-statement checks if the value already
// exist in the returnstack
$$returnStack = $$returnStack & 

    IfPatternCount"¶" $$returnStack "¶"; "¶" & $$currentValue & "¶" = and Length$$currentValue 0

        // If true
        $$currentValue "¶"

        // If false
        "" 
    );

// Set a local variable to hold the list of values to return
// in case the current recursion is the last. We do not need to 
// worry about clearing this var, that is done automatic. We 
// need to store this locally so that we can clear $$returnStack 
// if needed  
return = $$returnStack

// End the declaration part of the Let-statement 
];

// Check if the value of counter is greater then the count
// of values passed to the function as parameter listOfvalues when 
// calling in. If the value of counter is less we call the function
// again to make one more recursion. If the value of counter is 
// greater then we are done looping and shall return values. 
// We return values using a Let-statement to clear two-dollar-vars 
If( ValueCount( ListOfValues ) > $$counter
    
    // If true
    FilterUniqeValuesListOfValues );
    
    // If false
    Let([
        // Clear two-dollar-vars because we are done looping
        $$counter "";
        $$currentValue "";
        $$returnStack ""
    ]; 
        // Return the list of unique values 
        LeftreturnLengthreturn ) - )))
)



Of course this is a bit excessive commenting even for me but I hope it clarifies what the calculation does. The point is that the function carries three values ($$counter, $$currentValue and $$returnstack) as two-dollar-variables between recursions and because the are two-dollar-variables we do not need to pass the values as function parameters between recursions. The syntax is very simple to read, executes quickly and the developer using the function only needs to see the one parameter that he actually is using.

When we return values the Let-statement on the end clears the two-dollar-variables and thus they are gone the second the function is done looping.

There is however one safety factor to think about. Since two-dollar-variables are scoped to the entire database is is wise to user fairly long variable names. This is to ensure that no existing two-dollar-variables gets replaced by the ones used by the function. As example the name $$counter is a very poor choice. It is likely that the very same name could be used in a script where this function is used and in that case the name would colide.

In my working version of the function above I use the following names to make sure that wont happen


  • $$counter is called $$RQCF__FilterUniqeValues_Counter
  • $$currentValue is called $$RQCF__FilterUniqeValues_CurrentValue 
  • $$returnStack is called $$RQCF__FilterUniqeValues_ReturnStack 
making the complete function look like this
The longer names on the two-dollar-variables make the syntax a little bit harder to read but they also make sure we won´t run into name conflicts later on.

I hope this post helped you realize the benefits of storing values between recursions in two-dollar-variables instead of complex parameter handling. Have a nice day =)