I understood that part of the goals of Commons RDF is to provide not just org.w3c.dom-like implementation pluggability, but also interoperability.
It means that applications can mix and match RDF Commons instances from different libraries and join them in a single Graph (if they so like), without having to do any explicit conversions. So a library that say does image analysis can provide a Graph of Triple instances with metadata (e.g. generated with Sesame or Commons RDF Simple), and the application is free to just to add those directly to a Jena-based Graph instance and do some OWL inferencing with Jena's APIs. No serialization or explicit conversion is needed, and implicit conversion might or might not happen in the implementation. The Simple Graph does the conversion now: https://github.com/apache/incubator-commonsrdf/blob/master/simple/src/main/java/org/apache/commons/rdf/simple/GraphImpl.java#L74 .. the reasoning being that then the new Graph would not be dependent on open connections or transactions in the incoming instances. But there is no requirement for such a conversion to be done in our API docs. Thus a implA.Triple.getSubject() is free to return a implB.IRI - which could be tricky with your approach. On 14 July 2015 at 15:47, Alexandre Bertails <[email protected]> wrote: > [snip] > >>> No. It is very much like the `java.util.Collections.sort` method [1]: >>> it was written/compiled only once. >> >> >> That wasn't quite what I had in mind - binary compatibility allows moving >> objects between systems without copy if the receiving system does not >> wish/need to copy. It's a choice of the receiver. > > Oh, I thought "binary compatibility" just meant "no need to recompile" ;-) > >> Injecting RDF<...> makes an algorithm independent of one base provider. > > Exactly. (but not sure about the use of the term "injecting" here) > >> If you want to work with two base providers, for example, code that does >> system A to system B copy, you need RDF<A> and RDF<B> injected. This is >> exactly your first point - common choices enables neutrality of containers. >> The "simple" commonsRDF, working on the interface objects can work with a >> mixture of origins. > > Why would you want to work with two implementations at the same time? > Unless you explicitly want to go from one to another, of course. > >> RDF<A> and RDF<B> are not compatible in the sense that a triple from one >> can't be put into a graph of the other; it needs unpacking from RDF<A> to >> the fundamentals (string for IRI etc) and repacking as RDF<B>. > > Yes, it is the same thing than working with > `com.hp.hpl.jena.graph.Triple` and `org.openrdf.model.Statement`. > > Does one need to go from one to another? > >> (You can at least have a single converter lib, > > Among other things, I want to avoid converters. > >> because there are fundamental >> base units (Strings in various uses) but (Java-ism) the converter needs to >> be called, there being no implicit definitions.) > > Sorry I didn't get that. > >> Both styles have their uses. > > Yes, I know. > > banana-rdf has been providing an RDF abstraction for 4 years now, that > now accommodates for 5 implementations (Jena, Sesame, banana-plantain, > jsonld.js, N3.js) and we never felt the need for interfaces à la Java. > > So I am genuinely trying to understand where and why people need those > interfaces, and how they will use them _in practice_ wrt the > underlying implementations. > > Alexandre > >> >> Andy >> >> >> >>> >>> [1] >>> http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#sort-java.util.List-java.util.Comparator- >>> >>> In practice, three things would likely happen: >>> >>> 1. Jena, Sesame, banana-rdf, etc. would have to provide an >>> implementation of `RDF<...>` so that their implementations can be used >>> with any system accepting using the `RDF<...>` approach >>> 2. libraries that want to be abstract in the underlying RDF system >>> they work with (e.g. a Turtle parser/writer, a SPARQL client, etc.) >>> would have to be parametrized by `Graph`, `Triple`, etc. >>> 3. but libraries from 2. would likely offer modules of their APIs >>> already instantiated for the main RDF libraries (Jena, Sesame, etc.) >>> so that they are ready to use with such systems >>> >>> Best, >>> Alexandre >>> >>>> >>>> Andy >>>> >>>> >>>> On 07/05/15 20:16, Alexandre Bertails wrote: >>>>> >>>>> >>>>> On Thu, May 7, 2015 at 11:18 AM, Alexandre Bertails >>>>> <[email protected]> wrote: >>>>>> >>>>>> >>>>>> Hi Stian, >>>>>> >>>>>> tldr: [1] https://gist.github.com/betehess/8983dbff2c3e89f9dadb >>>>> >>>>> >>>>> >>>>> I updated the gist with three examples at the end: CommonsRDF, >>>>> StringRDF, PlantainRDF. Note how the types do not have to relate to >>>>> the current interfaces, but they can if you want/need to. >>>>> >>>>> Alexandre >>>>> >>>>>> >>>>>> On Wed, May 6, 2015 at 4:24 PM, Stian Soiland-Reyes <[email protected]> >>>>>> wrote: >>>>>>> >>>>>>> >>>>>>> On 6 May 2015 at 05:58, Alexandre Bertails <[email protected]> wrote: >>>>>>>> >>>>>>>> >>>>>>>> I haven't followed the development in a long time, especially after >>>>>>>> the move to Apache. I just looked at it and I had a few remarks and >>>>>>>> questions. >>>>>>> >>>>>>> >>>>>>> >>>>>>> Hi, thanks for joining us! Let's hope we haven't scared you away while >>>>>>> we try to get our first Apache release out and have the odd Blank Node >>>>>>> fight.. :) >>>>>> >>>>>> >>>>>> >>>>>> Wait, there was a Blank Node fight and I wasn't part of it? >>>>>> >>>>>>>> Just some background for those who don't already know me: I am part >>>>>>>> of >>>>>>>> the banana-rdf project [1]. The main approach there relies on >>>>>>>> defining >>>>>>>> RDF and its operations as a typeclass [2]. In that world, Jena and >>>>>>>> Sesame are just two instances of that typeclass (see for example [4] >>>>>>>> and [5]). So there is no wrapper involved. Still, commons-rdf is >>>>>>>> really a good step in the right direction as we could obsolete a lot >>>>>>>> of stuff. >>>>>>> >>>>>>> >>>>>>> >>>>>>> I can definitely see that banana-rdf is relevant to commons-rdf - and >>>>>>> also any requirements you might have to commons-rdf coming from Scala >>>>>>> is interesting. >>>>>> >>>>>> >>>>>> >>>>>> That's cool if if we can accommodate commons-rdf to make it really >>>>>> useful from Scala-land. I think it is possible [1]. >>>>>> >>>>>>>> Right now, there is no support in commons-rdf for immutable >>>>>>>> operations. `Graph`s are mutable by default. Is there any plan to >>>>>>>> make >>>>>>>> an API for immutable graphs? Graphs in banana-rdf are immutable by >>>>>>>> default, and they are persistent in Plantain. We could always wrap an >>>>>>>> immutable graph in a structure with a `var`, but, well, there are >>>>>>>> better ways to do that. >>>>>>> >>>>>>> >>>>>>> >>>>>>> There has been suggestions along those lines. It is not a requirement >>>>>>> of Graph now to allow .add() etc. - but there is no method to ask if a >>>>>>> graph is mutable or not. >>>>>>> >>>>>>> In the user guide >>>>>>> http://commonsrdf.incubator.apache.org/userguide.html#Adding_triples >>>>>>> we therefore say: >>>>>>> >>>>>>>> Note: Some Graph implementations are immutable, in which case the >>>>>>>> below >>>>>>>> may throw an UnsupportedOperationException. >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> We could probably add this to the Javadoc of the mutability methods of >>>>>>> Graph with an explicit @throws. >>>>>>> >>>>>>> I raised this as https://issues.apache.org/jira/browse/COMMONSRDF-23 >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> https://issues.apache.org/jira/browse/COMMONSRDF-7 discusses how we >>>>>>> should define immutability on the non-Graph objects. >>>>>>> >>>>>>> >>>>>>> In Clerezza's Commons RDF Core (which is somewhat aligned with Commons >>>>>>> RDF) there is an additional marker interface ImmutableGraph -- perhaps >>>>>>> something along those lines would work here? >>>>>> >>>>>> >>>>>> >>>>>> If it doesn't exist in the type (i.e. statically), it's basically lost >>>>>> knowledge. @throws, being silent or explicit, is pretty much useless >>>>>> because now client code needs to check for this possibility. It would >>>>>> be a slightly better to make it an interface. And we could could have >>>>>> another interface for immutable graphs, where `add(Triple)` would >>>>>> return another graph. >>>>>> >>>>>> See how it can be done in [1]. >>>>>> >>>>>>> >>>>>>> >>>>>>> https://github.com/apache/clerezza-rdf-core/blob/master/api/src/main/java/org/apache/clerezza/commons/rdf/ImmutableGraph.java >>>>>>> >>>>>>> >>>>>>>> `RDFTermFactory` is stateful just to accommodate >>>>>>>> `createBlankNode(String)`. It's stateless otherwise. This is really >>>>>>>> an >>>>>>>> issue for banana-rdf as everything is defined as pure function (the >>>>>>>> output only depends on the input). >>>>>>> >>>>>>> >>>>>>> >>>>>>> It does not need to be stateful. >>>>>>> >>>>>>> In simple we implemented this using a final UUID "salt" that is >>>>>>> created per instance of the factory. Do you consider this state? >>>>>>> >>>>>>> >>>>>>> >>>>>>> https://github.com/apache/incubator-commonsrdf/blob/master/simple/src/main/java/org/apache/commons/rdf/simple/SimpleRDFTermFactory.java#L51 >>>>>>> >>>>>>> >>>>>>> This is then used by >>>>>>> >>>>>>> >>>>>>> https://github.com/apache/incubator-commonsrdf/blob/master/simple/src/main/java/org/apache/commons/rdf/simple/BlankNodeImpl.java#L41 >>>>>>> as part of a hashing to generate the new uniqueReference(). Thus a >>>>>>> second call on the same factory with the same name will be hashed with >>>>>>> the same salt, and produce the same uniqueReference(), which makes the >>>>>>> second BlankNode equal to the first. >>>>>>> >>>>>>> >>>>>>> But you can achieve the contract by other non-stateful means, for >>>>>>> instance a random UUID that is static final (and hence no state at all >>>>>>> per factory instance), and you can create a uniqueReference() by >>>>>>> concatenating that UUID with the System.identityHashCode() of the >>>>>>> factory and concatenate the provided name. >>>>>> >>>>>> >>>>>> >>>>>> This approach only gives you the illusion that there is no state, but >>>>>> there *is* one (e.g. with UUID, and the atomic counter). Because of >>>>>> its current contract, `createBlankNode(String)` cannot be >>>>>> referentially transparent, and this is an issue if one wants to take a >>>>>> functional approach. >>>>>> >>>>>>> Also you are not required to implement createBlankNode(String) - you >>>>>>> can simply throw UnsupportedOperationException and only support >>>>>>> createBlankNode(). >>>>>> >>>>>> >>>>>> >>>>>> What is the point of doing/allowing that? As a users or implementors, >>>>>> I want to know that I can rely on a method/function that is >>>>>> accessible. And that is also why I dislike the default implementation >>>>>> approach taken in the current draft. >>>>>> >>>>>>> This should probably be noted in the (yet so far just imagined) >>>>>>> Implementors Guide on the Commons RDF website. >>>>>>> >>>>>>> https://issues.apache.org/jira/browse/COMMONSRDF-24 >>>>>>> >>>>>>> >>>>>>>> Is `createBlankNode(String)` really needed? The internal map for >>>>>>>> bnodes could be maintained _outside_ of the factory. Or at least, we >>>>>>>> could pass it as an argument instead: `createBlankNode(Map<String, >>>>>>>> BlankNode>, String)`. >>>>>>> >>>>>>> >>>>>>> >>>>>>> We did discuss if it was needed - there are arguments against it due >>>>>>> to blank nodes "existing only as themselves" and therefore a single >>>>>>> JVM object per BlankNode should be enough - however having the >>>>>>> flexibility for say a streaming RDF parser to create identitcal blank >>>>>>> node instances without keeping lots of object references felt like a >>>>>>> compelling argument to support this through the factory - with for >>>>>>> example the hashing method above this means no state is required. >>>>>> >>>>>> >>>>>> >>>>>> This is making *very structuring assumption*. Being referentially >>>>>> transparent makes none, and will always accommodate all cases. That >>>>>> being said, I understand the constraints. >>>>>> >>>>>> Note: [1] does not attempt to fix that issue. >>>>>> >>>>>>>> # wrapped values >>>>>>>> >>>>>>>> There are a lot of unnecessary objects because of the class >>>>>>>> hierarchy. >>>>>>>> In banana-rdf, we can say that RDFTerm is a plain `String` while >>>>>>>> being >>>>>>>> 100% type-safe. That's already what's happening for the N3.js >>>>>>>> implementation. And in Plantain, Literals are just `java.lang.Object` >>>>>>>> [6] so that we can directly have String, Int, etc. >>>>>>> >>>>>>> >>>>>>> >>>>>>> Well, this is tricky in Java where you can't force a new interface >>>>>>> onto an existing type. >>>>>>> >>>>>>> How can you have a String as an RDFTerm? Because you use the >>>>>>> ntriplestring? This would require new "instanceOf"-like methods to >>>>>>> check what the string really is - and would require various classes >>>>>>> like LiteralInspector to dissect the string. This sounds to me like >>>>>>> building a different API.. >>>>>> >>>>>> >>>>>> >>>>>> The point is to abstract things away. By choosing to use actual >>>>>> interfaces, you are forcing everything to be under a class hierarchy >>>>>> for no good reason. I do not find the motivation for this approach in >>>>>> the documentation. >>>>>> >>>>>> Please see [1] for a discussion on that subject. >>>>>> >>>>>>> While I can see this can be a valid way to model RDF in a non-OO way, >>>>>>> I think that would be difficult to align with Commons RDF as a >>>>>>> Java-focused API, where most Java programmers would expect type >>>>>>> hierarchies represented as regular Java class hierarchies. >>>>>> >>>>>> >>>>>> >>>>>> I am not convinced. The RDF model is simple enough that another >>>>>> approach is possible [1]. >>>>>> >>>>>>>> That means that there is no way currently to provide a >>>>>>>> `RDFTermFactory` for Plantain. The only alternatives I see right now >>>>>>>> are: >>>>>>> >>>>>>> >>>>>>> >>>>>>> What is the challenge of returning wrappers? I think this is the >>>>>>> approach that Jena is also considering. >>>>>>> >>>>>>> Presumably if you are providing an RDFTermFactory then that is to >>>>>>> allow JVM code that expects any Commons RDF code to create Plantain >>>>>>> objects for RDF. They would expect to be able to do say: >>>>>>> >>>>>>> factory.createLiteral("Fred").getDatatype() >>>>>>> >>>>>>> which would not work on a returned String >>>>>> >>>>>> >>>>>> >>>>>> You can (of course) do things like that in Scala, in a very typesafe >>>>>> way, i.e. it's not monkey patching. And this is happening in >>>>>> banana-rdf :-) >>>>>> >>>>>> That would be totally compatible with [1]. >>>>>> >>>>>>>> # getTriples vs iterate >>>>>>>> >>>>>>>> Not a big deal but I believe the naming could be improved. When I >>>>>>>> read >>>>>>>> getTriples, I expect to have all the triples in my hand, but this is >>>>>>>> not quite what Streams are about. On the other hand, when I read >>>>>>>> iterate, I kinda expect the opposite. Of course the types clarify >>>>>>>> everything but I believe it'd be easier to use getTriplesAsStream and >>>>>>>> getTriplesAsIterable. >>>>>>> >>>>>>> >>>>>>> >>>>>>> I might disagree - but I think this is a valuable to discuss. >>>>>> >>>>>> >>>>>> >>>>>> As I said, not a big deal. Types are what really matters in the end. >>>>>> >>>>>>> I have taken the liberty to report this in your name as: >>>>>>> https://issues.apache.org/jira/browse/COMMONSRDF-22 >>>>>>> >>>>>>> so we can discuss this further in the email thread that should have >>>>>>> triggered. >>>>>>> >>>>>>> >>>>>>> >>>>>>> Thanks for all your valuable suggestions - please do keep in touch and >>>>>>> let us know if you have a go at aligning banana-rdf with the upcoming >>>>>>> 0.1.0 release, further feedback on documentation, and anything else! >>>>>> >>>>>> >>>>>> >>>>>> I believe that the the main issue is that the current approach is both >>>>>> for library users _and_ library authors, but there really are two >>>>>> different targets here. I agree that the class for the RDF model can >>>>>> provide a common framework for many Java people. But libraries relying >>>>>> on commons-rdf should not be tied to the classes. >>>>>> >>>>>> Please have a look at this gist to see what I mean and tell me what >>>>>> you think [1]. >>>>>> >>>>>> Alexandre >>>>>> >>>>>> [1] https://gist.github.com/betehess/8983dbff2c3e89f9dadb >>>>>> >>>>>>> >>>>>>> -- >>>>>>> Stian Soiland-Reyes >>>>>>> Apache Taverna (incubating), Apache Commons RDF (incubating) >>>>>>> http://orcid.org/0000-0001-9842-9718 >>>> >>>> >>>> >> -- Stian Soiland-Reyes Apache Taverna (incubating), Apache Commons RDF (incubating) http://orcid.org/0000-0001-9842-9718
