Re: practical problems with rdf:parseType="Collection" implementation

One of the reasons for adding parsetype=collection was precisely because 
some people needed a way to express a "closed" list;  i.e. one which could 
not be made into another (well-formed) list simply by the addition of extra 
triples to a graph.

So in many respects I would see that which you perceive as "problems" to be 
"features".

#g
--

At 17:09 12/08/03 -0700, Garret Wilson wrote:

>Everyone,
>
>I'm just getting around to implementing support for 
>rdf:parseType="Collection", even though I've been using it for a while in 
>specifications I've written.
>
>The design of rdf:List looks good in theory, but there are a few details 
>that make it a pain to implement---particularly, the way rdf#nil is used:
>
>1. Empty lists cannot be modified.
>
>In the RDF world, it's natural to think that one can always add things to 
>a resource. I can specify another dc:creator to a book. I can later add an 
>rdfs:label to a resource. Yes, I know that RDF is designed to only be 
>aware of one set of static relationships, but in the real world we need to 
>modify resources at some time or another. We can modify rdf:Alt, rdf:Bag, 
>and rdf:Seq, even if they are empty---we just add one or more resources to 
>the collection.
>
>rdf:List is designed so that one cannot add anything to an empty rdf:List, 
>because there is only one empty rdf:List, the one named rdf#nil. There are 
>an infinite number of non-empty lists, with an infinite number of (usually 
>anonymous/blank node) reference URIs, but *none* of those lists can be 
>empty, because the empty list has its own static universal reference URI. 
>Conversely, the empty list can never be added to without changing its 
>reference URI. Put differently, an empty rdf:List cannot be filled---it 
>can only be replaced with a filled list. (Compare this to an rdf:List with 
>one element---programmatically, one can add more elements by changing the 
>rdf:rest property, allowing the list remains the same entity, identified 
>by the same reference URI. This is impossible with an empty list.)
>
>2. It is a pain to populate an rdf:List.
>
>Even if we accept the theoretical notion of RDF as a static snapshot of 
>relationships, in the real world one has to populate that directed graph 
>programmatically---when parsing an RDF+XML document, for instance. With 
>the old containers, that was easy: we start with an empty rdf:Alt, 
>rdf:Bag, or rdf:Seq and then add elements if and only if they are present.
>
>With rdf:List, this procedure remains the same *only* after we know we 
>have one element in a list. Until we have one element in the list, we 
>don't know whether to create an anonymous rdf:List and populate it with 
>items, or (if there are no items) to create an rdf#nil list (with its 
>unique reference URI). This results in very inelegant algorithms:
>
>while(there are child elements)
>{
>   create a new rdf:List
>   if(we've already created an rdf:List)
>   {
>     add the new rdf:List to the old one
>   }
>   else
>   {
>     specify that the new list is the "root" list
>     save this new list for next time
>   }
>}
>if(we have record of finding a "root" list)
>   use the "root" list as the property value
>
>In contrast, the old containers allowed very elegant implementations, 
>because they didn't distinguish conceptually between empty and filled 
>containers:
>
>create new container
>while(there are child elements)
>{
>   add the element to the container
>}
>use the new container as the property value
>
>3. It is impossible to independently insert an element at the beginning of 
>an rdf:List.
>
>In object-oriented programming, I'd like to have an object represent an 
>rdf:List. In Java, something implementing java.util.List would be great. 
>Given any MyList, it's a simple matter to insert something at index i+1 
>with i>0: I just create a new rdf:List with rdf:first representing the 
>inserted resource, change rdf:List(i).rdf:rest to point to the new 
>rdf:List, and change rdf:List(i+1).rdf:rest to the old value of 
>rdf:List(i).rdf:rest.
>
>That's all fine except when i=0. To insert at the front of the list, I 
>have to know for which resource property the rdf:List is the property 
>value. This is made worse by the fact that several properties (of several 
>resources) might have the rdf:List as a property value. This leads to the 
>following inconsistency: if resources example.com#book1, 
>example.com#book2, and example.com#book3 all have a property of 
>listOfComments, I can always add another comment to the end of the list 
>without modifying the property value for any of the books, but if I want 
>to *insert* a comment at the first of the list, I have to modify the 
>property value for each of the books.
>
>In very practical terms, that means if I have the function...
>
>add(RDFList list, RDFResource resourceElement, int index)
>
>...it will work for all values of index except index==0, unless I have 
>access to the entire RDF data model, walk the graph, and find all 
>resources which have properties for which the list is a property value.
>
>Similarly, going back to problem #1 (above), the function...
>
>add(RDFList list, RDFResource resourceElement, int index)
>
>...cannot work with empty lists!
>
>I understand that the old collection framework had shortcomings (those 
>silly indexes, for one thing) and that the new rdf:List framework looks 
>nice in a pretty static graph on paper. The specific way that rdf#nil is 
>used as an empty list, however, creates very inelegant impelementation 
>restrictions. Surely rdf:List could me modified to be better than the old 
>collections, yet also usable in real life.
>
>Garret

---------------------------------
Graham Klyne  <GK@NineByNine.net>
Nine by Nine
http://www.ninebynine.net/

Received on Wednesday, 13 August 2003 05:27:56 UTC