Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No Node interface? #159

Closed
namedgraph opened this issue Feb 20, 2019 · 31 comments
Closed

No Node interface? #159

namedgraph opened this issue Feb 20, 2019 · 31 comments

Comments

@namedgraph
Copy link

namedgraph commented Feb 20, 2019

I think it is a shortcoming that NamedNode and BlankNode do not share a common super-type, which would make sense to call Node. Even the naming indicates that there should be one. Blank nodes and resources are the same except how they are labelled, no?

It makes it difficult to port code from Jena, which has such type hierarchy:
RDFNode

  • Resource
    • isBlank() means bnode
    • isURI() means URI
  • Literal
@RubenVerborgh
Copy link
Member

But why? What tangible benefit would this bring?

@namedgraph
Copy link
Author

The benefit of a super-type would be that you could substitute a URI resource with a blank node and that would not require any changes to the code.

More specifically, consider I want to implement SPIN API in JS. The base class of the model is Command, which extends Jena's Resource.

Now, in RDFJS, which interface do I use as the base - BlankNode or NamedNode? In reality it is neither, because a command can be either a URI resource or a blank node, which again calls for a superclass.

@namedgraph
Copy link
Author

RDF4J has exactly the same concept of Resource:

The supertype of all RDF resources (IRIs and blank nodes).

@RubenVerborgh
Copy link
Member

RubenVerborgh commented Feb 20, 2019 via email

@namedgraph
Copy link
Author

OK cool. And what about subclassing?

@RubenVerborgh
Copy link
Member

Up to the implementer; no superclass relationship is imposed (but it can be used). Add your own Node in between if you wish to; doesn’t break contract.

@namedgraph
Copy link
Author

I'll see if this works out.

To flip your question: what is the benefit of diverging from the RDF model used in major RDF frameworks?

@RubenVerborgh
Copy link
Member

We follow the RDF spec, and leave the freedom to follow other frameworks up to the implementers. Our spec does not impose any superclass relations, not even to Term.

@elf-pavlik
Copy link
Member

elf-pavlik commented Mar 4, 2019

@namedgraph would you ever create instances of Node? Or would you ever want DataFactory.node() method to create those instances?

Please also keep in mind that applications have to rely on termType value and never use instanceof

@namedgraph
Copy link
Author

No, instances of Node would not make sense. Its purpose would be more like that of an interface, to enable the same contract for both URIs and blank nodes. Again, like Jena's Resource.

@RubenVerborgh
Copy link
Member

RubenVerborgh commented Mar 4, 2019

Its purpose would be more like that of an interface

But that interface would not have any different methods than Term; hence, it is not necessary from a JavaScript perspective.

enable the same contract for both URIs and blank nodes.

They have that.

@RubenVerborgh
Copy link
Member

Or phrased differently: name one thing that would be in Node that is not in Term, and we have a basis for discussion.

@namedgraph
Copy link
Author

namedgraph commented Mar 4, 2019

I need to look into some (code) examples then. Are there any? How would RDF/JS

  • add/remove RDF property - I assume as JSON properties?
  • check existence of RDF property (with a specific value)
  • iterate RDF properties (that match a combination of p/o values)

Any boilerplate would be candidates for new methods.

What happens if I change termType from BlankNode to NamedNode yet the value is not a valid URI?

@RubenVerborgh
Copy link
Member

I need to look into some (code) examples then. Are there any? How would RDF/JS

* add/remove property - I assume as JSON properties?

* check existence of property (with a specific value)

* iterate properties (that match a combination of p/o values)

I'm confused; are we talking here about JSON properties (= JavaScript object keys), or RDF properties (= predicates)?

What happens if I change termType from BlankNode to NamedNode

You would be operating outside of the spec, as Node is a read-only interface.

@namedgraph
Copy link
Author

Updated comment

@RubenVerborgh
Copy link
Member

