shexSpec / shex

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

IF...THEN...ELSE pattern #21

Open labra opened 7 years ago

labra commented 7 years ago

A common pattern for data models is the IF-THEN-ELSE construct.

In ShEx, it can be modelled using the logical operators AND, OR, NOT.

For example, if we want to model a node that, if the value of property :p is 1, then the value of property :q is "one", otherwise it is "other", we could use something like:

:S IF { :p [ 1 ] } THEN { :q [ "one" ] } ELSE { :q [ "other" ] }

we could simulate that by making use of the logical equivalence

IF A THEN B ELSE C = (NOT A OR B) AND (A OR C)

so the previous shape could be written as:

:S (NOT { :p [ 1 ] } OR { :q [ "one" ] }) AND ({ :p [ 1 ] } OR { :q [ "other" ] }

However, I think it is a pain for the users to have to remember that kind of expressions and that it is also error-prone.

I think future versions of ShEx could add some macro or operation for the IF-THEN-ELSE pattern.

vrandezo commented 4 years ago

Just a comment: I find an IF ... THEN ... ELSE ... rather limiting and would wonder if a CASE pattern would be more scalable to cover more cases with less verbosity.

labra commented 4 years ago

I am trying to compare possible syntaxes. Let's take an example from this question :

Can I have a shape that says "if state is assigned, assignee must have a value, if it is unassigned, it must not" ?

A possible definition with the current syntax could be something like:

:IssueShape { a [ :Issue ] } 
AND ( NOT { :state [:assigned ] } OR { :assignee @:Value }) 
AND ( { :state [:assigned ] } OR { :assignee @:Value {0,0} } )

:Value { a [ :Value ] }

Which is not very readable.

Using the IF-THEN-ELSE, we could write it as:

:IssueShape { a [ :Issue ] } AND 
IF { :state [ :assigned ] } 
THEN { :assignee @:Value }  
ELSE { :assignee @:Value {0,0} }

If we tried to use a CASE, it could be something like:

:IssueShape { a [ :Issue ] } AND 
CASE { :state [ :assigned ] } => { :assignee @:Value }  
CASE . => { :assignee @:Value {0,0} }

One concern about several CASE's is that the order of them affect the shape definition, while with the IF-THEN-ELSE, although is more verbose, it forces the author to think what he really intends to express.

For example, if one wants to express now:

Can I have a shape that says "if state is assigned, assignee must have a value, if, state is onReview, reviewer must have a value, and if state is neither assigned nor on review, then it must have no value" ?

A simple representation of the above with CASEs could be:

:IssueShape { a [ :Issue ] } AND 
CASE { :state [ :assigned ] } => { :assignee @:Value }  
CASE { :state [ :onReview ] } => { :reviewer @:Value }
CASE . => { :assignee @:Value {0,0} }

It looks OK but the order of the cases can affect the validation.

For example, if one issue has both values for :assigned and :onReview the validator would need to decide if it checks the first CASE or the second CASE (or both). Usually, programming languages like C or Java choose the first one...but having to take into account the order of definitions in ShEx could make it more complex than necessary.

If we had only IF-THEN-ELSE expressions, the author would be more forced to take into account the different cases. For example, the following definition makes clear, that the validator checks first that the state is assigned so on:

:IssueShape { a [ :Issue ] } AND 
IF { :state [ :assigned ] } THEN { :assignee @:Value }  
ELSE IF { :state [ :onReview ] } THEN { :reviewer @:Value }
ELSE { :assignee @:Value {0,0} }
ericprud commented 4 years ago

Looking for a precedent from programming languages. does static analysis catch shadowed cases? or some shadowed cases?