Tracking computation dependencies and lazily recomputing while caching results

L

levy

Hi,

This is a piece of code I would like to share. It's not a universal
hammer but I believe it's a good one even though it could be improved
in many ways. (Not tested too hard)

The code is quite simple I believe and if you understand AspectJ and
the main idea then it's easy to use.

The idea is that functions marked with @Computed annotation will not
be recomputed unless another function's (also marked with @Computed)
value has been changed meanwhile on which the requested function
depends. Depends means that it used that function last time it was
computed. Computations can be replaced on a per instance basis and
dependencies are kept also per instance.

There are several things one could use this stuff. One thing is
replacing the listener stuff found all over the place in Java.

The fill source code (approximately 250 lines) can be downloaded
from:

http://files-upload.com/files/464504/computed.zip

import computed.Computed;
import computed.ComputedObject;
import computed.IComputation;


public class ComputedTest extends ComputedObject {
@Computed public int getA() {
return 1;
}
@Computed public void setA(int a) {}

@Computed public int getB() {
return getA() + 1;
}
@Computed public void setB(int b) {}
@Computed public void setB(IComputation<Integer> computation) {}

@Computed public int getC() {
return getA() + getB();
}
@Computed public void setC(Object value) {}

public static void main(String[] args) {
new ComputedTest().test();
}

/**
* Did you suffer writing various cache mechanisms all over the place
in your programs?
* This is a not new but interesting solution by
(e-mail address removed).
*
* What does the following piece of code print?
* Or more precisely: how many time does it print "Recomputing"?
*
* Notes: This stuff could be enhanced in many ways:
* - storing ComputedState objects in separate member variables
* - handling thread safety
* - forward/backward chaining (instead of having this always lazy
computation)
* - less memory consuming for per class computed functions
* - etc.
*/
public void test() {
print();
print();
setA(2);
print();
setB(1);
print();
setC(new IComputation<Integer>() {
public Integer compute() {
return getA() + 3 * getB();
}
});
print();
}

private void print() {
System.out.println(getA());
System.out.println(getB());
System.out.println(getC());
System.out.println();
}
}


The result is:
=========

Recomputing: A
1
Recomputing: B
2
Recomputing: C
3

1
2
3

Recomputing: A
2
Recomputing: B
3
Recomputing: C
5

2
Recomputing: B
1
Recomputing: C
3

2
1
Recomputing: C
5
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top