Shared Functions#
Using the feature “shared functions”, a GTlab Module can use functions of other modules without the need to compile against the other module. Shared functions have the multiple benefits:
Use of functions provided by other modules
Use of shared functions from python scripting
They are provided during runtime by the core framework.
There is no module-module dependency during the compile time.
The basic principle is shown the following image:
Writing shared functions#
The class GtModuleInterface has been extended by the method GtModuleInterface::sharedFunctions(),
where a module can return its shared functions. But how to do it? What is a gt::SharedFunction?
The easiest way to write a shared function is to wrap an existing (non-shared) function. Lets assume we have the following function to compute a sum:
// In ModuleA
static int my_test_sum(int a, int b)
{
return a + b;
}
This function can now be converted into a shared function and registered as follows
QList<gt::SharedFunction>
ModuleA::sharedFunctions() const
{
gt::SharedFunction sharedFunction = gt::interface::makeSharedFunction(
"my_test_sum", // The name the function will be registered at the framework
my_test_sum, // the function "pointer"
"Returns the square of x.\nSignature: " + // provide an optional description
gt::interface::getFunctionSignature(my_test_sum) // the signature can be deduced automatically
);
return {sharedFunction};
}
How does it work? gt::interface::makeSharedFunction() wraps the upper function into a new function with the following shared function signature
QVariantList function(const QVariantList& args)
This implies, that all arguments of the function to be wrapped need to be convertible into QVariant.
makeSharedFunction checks at runtime, that the number of arguments passed to the function is correct, and that all argument types are as expected.
makeSharedFunction performs some magic behind the scenes, but it can be summarized as
It converts a regular function (or a function object or a lambda) into a shared function
It checks the arguments passed by the user, i.e. checks the correct argument number and types
It adds an description if none was provided. It will deduce the function signature automatically (using
gt::interface::getFunctionSignature())Sometimes, the automatically generated conversion code might not work as expected. In this case, the shared function can also be defined using the upper function signature as follows.
Creating a shared function - the advanced way#
Sometimes, the automatic of a regular function is not desired and the developer wants to have precise control.
This can be achieved by implementing a shared function manually.
Simply said, the user needs to provide a function with the shared function signature, i.e. QVariantList function(const QVariantList& args).
Here’s an example of the upper sum function wrapped manually into a shared function.
QVariantList mySharedSum(const QVariantList& args)
{
if (args.size() != 2)
{
// error, number of arguments incorrect
return {};
}
bool ok = true;
// get argument a
double a = args[0].toDouble(&ok);
if (!ok)
{
// error: first argument is not a double value
return {};
}
// get argument b
double b = args[1].toDouble(&ok);
if (!ok)
{
// error: second argument is not a double value
return {};
}
double sum = my_test_sum(a + b);
return QVariantList({sum});
}
If this function signature is used, no automatic conversion will be done and the function is responsible for checking all arguments.
Then, the function can be registered as above, i.e.
QList<gt::SharedFunction>
ModuleA::sharedFunctions() const
{
gt::SharedFunction sharedFunction = gt::interface::makeSharedFunction(
"mySharedSum", // The name the function will be registered at the framework
mySharedSum, // the function "pointer"
"Returns the square of x.\nSignature int my_test_sum(int a, int b)"
);
return {sharedFunction};
}
Using shared functions#
// query the function from gtlab
auto function = gt::interface::getSharedFunction("<GT_MODULE_ID>", "my_test_sum");
// check, that the function exists
if (!function.isNull())
{
// call the function and compute the sum
auto returnValues = function({1, 2});
// make sure the return type is as expected
assert(returnValues.size() == 1);
// result is 3.0
double result = returnValues[0].toDouble();
}