[Bug 13674] New: [XQ30] schema-element() types behave differently in different modules.

http://www.w3.org/Bugs/Public/show_bug.cgi?id=13674

           Summary: [XQ30] schema-element() types behave differently in
                    different modules.
           Product: XPath / XQuery / XSLT
           Version: Member-only Editors Drafts
          Platform: PC
        OS/Version: Windows NT
            Status: NEW
          Severity: normal
          Priority: P2
         Component: XQuery 3.0
        AssignedTo: jonathan.robie@gmail.com
        ReportedBy: oliver@cbcl.co.uk
         QAContact: public-qt-comments@w3.org


I have been trying to modify our typing judgements to allow for separate
compilation of modules (there were several places in the FS rules where this
was not possible), and have run into the following issue with schema-element()
types.

Consider the following:

1. A schema with target namespace "urn:S1" which declares an element {urn:S1}E.
2. A schema with target namespace "urn:S2" which declares an element {urn:S2}E
which substitutes for {urn:S1}E.


Now, consider the module (urn:M1):


declare module namespace m1="urn:M1";
import schema namespace s1="urn:S1";

declare function m1:function($x as schema-element(s1:E)) as xs:boolean
{
    return $x instance of schema-element(s1:E);
}


The function m1:function accepts any element in the in-scope schema elements
that substitutes for s1:E.  In this case it only accepts elements named s1:E. 
Clearly this function should always return true.



Consider the following query.

import schema namespace s1="urn:S1";
import schema namespace s2="urn:S2";
import module namespace m1="urn:M1";

let $function := m1:function#1 as function(schema-element(s1:E)) as xs:boolean
let $argument := validate { <s2:E /> } as schema-element(s1:E)
return $function($argument)


In this query the type schema-element(s1:E) also matches an s2:E element, as
this is in the substitution group for s1:E.

Following the rules given in the XQuery spec, both these type judgements are
fine.

Since the function takes a schema-element(s1:E) and we are passing it a
schema-element(s1:E) no argument conversion takes place.

However, the actual value of the function call is false, which indicates that
something odd is going on, and the type system is not sound.


I can see several ways of resolving this, none of which seem entirely
satisfactory:

1. schema-element(E) matches any element that substitutes for E, regardless of
whether this schema was imported in the current module.
  That is, when matching a schema-element(E) an implementation should use all
the schema elements that it is aware of, and not just those that have been
imported.

2. It is a static error if schema-element(E) is used ambiguously in different
modules.
  If a module imports a schema which contains an element E' in namespace N'
that substitutes for an element E in namespace N then it is a static error if
any module contains a schema-element(E) without importing the namespace E', or
more simply if any module imports N without importing N'.

3. schema-element(E) is shorthand for the union of matching element types.
  Specifically, schema-element(E) is expanded to the union of element types
element (E', T') where E' and T' are the name and type respectively of an
in-scope schema element that substitutes for E.

4. Importing a schema also imports any other namespaces the implementation is
aware of that substitute elements in it.

A few notes on each suggestion:
1:
  This agrees with the static typing rules given in FS.  (FS apples all its
type judgements based on the fact that it knows every type that can appear).
  When compiling modules seperately this hampers static analysis, as you cannot
say anything about the name of an element that matches a type T without knowing
which other schemas are available in other modules.
  Changing a schema import in one module could break another module.  This may
not be a problem in practice!

2:
  This is the simplest option to implement in the spec - just adding one more
error condition.
  This prevents the following use case:
  * There is a simple schema S
  * There are two incompatible extensions to S, S1 and S2.
  * There are two queries Q1 and Q2 importing S1 and S2 which both use a common
module M inporting S.
  Now, to use M in Q1 it must import S1.  To use M in Q2 it must import S2. 
But it is an error if M imports both.
  Whilst the extra error may seem somewhat arbitrary to users, I suspect that
it will very rarely be seen.

3:
  Painful to explain in the spec, as we don't have arbitrary union types
  This could lead to more costly type checking when calling functions in
precompiled modules.
  The meaning of the type schema-element(E) would depend on its context.  This
would cause issues when exposing types to the outside world, and would hurt
APIs.
  Potential for bugs.

4:
  Implementations are already allowed to do this since the schemas that are
imported by a "schema import" are implementation defined.
  This is similar to option 1, but performs the same task by adding more types
to the in-scope schema types.
  This can also be viewed as similar to option 2, but implicitly imports
missing schemas rather than raising an error.
  This prevents a module from being compiled until all schemas are known.

My opinion is that whilst option 3 seems cleanest in theory, it is probably the
worst in practice!  Option 1 seems nicest from a "no suprises" user
perspective, but currently my preference would lie with option 2 as this allows
the greatest flexibility to implementors.

-- 
Configure bugmail: http://www.w3.org/Bugs/Public/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the QA contact for the bug.

Received on Thursday, 4 August 2011 17:22:04 UTC