Closed KonradHoeffner closed 1 year ago
This is indeed a limitation of the Graph
trait, and I do not plan to change it in the near future (this would break too many things).
What prevents you from using a fully polymorphic function instead?
fn foo<G: Graph>(g: G) {}
This works perfectly, thanks!
I did not know this is possible, as I started with fn foo(g : Graph)
as I would in for example Java and then I just followed the directions of the borrow checker starting with using "dyn".
Unfortunately, I am again at a point where not being able to use it as a Trait object makes my code very convoluted. Depending on the runtime parameters (e.g. extension of the file to be loaded) of my program, different types of Graph are used and the resulting graph is stored in an enum:
pub enum GraphEnum {
FastGraph(FastGraph),
#[cfg(feature = "hdt")]
HdtGraph(HdtGraph),
}
Now I have to create a helper method for every method that uses a graph, for example:
pub fn serialize_rdfxml(iri: Iri<&str>) -> Result<String, Box<dyn Error>> {
match graph() {
GraphEnum::FastGraph(g) => serialize_rdfxml_generic(g, iri),
#[cfg(feature = "hdt")]
GraphEnum::HdtGraph(g) => serialize_rdfxml_generic(g, iri),
}
}
pub fn serialize_rdfxml_generic<G: Graph>(g: &G, iri: Iri<&str>) -> Result<String, Box<dyn Error>> {
Ok(RdfXmlSerializer::new_stringifier().serialize_triples(g.triples_matching(Some(deskolemize(&iri)), Any, Any))?.to_string())
}
The code is now littered with those helper methods, and adding anything has become cumbersome. I have tried to write an "Impl" block for GraphEnum with a triples_matching method, because that is the only one I am using, but that did not seem work because the GTripleSource trait is very complex as well. Is there anything else I can do to simplify this?
P.S.: After several hours, I figured out the way given below, in case someone else needs this functionality. I think the amount of complicated traits like these make using Sophia a bit cumbersome sometimes, but I guess that is a different issue so I will close this issue again.
#[allow(clippy::large_enum_variant)]
pub enum GraphEnum {
FastGraph(FastGraph),
#[cfg(feature = "hdt")]
HdtGraph(HdtGraph),
}
impl GraphEnum {
fn triples_matching<'s, S, P, O>(&'s self, sm: S, pm: P, om: O) -> Box<dyn Iterator<Item = Result<[SimpleTerm<'static>; 3], Infallible>> + '_>
where
S: TermMatcher + 's,
P: TermMatcher + 's,
O: TermMatcher + 's,
{
match self {
// both graphs produce infallible results
GraphEnum::FastGraph(g) => Box::new(g.triples_matching(sm, pm, om).flatten().map(|triple| Ok(triple.map(SimpleTerm::from_term)))),
#[cfg(feature = "hdt")]
GraphEnum::HdtGraph(g) => Box::new(g.triples_matching(sm, pm, om).flatten().map(|triple| Ok(triple.map(SimpleTerm::from_term)))),
}
}
}
I want my application to work with both FastGraph and LightGraph, so that users can choose which suits their usecase best, but I cannot use Graph parameters because it is not "object safe" according to the compiler.
Is there some way around this? Are all those generic parameters needed?