Creating fields

The first thing to consider when creating a field is whether we want to be able to change its value. If the answer is yes, then we'll need a MutableField.

Mutable fields

link

Most of the time, we will want to be able to set values in our fields manually. For this purpose we need a MutableField instance.

import com.femastudios.dataflow.util.* fun main() { val f /* : MutableField<String> */ = mutableFieldOf("hello world") f.value = "foo bar" //Allowed println(f.value) }
MutableField<String> f = MutableField.of("hello world"); f.setValue("foo bar"); //Allowed

If we want to change the value based on the previous one, we can do something like this:

import com.femastudios.dataflow.util.* fun main() { val f = mutableFieldOf(5) f.setValue { it * 10 } //Will multiply 5 by 10, setting the value to 50 println(f.value) }
MutableField<Integer> f = MutableField.of(5); f.setValue(old -> old * 10); //Will multiply 5 by 10, setting the value to 50

The given lambda will atomically change the value of the field: the value won't be changed until the computation is complete, and multiple calls to the function will be enqueued and be executed one at a time.

Constant fields

link

Sometimes the need may arise to create a field with a constant value (i.e. we cannot set the value).

import com.femastudios.dataflow.util.* fun main() { val f /* : Field<String> */ = fieldOf("hello world") println(f.value) //OK //Cannot call f.value = "foo bar" }
Field<String> f = Field.of("hello world"); //Cannot call f.setValue("foo bar");

Restrictions on field values

link

Please note that there are a couple restrictions on things that should be put as field values:

  • Only immutable data: fields cannot know when the internal state of the value they hold changes, thus being unable to call the necessary callbacks in that case. For this reason, you should never put mutable data in fields; this also makes the fields thread-safe.
  • equals() implemented correctly: two equal objects should never have some accessible property whose value is different. This because when a value is trying to be set in a field, it is first checked for equality with the old one; if true is returned the value is not set and listeners are not called. This is necessary to improve efficiency as the number of fields in the program explodes.

Obliviously fields cannot check if the values satisfy this restrictions, neither at compile-time nor at run-time, so it is the programmer's duty to avoid this situations.

Utility functions

link

In order to make field creation easier and more idiomatic, several utility functions are available to create both constant and mutable fields.

Fields of constants

link

These functions allow to create a Field whose value is a well-known constant (either null, true or false).

import com.femastudios.dataflow.util.* fun main() { fieldOfNull() //yields Field<Nothing> containing null fieldOfTrue() //yields Field<Boolean> containing true fieldOfFalse() //yields Field<Boolean> containing false }
FieldUtils.fieldOfNull(); //yields Field containing null Field.ofNull(); //same as above FieldUtils.fieldOfTrue(); //yields Field<Boolean> containing true FieldUtils.fieldOfFalse(); //yields Field<Boolean> containing false

Collection fields

link

We can also put immutable collections in fields, and Dataflow provides a few utility functions for this purpose. More information about collections in fields can be found here.

List fields

link

A way to create fields or mutable fields that contain an immutable List.

import com.femastudios.dataflow.util.* fun main() { //yields Field<List<String>> containing the immutable list ["a, "b", "c"] listFieldOf("a", "b", "c") //yields Field<List<Int?>> containing an immutable empty list listFieldOf<Int?>() //yields MutableField<List<Float>> containing the immutable list [1, 2, 3] mutableListFieldOf(1f, 2f, 3f) }
//yields Field<List<String>> containing the immutable list ["a, "b", "c"] FieldUtils.listFieldOf("a", "b", "c") //yields Field<List<Integer>> containing an immutable empty list FieldUtils.<Integer>listFieldOf() //yields MutableField<List<Float>> containing the immutable list [1, 2, 3] FieldUtils.mutableListFieldOf(1f, 2f, 3f)

Set fields

link

Similarly to lists, these functions create fields or mutable fields that contain an immutable Set.

import com.femastudios.dataflow.util.* fun main() { //yields Field<Set<String>> containing the immutable set {"a, "b", "c"} setFieldOf("a", "b", "c") //yields Field<Set<Int?>> containing an immutable empty set setFieldOf<Int?>() //yields MutableField<Set<Float>> containing the immutable set {1, 2, 3} mutableSetFieldOf(1f, 2f, 3f) }
//yields Field<Set<String>> containing the immutable set {"a, "b", "c"} FieldUtils.setFieldOf("a", "b", "c") //yields Field<Set<Integer>> containing an immutable empty list FieldUtils.<Integer>setFieldOf() //yields MutableField<Set<Float>> containing the immutable set {1, 2, 3} FieldUtils.mutableSetFieldOf(1f, 2f, 3f)

Map fields

link

Lastly, we can also create fields or mutable fields that contain an immutable Map.

import com.femastudios.dataflow.util.* fun main() { //yields Field<Map<Int, Char>> containing the immutable map {1: 'a', 2: 'b'} mapFieldOf(1 to 'a', 2 to 'b') //yields Field<Map<Int, Boolean?>> containing an immutable empty map mapFieldOf<Int, Boolean?>() //yields MutableField<Map<Char, Double>> containing the immutable map {'a': 1.5, 'b': 5.4} mutableSetFieldOf('a' to 1.5, 'b' to 5.4) }
//yields Field<Map<Int, Character>> containing the immutable map {1: 'a', 2: 'b'} FieldUtils.mapFieldOf(new Pair(1, 'a'), new Pair(2, 'b')) //yields Field<Map<Int, Boolean>> containing an immutable empty map FieldUtils.<Int, Boolean>mapFieldOf() //yields MutableField<Map<Character, Double>> containing the immutable map {'a': 1.5, 'b': 5.4} FieldUtils.mutableSetFieldOf(new Pair('a', 1.5), new Pair('b', 5.4))