These operations would be on the level of Dataset (https://rdf.js.org/dataset-spec/).

@elf-pavlik
Copy link
Member

What happens if I change termType from BlankNode to NamedNode yet the value is not a valid URI?

#81 has strong support to define those instances as immutable

@namedgraph
Copy link
Author

namedgraph commented Mar 4, 2019

Right... coming from Jena, this looks inconvenient to me as well.

First of all, no Triple (= Statement) type, only Quad? Likewise, no Graph (= Model), only Dataset (= Dataset)?
I don't think most people think in quads, sometimes you just want to work on plain triples. Dataset.add(Graph, URI) would be much more natural to me, instead of Dataset.addAll(sequence<Quad>). Similarly, how do I remove/replace/append default/named graphs? Plain quads will create so much boilerplate - why not abstract it?

Second, no Node (= Resource) centric API. To me personally the mental model is "here's a resource that has a URI and some properties and I'm gonna change some of their values" rather than "here's a dataset with a list of quads and some of them have a subject with this URI so I'll filter them and I'll filter the properties as well so I can remove the quads and eventually add new quads with new objects instead". For example consider replacing document title

doc.removeAll(DCTerms.title).addProperty(DCTerms.title, "New title");

vs

dataset.deleteMatches(doc, DCTerms.title, null, null).add({ doc, DCTerms.title, "New title", null });

Which one reads better?

TL;DR I think graph- and resource-centric APIs are lacking.

@RubenVerborgh
Copy link
Member

RubenVerborgh commented Mar 4, 2019

Right... coming from Jena, this looks inconvenient to me as well.

Rightly so, because they are different worlds.

The question we asked ourselves is rather: what is a common way to work with the main elements of the RDF specification in JavaScript?

Which one reads better?

  • doc.removeAll(x): what does it remove? All triples where x is one component? Subject? Object?
  • doc.addProperty(x, y): to what subject does it add that property?

I honestly do not know the above answers.

Also, note that this is the low-level interface. These are the minimal primitives we are agreeing on for interoperability. Feel free to build any higher-level interface that implements removeAll and deleteMatches; they are just not part of what we need for interoperability.

@namedgraph
Copy link
Author

Re. the methods, it's all in Jena's javadoc for Resource.

OK so I'm getting to my point :) If I was about to build a higher-level resource-centric interface above Dataset, which type should my Resource extend?

  • it can't be Term because it's too general - resource methods do not apply to literals etc.
  • it can't be neither NamedNode nor BlankNode, because the point of Resource is to unify them

That's why I'm saying Node is missing - maybe it doesn't matter on the low level, but the subclassing starts to matter on the higher levels. And the low level design has to take those into account ahead of time.

Maybe some JS loosely-typed magic will allow to work around this, but I think having higher-level APIs in mind, the need for a common Node becomes evident on the pure conceptual (class diagram) level.

@elf-pavlik
Copy link
Member

vs https://github.com/simplerdf/simplerdf

doc.title = "New title"

I bet @bergos will update it to use implementation of https://rdf.js.org/dataset-spec/ which should allow you to also build your proposed interface on top of it.

which type should my Resource extend

Just to clarify do you refer to actually using ES extends keyword in your code or your would like to write WebIDL documentation for your implementation?

@namedgraph
Copy link
Author

@elf-pavlik there's no code yet :) I'm looking into how to port some of my Jena code to JS in a painless yet standard-compliant way.

I guess simplerdf is more like what I'm looking for. Too bad if it's not RDFJS compatible.

Note that Jena also has low-level Node/Graph/DatasetGraph API that the higher-level Resource/Model implementations use internally. Node and DatasetGraph seem to compare better to Term and Dataset in RDF/JS.

@RubenVerborgh
Copy link
Member

That's why I'm saying Node is missing - maybe it doesn't matter on the low level, but the subclassing starts to matter on the higher levels.

And what I'm saying is: implement Node on that level then.

Nothing in the spec stops you from having a Node subclass. It just doesn't mandate it.

@elf-pavlik
Copy link
Member

elf-pavlik commented Mar 4, 2019

If you look at reference implementation, it doesn't even have need to implement Term neither uses ES class or extends keywords. I doubt lack of Node interface in the spec would impact your implementation in any way. Once you start hitting some obstacles I'm sure someone on one of rdfjs gitter channels will suggest ES idiomatic solution.

BTW If you prefer some notion of strong types, #129 has links to TS definitions which you can find useful.

@elf-pavlik
Copy link
Member

@namedgraph do you have any new input to this conversation or you think this issue can get closed?

@awwright
Copy link
Member

awwright commented Apr 8, 2019

Someone clarify for me, isn't this what a Term is?

I assume we call them Terms because Node would get confused with a DOM Node

@RubenVerborgh
Copy link
Member

Someone clarify for me, isn't this what a Term is?

Node is a conceptual superclass of (only) NamedNode and BlankNode, whereas Term is a superclass of Literal and Variable as well.

@awwright
Copy link
Member

awwright commented Apr 8, 2019

Yeah, then I'm not sure what benefit we get by creating a common superclass out of BlankNode and NamedNode.

Recall that a BlankNode can also quantify a Literal, too! So it would probably be misleading, at best, I think.

Is my assumption correct, that we call it a Term because Node is already in a WebIDL spec (in DOM)?

@RubenVerborgh
Copy link
Member

Is my assumption correct, that we call it a Term because Node is already in a WebIDL spec (in DOM)?

First time I hear that argument, so probably no. More likely to come from the RDF spec:

IRIs, literals and blank nodes are collectively known as RDF terms.

@awwright
Copy link
Member

awwright commented Apr 8, 2019

@RubenVerborgh Ah yes, of course.

In RDF Interfaces it was RDFNode, but RDF 1.1 wasn't a thing then.

@namedgraph
Copy link
Author

@elf-pavlik nothing more from me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants