Tasks
A task is defined to be something that calculates the value of an attribute. Examples of tasks include the lambda passed when creating an attribute and the transformation function between two attributes.
What distinguishes tasks from a simple function is the fact that they must ultimately produce an AttributeData
instance. The problem is that it would be highly inconvenient for you, the end user of this library, to always create an instance to return since most of the time you'll need to return a Loaded
instance in transformation functions. For this reason the return value of tasks is T
, not AttributeData<T>
: it is implied that when the task returns a value, the status is loaded.
How to return something different then? For this purpose all tasks accept as their receiver a WorkContext
instance, from which we can create and throw a particular exception that conveys this meaning. For more information about receiver of functions see the Kotlin™ documentation.
This examples of transformations of an attribute will clarify:
import com.femastudios.dataflow.async.*
import com.femastudios.dataflow.async.util.*
import java.util.Random
fun main() {
val a = attributeOf(lazy = false) { //The receiver of this lambda is a WorkContext instance, so `this` is now a WorkContext
println("this = " + (this is WorkContext)) //Verify that `this` is a `WorkContext` instance
val ret = Random().nextInt(100)
if(ret < 50) {
throwError("Nasty error!") //<-- called on the WorkContext receiver
} else {
ret
}
}
Thread.sleep(100) //Allow time for the attribute to compute
println(a.value) //Will be either LOADED or ERROR, depending on random result
}
Attribute<Integer> a = Attribute.of(workContext -> {
//Since Java doesn't support the change of `this` in lambdas the WorkContext is passed as its first parameter
final int ret = new Random().nextInt(100);
if(ret < 50) {
//Since Java cannot understand that a method can always throw an exception
//we must use a different function that creates the exception and throw it ourselves
throw workContext.errorException("Nasty error!");
} else {
return ret;
}
});
Thread.sleep(1000); //Allow time for the attribute to compute
System.out.println(a.getValue()); //Will be either LOADED or ERROR, depending on random result
In this example we declared a new attribute with a task: this task generates a random number and returns it if it is less than 50
, otherwise throws an exception generated with the passed WorkContext
. There are also more functions that allow you to pass an instance of NotLoaded
.
Note that you must explicitly throw errors, and that any uncaught exception in tasks will propagate its way up to caller, similarly to what happens on fields.