I am currently working on creating my own persistent array in java, which uses a binary search tree to store an collection of values.
I want to add a map method that takes a Function
as an argument to generate a new array. I don't want to evaluate the functions unless the particular value is requested. This is pretty simple to do as lambdas are lazy evaluated. However, I also only want a function to be evaluated only once, even if the result is requested multiple times.
I could create a node that stores the supplier and updates the result when evaluated:
class Node<T> {
private T value;
private Supplier<T> supplier;
public T get() {
if (null != value)
return value;
value = supplier.get();
return value;
}
}
...where supplier
is derived from a Function
being applied to a value in an older version of the persisted array.
However, this is no longer a functional approach, and has the potential to cause errors in a multi-threaded system*. It also doesn't yield an advantage in the case where supplier returns a null value**.
Another approach would be return an instance of Node
on a get call:
class Node<T> {
private final Optional<T> value;
private final Supplier<T> supplier;
Node(Supplier<T> supplier, T value) {
this.supplier = supplier;
this.value = Optional.ofNullable(value);
}
public Tuple<Node<T>, T> get() {
if (null != value)
return new Tuple<>(this, value.orElse(null));
T result = supplier.get();
Node<T> newNode = new Node<>(null, result);
return new Tuple<>(newNode, result);
}
}
I like this approach for staying functional; but it would require a lot of overhead in all the parent nodes going up the tree for just a get call. And it would require cumbersome unboxing in the using application's code.
Does anyone have another approach they can think of to make this work the way I'm asking? Thanks.
*This could be solved using locking mechanisms, but adds a layer of complexity I'm hoping to avoid.
**I've thought about making value
an Optional<T>
, where null
means hasn't been evaluate, and Optional.empty()
as has been evaluated and returns a null. However, this works around my issue, rather than solving it.
For anyone not familiar with a persisted array, it's a data structure that creates a new instance of itself whenever an update is performed. This allows it to be purely immutable. Using a binary tree (or more common 32-bit tree) method allows the updates to reduce duplicating data, both in speed and memory.
EDIT:
The code for the collection can be found on github. For description of use, you can look in the test folder.