Passing Automation Script Functions as Parameters

January 21, 2025

Introduction

Abstraction and reusability are key principles in software development that offer significant benefits for managing complexity and readability of your code. They promote separation of concerns and modularity, allowing implementation details to be isolated. This enables other developers to reuse code without needing to delve into the specifics of an implementation. It can also help reduce "copypasta", where you copy and paste blocks of code, sometimes with minor modifications, to multiple places, making it extremely difficult to maintain.

A technique to encourage abstraction and reusability is using higher-order functions and passing one function as parameters to another function. In both JavaScript and Python, functions are first-class objects and can therefore be assigned to variables and passed as parameters to other functions. This capability is also available in Automation Scripts for both languages.

Higher-order functions can be seen in many built-in functions such as forEach(), map(), filter(), and reduce(). These extremely useful functions illustrate the utility of this approach and are the foundation for the functional programming paradigm. Passing functions as parameters can also be used for event handling and callbacks. For example, you might want to allow a script to post progress updates without the script needing to understand the implementation of how the update is handled.

Creating a Function

The example below shows how to define two functions, add and subtract, that take two parameters and return the result of adding or subtracting the two parameters. The apply function takes a function as a parameter and calls it with the two values passed to it. The apply function is then called with the add and subtract functions as parameters and the result is logged to the Maximo script logger.

The example is simple to illustrate the concept. In practice, you would likely have more complex functions and use cases.

JavaScript

var add = function addition(a, b) {
return a + b;
}
var subtract = function subtraction(a, b) {
return a - b;
}
function apply(value1, value2, operation){
return operation(value1, value2);
}
// The answer is 3
service.log_info("Result of adding 1 and 2 is " + apply(1, 2, add));
// The answer is 1
service.log_info("Result of subtracting 2 and 1 is " + apply(2, 1, subtract));

Python

The same example can also be implemented in Python. Note however that in Python the function must first be defined and then assigned to a variable, unlike JavaScript where the function can be assigned directly to a variable.

# define the add function
def addition(a,b):
return a + b
add = addition
# define the subtract function
def subtraction(a,b):
return a - b
subtract = subtraction
def apply(value1, value2, operation):
return operation(value1, value2)
# The answer is 3
service.log_error("Result of adding 1 and 2 is " + str(apply( 1, 2, add)))
# The answer is 1
service.log_error("Result of subtracting 2 and 1 is " + str(apply(2, 1, subtract)))

Passing Functions as Parameters in Automation Scripts

Another very useful application of passing functions as parameters is when invoking one Automation Script from another. We covered invoking scripts in a previous post here. In this post we build on that to add a function to the global context and pass it as a parameter to a script named SHARPTREE.LIB. The SHARPTREE.LIB script can then call the add and subtract functions that were passed as parameters directly, as if those functions were defined within the script itself.

JavaScript

// import the Java HashMap
HashMap = Java.type('java.util.HashMap');
// define the add function
var add = function addition(a, b) {
return a + b;
}
// define the subtract function
var subtract = function subtraction(a, b) {
return a - b;
}
// create a new HashMap to use as the execution context
var library = new HashMap();
// add the standard service to the global context
library.put('service', service);
// add the add function to the global context
library.put('add', add);
// add the subtract function to the global context
library.put('subtract', subtract);
// invoke the library with the context
service.invokeScript("SHARPTREE.LIB", library);

Python

# import the Java HashMap
from java.util import HashMap
# define the add function
def addition(a, b):
return a + b
add = addition
# define the subtract function
def subtraction(a, b):
return a - b
subtract = subtraction
# create a new HashMap to use as the execution context
library = HashMap()
# add the standard service to the global context
library.put('service', service)
# add the add function to the global context
library.put('add', add)
# add the subtract function to the global context
library.put('subtract', subtract)
# invoke the library with the context
service.invokeScript("SHARPTREE.LIB", library)

An example implementation of the SHARPTREE.LIB script may look like the following.

Note that the the implementation for SHARPTREE.LIB checks that the add and subtract functions are available in the context before calling them. It is good practice to validate that the expected global variables are available before using them. This is especially important when invoking scripts from multiple launch points or contexts. For example the mbo variable may be available when the script is launched from a object launch point, but not when launched from a direct REST API call.

JavaScript

In JavaScript using the built in typeof function to check if the add variable is defined in the context and returns undefined if it is not.

// call the main function to ensure a single entry point to the script
main();
// the main function provides an entry point to the script so there is a single point of entry and exit, exiting the function also exits the script.
function main(){
if(typeof add !== 'undefined'){
service.log_info("Result of adding 1 and 2 is " + add(1, 2));
} else {
service.log_error("The add function not found in context");
}
}

Python

In Python using the built in globals function returns an array of global variables, which we can use the in operator to check if the add function is defined in the context.

def main():
if 'add' in globals():
service.log_info("Result of adding 1 and 2 is " + str(add(1, 2)))
else:
service.log_error("The add function not found in context")
# call the main function to ensure a single entry point to the script
main()

Final Thoughts

In this post, we demonstrate how to define a function and pass it as a parameter to another function in both JavaScript and Python. We also show how to pass functions as part of the global context when invoking other Automation Scripts. This technique can be used to create reusable and modular code that is easier to maintain and understand. It can also be used to invoke one Automation Script from another and pass functions as parameters to the invoked script. This can be useful when you want to provide a function to another script without needing to define it in the script itself.

If you have any questions, comments or have suggestions for topics you would like to see us cover, please reach out to us at [email protected]

In the time it took you to read this blog post...

You could have deployed Opqo, our game-changing mobile solution for Maximo.

Opqo is simple to acquire, simple to deploy and simple to use, with clear transparent monthly pricing that is flexible to your usage.