registercustomfunction
registercustomfunction
FOLDER
,
NAME
,
PARAMETERCOUNT
,
SOURCE

The registercustomfunction statement defines a new custom function.

Parameters

This statement has four parameters:

folder – This parameter is unused but is retained for compatibility with Panorama 6. You can either set this parameter to `""` or omit it entirely

name – This is the name of the custom function. The name must start with a letter, and then may contain letters, numbers, period, underscore, and the omega symbol (Ω). Upper and lower case are the same (function names are case insensitive). Earlier versions of Panorama required that the function name end with `(`, but this is now optional. (Of course the `(` is required when using the function.) When choosing a custom function name, make sure you don’t use a name that Panorama is already using – doing so could cause Panorama to break. A good practice is to always prefix your custom function names with a special prefix, perhaps your initials or company name.

parametercount – The number of parameters the function has (0, 1, 2, …).

source – the body of the function. This is the formula that calculates the value returned by the function. If the function has parameters, they must be represented as `•1`, `•2`, `•3`, etc. Note that the entire formula must be quoted.

Description

This statement defines a new custom function. Once a function is defined it remains defined until you quit Panorama, even if the database that originally set up the definition is no longer open.

This example creates a new custom function named concatenate(. This function has two parameters.

    registercustomfunction "CONCATENATE(",2,{•1+•2}

Once the function is defined, you can use it in any other formula, just like functions that are built in to Panorama.

    Name = concatenate(First,Last)

Starting with Panorama X, you can now define the same function more than once, with different numbers of parameters.

    registercustomfunction "CONCATENATE(",2,{•1+•2}
    registercustomfunction "CONCATENATE(",3,{•1+•2+•3}
    registercustomfunction "CONCATENATE(",4,{•1+•2+•3+•4}

Now you can use this function with different numbers of parameters.

    Name = concatenate(First,Last)
    Name = concatenate(First,Middle,Last)

Using this technique it’s possible to make the same function do something completely different if it has different numbers of parameters, but we don’t recommend doing that.

#### Defining Functions in a Custom Statement Library

A good place to define a custom function is in the `.InitializeFunctions` procedure inside a custom statement library (inside the `~/Library/Application Support/PanoramaX/Libraries` folder). If you put your custom function definition code in that procedure (as shown below), it will run automatically when Panorama starts up, and will also run automatically when you use the Libraries>Register Functions and Libraries command in the View Organizer (you should do this each time you change the custom function definitions and want to try them out).

To learn more about Custom Libraries and how to create and use them see Custom Statements.

#### Defining Custom Functions with Procedure Code

Custom functions are normally created based on a simple formula. But by using the call(, callwithin( or execute( functions you can create a custom function that uses a procedure to calculate the function value. This gives you tremendous flexibility, but with a cost – a custom function based on a procedure will be much slower* than a custom function that is simply based on a formula – possibly orders of magnitude slower. So it’s best to avoid using a procedure unless you have no choice.

Suppose you want to create a custom function that returns true or false depending on whether a value is a valid month. For example 2, 7, “feb” and “December” would be valid months, while 18, “red” or “zog” would not be valid.

The first step is to write a procedure that analyzes the parameter and determines whether the month is valid or not. This code must culminate in using the functionvalue statement to return the result.

    let aMonth = parameter(1)
    let monthNumber = val(aMonth)
    if monthNumber=0
        monthNumber =
            arraysearch("jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec",
            lower(aMonth)[1,3],1,",")
    endif
    functionvalue between(monthNumber,1,12)

I’ll put this procedure in my Custom Statements library, so it will automatically load into memory when Panorama launches. However, this procedure is NOT a custom statement, so I don’t give it an all upper case name. (The name could be anything, it doesn’t have to end in Function, it just shouldn’t be all upper case.)

Now I’m ready to use this in a formula.

    call("_Jim Rea's Custom Statements","ValidateMonthFunction","April") ☞ TRUE
    call("_Jim Rea's Custom Statements","ValidateMonthFunction",17) ☞ FALSE
    call("_Jim Rea's Custom Statements","ValidateMonthFunction",2) ☞ TRUE

To make this more convenient, I’ll define it as a custom function in the .InitializeFunction procedure in the custom library database:

    registercustomfunction "VALIDMONTH(",1,
        {call("_Jim Rea's Custom Statements","ValidateMonthFunction",•1)}

Now this function can be used in any formula:

    validmonth("April") ☞ TRUE
    validmonth(17) ☞ FALSE
    validmonth(2) ☞ TRUE

One problem with my .InitializeFunction is that the name of the library database is hard coded into the code. With a slight adjustment this dependency can be removed – this version of the code works the same but will work even if the name of the library database changes, or if this is moved to a different library database.

    let library = info("proceduredatabase")
    registercustomfunction "VALIDMONTH(",1,
        {call(}+quoted(library)+{,"ValidateMonthFunction",•1)}

Here is the complete code needed to implement this custom function.

Note: In this particular case it would be possible to write a formula that validates a month without having to use procedure code. The formula would be a bit complicated and tricky to figure out, but it would be possible and would be much faster, especially if you planned to use this function with the select or formulafill statements. I’ll leave figuring out the exact formula required as an exercize for the reader.

See Also

- call( -- allows a procedure to be called as a subroutine within a formula and return a result.
- callwithin( -- allows a "mini-procedure" to be called as a subroutine within a formula and return a result.
- Custom Statements -- creating your own custom statements that can be used in your code.
- customstatementdatabase( -- returns the name of the library database that defines a custom statement.
- execute( -- allows a formula to execute a sequence of statements and return a result.
- functionvalue -- returns a value calculated by a procedure using the call(, callwithin( or execute( functions.
- info("customfunctions") -- returns a list of all available custom functions.
- info("customstatements") -- returns a list of all available custom statements.
- loadcustomfunctions -- reloads all ProVUE defined custom functions.

History

Version | Status | Notes
10.0 | Updated | Carried over from Panorama 6, but now allows the same function to be defined multiple times with different numbers of parameters, and the formula must be quoted.