- From: Garret Wilson <garret@globalmentor.com>
- Date: Tue, 12 Aug 2003 17:09:12 -0700
- To: www-rdf-interest@w3.org
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
Received on Tuesday, 12 August 2003 20:09:21 UTC