Coming from C++, I’m used to writing something like
class workspace {
public:
int* frontBuffer;
int* backBuffer;
workspace() { ... allocate front and back buffers here ...}
void swap_buffers() {
int* tempPtr = frontBuffer;
frontBuffer = backBuffer;
backBuffer = tempPtr;
}
};
With the idea that operations on the buffers can read from frontBuffer
, write to backBuffer
and then swap the buffers before returning, leaving their result in the frontBuffer for the next operation.
What is the Julian way of performing this operation? Should I use a mutable struct? My suspicion is I should not, and instead have something like
struct Workspace
frontBuffer::Array{Int64}
backBuffer::Array{Int64}
end
function Workspace(s::Int64)
return Workspace(zeros(s), zeros(s))
end
function swapbuffers(w::Workspace)
return Workspace(w.backBuffer, w.frontBuffer)
end
This requires that each operation return the updated workspace and means that if I do
julia> w = Workspace(5)
Workspace([0, 0, 0, 0, 0], [0, 0, 0, 0, 0])
julia> w.frontBuffer[1] = 1
1
julia> w
Workspace([1, 0, 0, 0, 0], [0, 0, 0, 0, 0])
julia> r = swapbuffers(w)
Workspace([0, 0, 0, 0, 0], [1, 0, 0, 0, 0])
julia> w
Workspace([1, 0, 0, 0, 0], [0, 0, 0, 0, 0])
Of course, while I’ve allocated a new Workspace
there’s been no additional allocations of the underlying arrays, as
julia> w.backBuffer === r.frontBuffer
true
Again, coming from C++, I’m used to passing a reference to my workspace as an argument to an operation, and so there would be no new allocation of a Workspace at each swap, and the buffer swap would be visible to anyone holding a reference to the underlying workspace (i.e., w.backBuffer === r.backBuffer
would be true).
I understand that there’s tradeoffs between these approaches, and I’m not asking about which is better, or how to make my Julia code like my C++ code. I admit I’m a little suspicious of allocating a new Workspace
at each swap when I expect to do millions of these as part of a big computation, but I’m open to the idea that this is basically irrelevant due to good optimization and garbage collection. I’m mostly just wondering whether the Julia approach I’ve described above is the “right way” to do this kind of thing in Julia, or if there’s some other idiom I should be looking at.