Description
I was trying to use type-scoped contexts to define a @context
and was surprised to discover that any type-scoped terms that get defined in the active context continue to be defined beyond the object with the matching @type
. I think this is very unexpected behavior from an OOP modeling perspective. Also, it is very problematic for @protected
terms, as it means that you can't model objects of one type that contain objects of another type when there is a commonly used JSON key (that may or may not have the same term definition) when terms are protected.
A playground example:
{
"@context": {
"@version": 1.1,
"@vocab": "ex:",
"@protected": true,
"Library": {
"@context": {
"book": "library:book",
"name": "library:name"
}
},
"Person": {
"@context": {
"name": "person:name"
}
}
},
"@id": "the:library",
"@type": "Library",
"book": {
"@id": "the:book",
"about": {
"@id": "the:person",
"@type": "Person",
"name": "Oliver Twist",
"book": "unexpectedly defined as library:book!"
}
}
}
Produces these quads:
<the:book> <ex:about> <the:person> .
<the:library> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <ex:Library> .
<the:library> <library:book> <the:book> .
<the:person> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <ex:Person> .
<the:person> <library:book> "unexpectedly defined as library:book!" .
<the:person> <person:name> "Oliver Twist" .
If you use @protected
here, you get an error (which I also find unexpected):
{
"@context": {
"@version": 1.1,
"@vocab": "ex:",
"@protected": true,
"Library": {
"@context": {
"@protected": true,
"book": "library:book",
"name": "library:name"
}
},
"Person": {
"@context": {
"@protected": true,
"name": "person:name"
}
}
},
"@id": "the:library",
"@type": "Library",
"book": {
"@id": "the:book",
"about": {
"@id": "the:person",
"@type": "Person",
"name": "Oliver Twist",
"book": "unexpectedly defined as library:book!"
}
}
}
That error happens even if name
is defined the same way for both types.
I suspect that type-scoped terms behave this way because it was easy to implement, but I think it is very surprising behavior that may not have been exposed yet due to limited examples.
It's possible that there's an easy fix for this. I think we should change this behavior so that we track whether a term definition in the active context was defined via a type-scoped context and whether or not it replaced a non-type-scoped term when it did so. Then, whenever traversing into one of the typed object's properties during processing, we revert all type-scoped terms to their previous definitions which may mean setting them to null
(clearing them) if they were previously undefined. Then processing can continue as normal.