Getting Caught by Java’s References
I was working on a problem today with the alerts in my web system and I was having a really hard time getting a handle on the problem. Basically, I had an object that did n-point moving average calculations on a data stream and I wanted to use that to feed a data aggregator where all the data from the n-point smoothing would be summed up across the firm to get "totals" that could be used in the alert expressions.
I had built the n-point moving average class to expose a 'previous' and 'current' array of data so that it looked just like the incoming data - an Object[]. I did this by having two such Object[] instance variables - one for the 'previous' and the other for the 'current'. When a new value came in, I'd copy the contents of the 'current' to the 'previous', add in the new, subtract out the old, and save the new as the old for this contributor. It worked like a dream.
What I was seeing was that the data going into the firm aggregator was showing the same values in the 'previous' and 'current' data arrays! This simply could not be. In the aggregator, I was saving the data from the n-point smoother, by contributor, similarly to the n-point smoother itself, so that we can add in the new, remove the old, save the new as the old, and get a nice running aggregation.
But it wasn't working that way.
And it took me several hours to figure it out. But I did.
References. Java references are somewhat deceptive. In C++ I'd know what I was doing more clearly because I'd have to be more careful with the heap variables. Stack variables were easy as they went out of scope and were gone. Copies were cheap, relatively.
But in Java, everything is a reference. So when I was getting the 'previous' and 'current' data from the n-point smoother, I was really getting the reference to the arrays I was using as storage. When I then got new data into the n-point smoother, I updated that data, and naturally, the data in the aggregator would change as well. After all, it's the same reference.
Ah!
So what I had to do was to make copies of the data coming out of the n-point smoother and into the aggregator. These, then formed snapshots of the data coming out and were exactly what I needed in the data flow.
In general, there's a lot to like about Java. Garbage Collection is one of them. But there are times that the visual warning of pointers in C++ makes it much easier to see issues - or potential issues. I've been coding for a while, and this guy flew right past me for several hours. That's tough to find.