Volatile functions

7.98K viewsScripting
0

I’m writing a plugin function which is volatile – repeated calls to it return varying values – but I’m having trouble making this work.

As an example, consider the built-in rand() function. This returns a different value after each call (i.e. it has type “”IO double”” rather than “”double””, to borrow the Haskell convention).

Now if I write a Groovy function:

double groovy_rand() {
return new Random().nextDouble();
}

Then this behaves as I would expect, in that a 2D matrix with e.g. A1 = groovy_rand() produces a list of random numbers across category B.

But if I write a plugin function:

public class PluginRand extends AbstractQFunction {

public QValueList evaluate(QValueList[] args) {
return QValueFactory.createSingletonValueList(new Random().nextDouble());
}

public QType[] argumentTypes() {
return new QType[] {};
}

public QType returnType() {
return QType.cValueType;
}
}

then doing the same A1 = pluginrand() just produces a list across B of the same *first* random number.

How can I obtain the Groovy-like volatile behaviour from a plugin?

Many thanks.

0

Whoops. Sorry about that. I overlooked that fact that QAPI functions are inherently cached. Unfortunately, I [i:2ezu17og]can’t[/i:2ezu17og] offer any elegant way around that. However, here is the least offensive hack we can think of:

You can write your plug-in function so that it takes a dummy argument, and then pass (built-in) [font=””Courier New””]rand()[/font] as the argument value when you call the function from a formula. Although it’s not very pretty, this kills two birds with one stone: first, it forces evaluation of the plug-in function because it recognizes that its input is [font=””Courier New””]rand()[/font] which is subject to change. Second, it forces caching of the plug-in function to be turned off because [font=””Courier New””]rand()[/font] itself is not cached and therefore the engine will not cache any function whose value depends on an evaluation of [font=””Courier New””]rand()[/font]. This isn’t pretty, but I think it will get the job done. Here is what the function code would look like:

[code:2ezu17og]
public class PluginRand extends AbstractQFunction
{
@Override
public QValueList evaluate(QValueList[] args)
{
return QValueFactory.createSingletonValueList(Math.random());
}

@Override
public QType[] argumentTypes()
{
return new QType[]{QType.cValueType};
}

@Override
public QType returnType()
{
return QType.cValueType;
}
}
[/code:2ezu17og]

Incidentally, you could also apply this same approach to a scripted function, which is [i:2ezu17og]already[/i:2ezu17og] non-cached but which would present the same problem as before with non-calculation due to lack of dependencies. In the case of a scripted function, the dummy argument with a [font=””Courier New””]rand()[/font] value gets you past the issue of non-auto-calculation, and you get the non-cached behavior for free. It’s also simpler to create than the plug-in version, although I understand that you may have your reasons for wanting or needing to go the plug-in route.

Hope this helps.
-Ben

You are viewing 1 out of 8 answers, click here to view all answers.

Latest Questions

Qloud Losing Formatting 4 Answers | 0 Votes
Meditation on timelines 3 Answers | 0 Votes