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

Hi Apollo,

This is a consequence of Quantrix’s optimized calculation process. Quantrix will only recalculate a cell’s value if it detects a change to another cell on which that value depends. When you use your function to calculate a cell, that cell’s value isn’t derived from any other cells, so Quantrix decides that it can’t possibly need to be re-calculated because it has no dependencies. Since the cell isn’t being calculated, your function never gets evaluated and it doesn’t get the chance to offer up a new value.

Luckily, you can write your function so that it saves a reference to its owning formula, then listens for calculation events on the model and forces the formula to recalculate itself if the model calculates. Try this:

[code:165h4yu0]
public class PluginRand extends AbstractQFunction
{
private QFormulaContext formula;
private QuantrixEventListener calculationListener = new QuantrixEventListener()
{
@Override
public void notify(QuantrixEvent event)
{
if (event.getType() == QuantrixEventType.cModelWillCalculate)
formula.forceRecalc();
}
};

@Override
public void registerFormulaContext(QFormulaContext context)
{
formula = context;
Model model = formula.getModel();
if (model != null)
model.addListener(calculationListener);
}

@Override
public void unregisterFormulaContext(QFormulaContext context)
{
Model model = formula.getModel();
if (model != null)
model.removeListener(calculationListener);
formula = null;
}

@Override
public QValueList evaluate(QValueList[] args)
{
return QValueFactory.createSingletonValueList(Math.random());
}

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

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

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