shexSpec / shex

ShEx language issues, including new features for e.g. ShEx2.1
25 stars 8 forks source link

Inheritance of Shape Expressions #50

Open labra opened 7 years ago

labra commented 7 years ago

Old versions of ShEx had an inheritance mechanism between Shape Expressions. Something like:

<Car> {  
  :wheel . {4} ; 
  :engine .
}

<NamedCar> &<Car> { 
 :name xsd:string 
}

IIRC, that mechanism was removed for ShEx 2.0, for simplicity and left for future ShEx versions.

However, the fields virtual: Bool and inherit: ShapeExprLabel? are still mentioned in appendix B.

We should either:

Anyway, even if we remove them for ShEx 2.0, I would propose to keep an open issue to discuss about inheritance between Shape Expressions.

labra commented 7 years ago

One way to emulate the previous example in current ShEx 2.0 is something like:

:ShapesContainer {
 $:CarShape (:wheel . {4} ; :engine .)
}

:NamedCar {
 &:CarShape ;
 :name xsd:string 
}

However, it is cumbersome as the user needs to change the reused shape before reusing it.

ericprud commented 6 years ago

Vitals diamond

I've created a demo which could benefit from inheritance. Logically, it has a diamond inheritance pattern (B and C inherit A and D inherits from B and C). Select vitals diamond in this conventional example.

Simplified, it looks like this:

                     <Observation>
                     //       \\         || specializes
        <Vital>:   <BP>         <Pulse>      | extends
                    |                |
                    |    <Posture>   |
                    |     / ||  \   |
<PostureVital>:  <PostureBP> || <PosturePulse>
                    |        ||       |
                    |     <Reclined>  |
                    |     /    \     |
<ReclinedVital>: <ReclinedBP    <ReclinedPulse>

This elides the fact that <{Posture,Reclined}{BP,Pulse}> all specialize <Observation>. Including this makes it look a bit like a heart:


                            <Observation>          || specializes
                        //  ||     ||    \\      | extends
                     //     ||     ||       \\
        <Vital>: //      <BP>     <Pulse>      \\
                 ||      /             \         ||
                 |\     |   <Posture>    |       /|
                 ||\\  |    /  || \    |    //||
<PostureVital>:  ||  <PostureBP> || <PosturePulse> ||
                 ||      |       ||       |        ||
                 ||      |   <Reclined>   |        ||
                 \\     |   /    \     |     //
<ReclinedVital>:    <ReclinedBP    <ReclinedPulse>

This example assumes that the person who extended <BP> and <Pulse> either had the power to add some triple expression labels to them (<BP-TE> and <Pulse-TE>) or some kind soul had already labeled every possibly-useful combination of triple expressions.

<Vital>, <PostureVital> and <ReclinedVital> are simply disjunctions of convenience for some data structure which references a <Vital> (e.g. <AdmissionRecord> { x:vitalsAtAdmission @<Vital> ...}) or a ShapeMap (e.g. :lie@<#Vital> in the demo).

The demo provides two alternative approaches to providing this functionality: "vitals path" and "vitals operator".

Vitals path

The manifest includes a couple syntaxes for getting around these assumptions (with terser text): vitals path: adds the ability to address a triple expression by following a JSON path from a shape expression label. It has examples which include all of the intervening JSON path:

and some that assume by defaults that [n] applies to nth shapeExpr and that addressing a Shape in a triple expression inclusion means you want the expression:

This strategy would require augmenting the syntax for references (currently just an RDF node per JSON-LD reference rules) and on its one doesn't do anything to address the need for the disjunctions for <Vital>, <PostureVital> and <ReclinedVital>. I added some EXPANDS keywords to the example to show how that could be handled by an orthogonal extension to ShEx.

Vitals operator

Another strategy, the one I've been entertaining for a while, is to have inheritance implied both by extension and restriction operators (& and - respectively). This appears to align with the inheritance rules from the programming language Eiffel (known for taking inheritance seriously) but I'm not an Eiffel expert. I believe there's a way to effectively compile this into the structure of vitals diamond but we'll see what I can prove in code in the next couple days.

One downside to Vitals operator (like any OO system) is that there is no way to specify that something be a base class and NOT a specialization or extension. This seems like a rare case and could be addressed in the future with special syntax to close base shapes and nullify their EXTRA declarations.

My preference is to use operators and to add some structural rules (we already have a few] to constrain it to a few practical cases like when the shape expression label references a simple shape or a conjunction with only one shape in it. I think this gives us time to get something out without painting ourselves into a corner while we wait for more complex use cases to float our way.

cmungall commented 5 years ago

Is there any update on this? Is there a dummies guide to inheritance in shex?

ericprud commented 4 years ago

There's a branch of the primer that talks about inheritance; see https://rawgit.com/shexSpec/primer/extends/index.html#inheritance

less polished: notes from implementor's meeting