FYI http://bertails.org/2015/06/17/an-rdf-abstraction-for-the-jvm/
Sorry for the long delay. Best, Alexandre On Sun, May 31, 2015 at 4:01 AM, Andy Seaborne <[email protected]> wrote: > On 14/05/15 15:58, Alexandre Bertails wrote: >> >> Thank you Andy, those are the questions that must be answered before >> significant code is being written. >> >> On Thu, May 14, 2015 at 3:37 AM, Andy Seaborne <[email protected]> wrote: >>> >>> Alexandre's proposal would the project in a different direction. >> >> >> Code-wise, this is true, as a lot of existing interfaces would become >> obsolete, so I understand why this is frustrating. But I believe that >> the proposal is better aligned with a larger goal of interop. > > > Could you expand on that because it looks like a different interoperability, > one where code (algorithms) can be easily ported between systems but it's by > recompiling with different choices for RDF<....> whereas factory injection > means the same binary code can work over different systems. > >>> The goals for me have been switching underlying systems (being able to >>> produce portable algorithms that can be applied without recompiling the >>> world (ServiceLoader to bind to implementation) and of interoperation >>> across >>> systems. >> >> >> The pure Scala parts of banana-rdf cannot interoperate using the >> current framework.And in a larger sense, the current Commons RDF does >> >> not accommodate a lot of more general use cases (see the 7 use cases I >> listed in a previous email). >> >> For me, the current approach was driven by the existing Jena and >> Sesame, and that's already progress. The real question is: are there >> other goals we want to address? If the answer is "no" then it's fine >> as well, but we need to know it, and the reason. >> >>> Being able to switch implementation choices by choosing different types >>> is >>> interesting but different. It would be nice to see both existing though >>> combining into one "thing" seems to overload the focus. >> >> >> As I showed in the code, the two can be combined. It is important that >> people here take the time to understand the big picture and how the >> pieces translate. >> >>> Do we want to "host" the generics approach as well (whether used for the >>> system abstraction work or to go along side)? >> >> >> Very good question. I believe library authors will want their work to >> be usable to more people, not just Jena and Sesame. So if the >> "generics approach" doesn't happen in Commons RDF, then people with >> interest in better interop will have an incentive to maintain the code >> outside of the project. Especially if they know that there is an easy >> way to communicate with the interfaces from Commons RDF, with no >> runtime cost. >> >>> The other difference is a theory-practice one. The current work is not >>> reworking the general style of Jena, Sesame, >> >> >> The "general style of Jena, Sesame" was not driven by interop. So >> people had different problems to solve and OOP was perfectly fine in >> that case. >> >>> common progamming ways of doing things. >> >> >> I simply don't know what "common programming". In some cases, I have >> heard people using that term to dismiss other forms of programming. >> >> What I know is that the approach in my proposal is not new at all, and >> has existed in Java-land for a long time. Just look at >> java.util.Comparator vs java.util.Comparable, that is the very same >> discussion, just with a few more types. >> >> First we need to agree (or not) on the goals, then we find a technical >> solution. And again, "not interested" is a perfectly fine answer. >> >>> I'd like to see the generics approach validated by external usage, >>> not for its technical design, but addressing whether it creates >>> sufficient >>> demand and sufficient acceptance. >> >> >> As for the design itself, you can consider it's been incubated in >> banana-rdf for four years. >> >> Alexandre >> >> [1] http://en.wikipedia.org/wiki/Type_class >> >>> >>> Andy >>> >>> >>> On 13/05/15 07:32, Alexandre Bertails wrote: >>>> >>>> >>>> Sergio, >>>> >>>> The approach is different. A "patch" against the current codebase >>>> would remove most of the interfaces. >>>> >>>> I suggest that you try to understand what's going on in the code, >>>> after you read the other messages in that thread. >>>> >>>> Then if there is interest, I can work on a real patch. >>>> >>>> Alexandre >>>> >>>> On Tue, May 12, 2015 at 11:25 PM, Sergio Fernández <[email protected]> >>>> wrote: >>>>> >>>>> >>>>> I'd say if you'd be much more valuable to see a patch about your >>>>> proposal >>>>> that a quick hack from scratch. >>>>> You can fork our github mirror: >>>>> https://github.com/apache/incubator-commonsrdf >>>>> >>>>> On Wed, May 13, 2015 at 8:01 AM, Alexandre Bertails >>>>> <[email protected]> >>>>> wrote: >>>>> >>>>>> On Tue, May 12, 2015 at 10:21 PM, Sergio Fernández <[email protected]> >>>>>> wrote: >>>>>>> >>>>>>> >>>>>>> Alexandre, >>>>>>> >>>>>>> git clone >>>>>>> >>>>>>> https://[email protected]/repos/asf/incubator-commonsrdf.git >>>>>>> commonsrdf >>>>>>> >>>>>>> The incubator prefix in the name is to keep clear we're still not >>>>>>> fully >>>>>>> endorsed by the ASF. I know it's a bit inconvenient, specially in >>>>>>> later >>>>>>> phases when we'd get rid of that, but is part of the incubator >>>>>>> process. >>>>>> >>>>>> >>>>>> >>>>>> Thanks! >>>>>> >>>>>> I have hacked something quick-and-dirty and made it available at [1]. >>>>>> >>>>>> Quick overview of the sub-packages: >>>>>> * `api`: just the RDF interface, and the interfaces from commons-rdf >>>>>> are moved under `concrete` >>>>>> * `concrete`: shows how to implement RDF with the interfaces approach >>>>>> * `simple`: a complete example adapted from commons-rdf >>>>>> * `classless`: a (almost) complete example which does not rely on >>>>>> shared interfaces >>>>>> * `turtle`: a example of how to rely on the RDF interface >>>>>> >>>>>> Feel free to ask questions. >>>>>> >>>>>> Alexandre >>>>>> >>>>>> [1] https://github.com/betehess/free-rdf >>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> On Tue, May 12, 2015 at 6:45 PM, Alexandre Bertails < >>>>>> >>>>>> >>>>>> [email protected]> >>>>>>> >>>>>>> >>>>>>> wrote: >>>>>>> >>>>>>>> Stian, >>>>>>>> >>>>>>>> It sounds stupid but I do not understand where the code actually >>>>>>>> lives. >>>>>>>> >>>>>>>> I have tried >>>>>>>> >>>>>>>> ``` >>>>>>>> git clone https://git-wip-us.apache.org/repos/asf/commons-rdf.git >>>>>>>> ``` >>>>>>>> >>>>>>>> and >>>>>>>> >>>>>>>> ``` >>>>>>>> git clone git://git.apache.org/commons-rdf.git >>>>>>>> ``` >>>>>>>> >>>>>>>> but both tell me that I "appear to have cloned an empty repository." >>>>>>>> The github repo is empty as well. >>>>>>>> >>>>>>>> Can somebody please give me the right URI? Sorry if I miss that in >>>>>>>> the >>>>>>>> documentation, but I did look there and couldn't find the answer :-/ >>>>>>>> >>>>>>>> Alexandre >>>>>>>> >>>>>>>> >>>>>>>> On Tue, May 12, 2015 at 8:41 AM, Alexandre Bertails >>>>>>>> <[email protected]> wrote: >>>>>>>>> >>>>>>>>> >>>>>>>>> Hi Stian, >>>>>>>>> >>>>>>>>> On Tue, May 12, 2015 at 7:35 AM, Stian Soiland-Reyes < >>>>>> >>>>>> >>>>>> [email protected]> >>>>>>>> >>>>>>>> >>>>>>>> wrote: >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> On 12 May 2015 at 06:20, Alexandre Bertails >>>>>>>>>> <[email protected]> >>>>>>>> >>>>>>>> >>>>>>>> wrote: >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> I actually didn't understand that we were discussing a >>>>>>>>>>> `createBlankNode(UUID)`. I think we just need to be able to >>>>>>>>>>> create >>>>>>>>>>> a >>>>>>>>>>> fresh blank node. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> That is what createBlankNode() does. >>>>>>>>>> >>>>>>>>>> Is your proposal to simply remove createBlankNode(String)? >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> As it is today, yes. Because its contract implies some kind of >>>>>>>>> shared >>>>>>>> >>>>>>>> >>>>>>>> state. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> But we have identified a use-case where the blank node can remember >>>>>>>>> in >>>>>>>>> which context it was generated e.g. the blank node label at parsing >>>>>>>>> time. >>>>>>>>> >>>>>>>>>>> Requiring the caller to provide an explicit UUID >>>>>>>>>>> means that the freshness is happening *outside* of the factory, >>>>>>>>>>> so >>>>>>>>>>> I >>>>>>>>>>> don't see the point. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Well, you wanted to pass in the uniqueness..? You can pass it as a >>>>>>>>>> String (as of today), or, loosely suggested, by restricting this >>>>>>>>>> to >>>>>>>>>> a >>>>>>>>>> UUID (which would require clients to think about this very common >>>>>>>>>> mapping/hashing). >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> No, the uniqueness must happen in `createBlankNode()`. That's how >>>>>>>>> you >>>>>>>>> can enforce the invariant. >>>>>>>>> >>>>>>>>>>> Also, it's forcing the strategy (UUID), which >>>>>>>>>>> might not be the best one for everybody, e.g. UUID is known to be >>>>>>>>>>> slow, at least for some notion of slow, and that could become a >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> There are several variations of UUID, you are free to use a >>>>>>>>>> timestamp one that is rather fast to make, SHA-1 is not known to >>>>>>>>>> be >>>>>> >>>>>> >>>>>> slow >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> either, so version 5 hashes are also fast. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> commons-rdf should leave that choice open. >>>>>>>>> >>>>>>>>>> But we agreed that UUID only might be a bit strict for some >>>>>>>> >>>>>>>> >>>>>>>> implementations, >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> which meant that uniqueReference() can return any unique string.. >>>>>>>>>> so >>>>>> >>>>>> >>>>>> if >>>>>>>> >>>>>>>> >>>>>>>> it >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> considered >>>>>>>>>> >>>>>>>>>> app=97975c0b-62c1-42c9-b2a9-e87948e4a46e ip=84.92.48.26 >>>>>>>>>> uid=1000 >>>>>>>>>> pid=292 name=fred >>>>>>>>>> >>>>>>>>>> to be a unique string (with hard-coded >>>>>>>> >>>>>>>> >>>>>>>> 97975c0b-62c1-42c9-b2a9-e87948e4a46e >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> in case someone else comes up with a similar scheme), >>>>>>>>>> and didn't mind leaking all that vulnerability data, then that >>>>>>>>>> would >>>>>> >>>>>> >>>>>> be >>>>>>>> >>>>>>>> >>>>>>>> a >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> compliant uniqueReference(). >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> I am not arguing for stateless vs stateful. I am just pointing at >>>>>> >>>>>> >>>>>> some >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> design issues which do not allow it. Currently, there is just no >>>>>>>>>>> way >>>>>>>>>>> for an immutable implementation to be used with such a factory. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> I am not sure what is the extent of "immutable" here. I'll assume >>>>>>>>>> it >>>>>>>>>> just means that all fields are final, not >>>>>>>>>> that the object is not allowed to have any field at all. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Being final just means that the reference won't be updated, but its >>>>>>>>> state can still be updated. So to be immutable, you also need the >>>>>>>>> final references to be immutable themselves. >>>>>>>>> >>>>>>>>>> You are free to >>>>>>>>>> create RDFTermFactory as you please, so you can simply do it like >>>>>> >>>>>> >>>>>> this: >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> public class ImmutableRDFTermFactory implements RDFTermFactory { >>>>>>>>>> private final UUID salt; >>>>>>>>>> public ImmutableRDFTermFactory(UUID salt) { >>>>>>>>>> this.salt = salt; >>>>>>>>>> } >>>>>>>>>> public BlankNode createBlankNode() { >>>>>>>>>> return new BlankNodeImpl(salt); >>>>>>>>>> } >>>>>>>>>> public BlankNode createBlankNode(String name) { >>>>>>>>>> return new BlankNodeImpl(salt, name); >>>>>>>>>> } >>>>>>>>>> / .. >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> public class BlankNodeImpl implements BlankNode { >>>>>>>>>> >>>>>>>>>> private static void unique(UUID salt) { >>>>>>>>>> Instant now = Clock.systemUTC().instant(); >>>>>>>>>> return salt.toString() + System.identityHashCode(this) + >>>>>>>>>> now.getEpochSecond() + now.getNano() + >>>>>> >>>>>> >>>>>> Thread.currentThread().getId(); >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> private final String uniqueReference; >>>>>>>>>> public BlankNodeImpl(UUID salt, String name) { >>>>>>>>>> uniqueReference = salt.toString() + name; >>>>>>>>>> } >>>>>>>>>> public BlankNodeImpl(UUID salt) { >>>>>>>>>> uniqueReference = salt.toString() + >>>>>> >>>>>> >>>>>> System.identityHashCode(this) >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> + new Date().; >>>>>>>>>> } >>>>>>>>>> } >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> This is not immutable because of the shared state. >>>>>>>>> >>>>>>>>>> Here there is no hidden mutability in AtomicLong or within >>>>>>>>>> java.util.UUID's SecureRandom implementation's internal state. I >>>>>> >>>>>> >>>>>> guess >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> you would not be happy with those either? >>>>>>>>>> >>>>>>>>>> The clock is obviously mutable - but as a device rather than a >>>>>>>>>> memory >>>>>>>> >>>>>>>> >>>>>>>> state. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> There is no "but" in the immutable world :-) >>>>>>>>> >>>>>>>>>>> Having `add` returning a `Graph` does not mean that `Graph` is >>>>>>>>>>> immutable. It just means that it *enables* `Graph` to be >>>>>>>>>>> immutable. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> There is nothing stopping an immutable Graph from having an >>>>>> >>>>>> >>>>>> additional >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> method that does this. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Now I am the one asking for some code, because I don't see how >>>>>>>>> that'd >>>>>>>> >>>>>>>> >>>>>>>> work :-p >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> As I said in a previous, you can wrap an immutable Graph in a new >>>>>>>>> object with a mutable reference to that graph, but, well, please >>>>>>>>> let's >>>>>>>>> avoid having to do that... >>>>>>>>> >>>>>>>>>> For some methods, like builders, returning the mutated state is >>>>>>>>>> good >>>>>>>> >>>>>>>> >>>>>>>> practice. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> When using persistent datastructures, a builder is not an option. >>>>>>>>> >>>>>>>>> There are areas where you do not want to go back to the mutable >>>>>>>>> version. It happens everywhere in banana-rdf e.g. the RDF DSL, the >>>>>>>>> RDF/class mapper, etc. Just because we need to compose graphs >>>>>>>>> without >>>>>>>>> risking to modify an existing one. >>>>>>>>> >>>>>>>>>> It has been suggested earlier to return bool on add() to be >>>>>> >>>>>> >>>>>> compatible >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> with Collection, but we were not all too happy with that as it >>>>>>>>>> might >>>>>>>>>> be difficult/expensive to know if the graph was actually mutated >>>>>>>>>> or >>>>>>>>>> not (e.g. you insert the same triple twice, but the store doesn't >>>>>>>>>> bother checking if the triple existed). >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Returning `bool` has very little value from my perspective. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> See >>>>>>>>>> https://issues.apache.org/jira/browse/COMMONSRDF-17 >>>>>>>>>> https://github.com/commons-rdf/commons-rdf/issues/27 >>>>>>>>>> https://github.com/commons-rdf/commons-rdf/issues/46 >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> So your suggestion is for the mutability methods to return the >>>>>> >>>>>> >>>>>> mutated >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> object (which may or may not be the original instance). I think >>>>>>>>>> this >>>>>>>>>> could be an interesting take for discussions - could you raise >>>>>>>>>> this >>>>>> >>>>>> >>>>>> as >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> a separate Jira issue? >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Yes, that'd be the way to go. >>>>>>>>> >>>>>>>>> But I would prefer to see how much interest in the general approach >>>>>>>>> there is before opening too many issues. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> Well, Scala is just a language. Immutability and referential >>>>>>>>>>> transparency, are just principles, but they are becoming more and >>>>>> >>>>>> >>>>>> more >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> important in many areas (Spark, concurrency, etc.). >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Agreed, also for distributed areas like Hadoop. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> There are *many* areas where accommodating immutable graphs has >>>>>>>>> become >>>>>>>>> important. >>>>>>>>> >>>>>>>>>>> There is no shortcut at all. The RDF model only resolves around >>>>>>>>>>> some >>>>>>>>>>> types (Graph, Triple, RDFTerm, BlankNodeOrIRI, IRI, BlankNode, >>>>>>>>>>> Literal) which can be left abstract, as opposed to being concrete >>>>>> >>>>>> >>>>>> when >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> using Java's interfaces. (it's "concrete" in the sense it's using >>>>>>>>>>> nominal subtyping) >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Well, I still don't see how a java.util.String will work with Java >>>>>>>>>> code that expects to be able to call .getIRIString(). Would >>>>>>>>>> Scala generate proxies on the fly? Or would it need to call >>>>>>>>>> .getIRIString() "elsewhere"? >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> It's like monkey patching, just in a controlled and type safe way: >>>>>>>>> >>>>>>>>> ``` >>>>>>>>> val rdf: RDF = ??? >>>>>>>>> >>>>>>>>> implicit class IRIWrapper(val iri: IRI) extends AnyVal { >>>>>>>>> def getIRIString(): String = rdf.getIRIString(iri) >>>>>>>>> } >>>>>>>>> >>>>>>>>> val iri: IRI = rdf.createIRI("http://example.com") >>>>>>>>> assert(rdf.getIRIString(iri) == iri.getIRIString()) >>>>>>>>> ``` >>>>>>>>> >>>>>>>>> Scala would find that there is an implicit conversion from IRI to >>>>>>>>> something with a getIRIString method, and would do the `new >>>>>>>>> IRIWrapper`. But because this is also a value class (`AnyVal`) then >>>>>>>>> no >>>>>>>>> object would actually be allocated. It's basically free. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> If you look at what I did, you have a *direct* translation of the >>>>>>>>>>> existing interfaces+methods+factory into simple functions. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Yes, but done in Scala. Can I see a suggestion to the changes of >>>>>>>>>> the >>>>>>>>>> current CommonsRDF Java interfaces - in Java? >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> No the gist is in Java and uses the same function names. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> * the Java interfaces becomes abstract types >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Java interfaces are abstract types. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Java interfaces provide some abstraction (subtype polymorphism). >>>>>>>>> Types >>>>>>>>> are compile-time information. At runtime, you see a reified version >>>>>>>>> of >>>>>>>>> the type, as an interface or as a class (and module type erasure). >>>>>>>>> That is why Java interfaces are not really abstract types. >>>>>>>>> >>>>>>>>>> Do you mean generics? >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Yes. >>>>>>>>> >>>>>>>>>> Generics of which class/interface? >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Of the RDF interface in the gist [1]. >>>>>>>>> >>>>>>>>> [1] >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> https://gist.github.com/betehess/8983dbff2c3e89f9dadb#file-rdf-java-L10 >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>>> Not all Commons RDF clients are expected to interface via >>>>>>>>>> RDFTermFactory. In fact many use-cases don't need it at all. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> * the methods on those interfaces become functions on the >>>>>>>>>>> abstract >>>>>>>> >>>>>>>> >>>>>>>> types >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> * the methods on the interfaces in the factory becomes simple >>>>>>>>>>> functions on the abstract types >>>>>>>>>>> * operating on a node happens with a visitor (as in visitor >>>>>>>>>>> pattern) >>>>>>>>>>> implemented as the `visit` function, taking 3 functions for the 3 >>>>>>>>>>> possible cases (I believe the current API asks for checking the >>>>>> >>>>>> >>>>>> class >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> at runtime...) >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> This is too much at an abstract (!) level for me to visualize as >>>>>> >>>>>> >>>>>> we're >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> clashing programming languages here.. could you detail how this >>>>>>>>>> would >>>>>>>>>> look in a set of *.java files? Feel free to raise it as a pull >>>>>> >>>>>> >>>>>> request >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> or similar, even if it's very draft-like. :) >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> I can transform my gist into a real project. I will need a couple >>>>>>>>> of >>>>>>>>> days to find the time. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> Now, let's say I am implementing a Turtle parser. The only thing >>>>>>>>>>> I >>>>>>>>>>> care about is how I can [use case 1] create/inject elements into >>>>>> >>>>>> >>>>>> some >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> existing RDF model. If I am writing a Turtle serializer, I only >>>>>>>>>>> care >>>>>>>>>>> about how to [use case 2] traverse that type hierarchy. In none >>>>>>>>>>> of >>>>>>>>>>> those cases did I care about having the types defined in the >>>>>>>>>>> class/interface hierarchy and I want anybody to use their own RDF >>>>>>>>>>> model. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Yes. And with the current take of Commons RDF, the Turtle parser >>>>>>>>>> is >>>>>> >>>>>> >>>>>> free >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> to return its own instances of RDFTerm interfaces, which any >>>>>>>>>> Commons >>>>>> >>>>>> >>>>>> RDF >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> consuming client will be able to use as-is, e.g. pass to their own >>>>>>>>>> Graph implementation. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> And here is what people will end up doing: >>>>>>>>> >>>>>>>>> ``` >>>>>>>>> Graph graph = JenaTurtleParser.parse(input); >>>>>>>>> com.hp.hpl.jena.graph.Graph jenaGraph = >>>>>>>> >>>>>>>> >>>>>>>> (com.hp.hpl.jena.graph.Graph)graph; >>>>>>>>> >>>>>>>>> >>>>>>>>> ``` >>>>>>>>> >>>>>>>>> Many will not want to see the common interface but the actual >>>>>>>>> subtype. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> class TurtleParser<Graph, Triple, RDFTerm, BlankNodeOrIRI, IRI, >>>>>>>>>>> BlankNode, Literal> { >>>>>>>>>>> RDF<Graph, Triple, RDFTerm, BlankNodeOrIRI, IRI, BlankNode, >>>>>> >>>>>> >>>>>> Literal> >>>>>>>> >>>>>>>> >>>>>>>> rdf >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> Graph parse(String input) { /* can call >>>>>>>>>>> rdf.createLiteral("foo"), >>>>>> >>>>>> >>>>>> or >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> anything in rdf.* */ } >>>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> I think the <brackets> speak for themselves here :-( >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> "Small" remark: I still don't think that >>>>>>>>>>> `createBlankNode(String)` >>>>>>>>>>> belongs to the RDF model. I would really like to see a use case >>>>>>>>>>> that >>>>>>>>>>> shows why it has to be present. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> This is a valid point of view which I think you should raise >>>>>>>>>> as a new Jira issue. We did argue that it is not part of the >>>>>>>>>> RDF model, but it is still a practically very useful feature, >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> "useful feature" --> this is where I would like to see a motivating >>>>>>>>> use case. Then we can discus how useful a feature it is, or how >>>>>>>>> much >>>>>>>>> of a problem it can be. >>>>>>>>> >>>>>>>>>> however it has generated many contention points in the past >>>>>>>>>> as it touches on state and uniqueness. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> See also this discussion about the need (or not) for >>>>>>>>>> exposing .uniqueReference() >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> I am all in favor or `uniqueReference`. That is how the invariants >>>>>>>>> on >>>>>>>>> the blank node can be achieved. >>>>>>>>> >>>>>>>>>> >>>>>>>>>> https://issues.apache.org/jira/browse/COMMONSRDF-13 >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> Finally, I will admit that writing all those types parameters can >>>>>> >>>>>> >>>>>> be a >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> bit cumbersome, even if it happens only in a very few places (as >>>>>>>>>>> a >>>>>>>>>>> user: only once when you build what you need e.g. a Turtle >>>>>>>>>>> parser). >>>>>>>>>>> But please let's not sacrifice correctness and functionality to >>>>>>>>>>> (a >>>>>>>>>>> little) convenience... >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Well, if those would be exposed to any client of the Commons RDF >>>>>>>>>> API >>>>>> >>>>>> >>>>>> I >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> fear we would see very little uptake.. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> How so? >>>>>>>>> >>>>>>>>>> If they are hidden inside some upper/inner interface that is not >>>>>>>>>> exposed otherwise, it is not so bad. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> Yes, you can always do that. >>>>>>>>> >>>>>>>>> Alexandre >>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> Stian Soiland-Reyes >>>>>>>>>> Apache Taverna (incubating), Apache Commons RDF (incubating) >>>>>>>>>> http://orcid.org/0000-0001-9842-9718 >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> Sergio Fernández >>>>>>> Partner Technology Manager >>>>>>> Redlink GmbH >>>>>>> m: +43 6602747925 >>>>>>> e: [email protected] >>>>>>> w: http://redlink.co >>>>>> >>>>>> >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> Sergio Fernández >>>>> Partner Technology Manager >>>>> Redlink GmbH >>>>> m: +43 6602747925 >>>>> e: [email protected] >>>>> w: http://redlink.co >>> >>> >>> >
