I have struct Metadata
which is quite big in size. Ideally I want to have only single instance of it in memory. I have another struct Polynomials
that requires
access to Metadata
for performing operations in its methods. I understand that I can store smart pointer to Metadata
inside Polynomial
using Arc
. But I have decided
against it, since applications that library targets are multithreaded and Polynomials are created and dropped many times. I also don't want to force overhead of
Arc
to library users.
So I could think of following three options to implement what I want. First is quite straightforward. I simply pass Metadata
as reference to each Polynomial
operation. For example,
struct Metadata {}
struct Polynomial {
data: Vec<u64>,
}
impl Polynomial {
fn add(&self, b: &Polynomial, metadata: &Metadata) -> Polynomial {
// Checks metadata is correct for polynomials before doing the operation, only in debug mode
todo!()
}
}
Problem with this apporach is that I have to always rememeber to pass correct metadata with each function call. An alternate to this is creating a Evaluator
struct like following:
struct Evaluator<'a> {
metadata: &'a Metadata,
}
impl Evaluator<'_> {
fn add(&self, a: &Polynomial, b: &Polynomial, metadata: &Metadata) -> Polynomial {
// Checks metadata is correct for polynomials before doing the operation, only in debug mode
todo!()
}
}
The benefit of using Evaluator
is that I will not have to rememeber to pass correct metadata with each function call, instead correct polynomials. This seems to be a better option
if I have to perform a bunch of polynomial operations specific to a given metadata within a given scope. So far this seems to be the case.
Another approach can be creating PolynomialWithMetadataRef
struct like
struct PolynomialWithMetadataRef<'a> {
data: &'a [u64],
metadata: &'a Metadata,
}
impl PolynomialWithMetadataRef<'_> {
fn add(&self, a: &PolynomialWithMetadataRef, metadata: &Metadata) -> Polynomial {
todo!()
}
}
The nice thing about 3rd approach is that it avoids having to check that metadata is correct for polynomials (only in debug mode) at every method call. Instead we can perform the check when
creating PolynomialWithMetadataRef
from Polynomial
, like
impl Polynomial {
pub fn view<'a>(&'a self, metadata: &'a Metadata) -> PolynomialWithMetadataRef {
// Checks metadata is correct for polynomials, only in debug mode
PolynomialWithMetadataRef {
data: &self.data,
metadata,
}
}
}
With this I can also implement std::ops
trait for PolynomialWithMetadataRef
. But again, I will have to rememeber to pass correct metadata at the time of calling Polynomial::view
.
I plan to stick to having asserts in debug mode only. So as far as I understand, all three will have equivalent performance at runtime. So the question is of only what's
easier for me to handle as the codebase grows.
I am curious whether I have missed anything? Open to suggestions to other patterns as well