Skip to content

Commit

Permalink
Drop the term "type alias" in favour of "named item type" (we previou…
Browse files Browse the repository at this point in the history
…sly used both); change the way the rules for recursive types are expressed.
  • Loading branch information
michaelhkay committed Oct 8, 2023
1 parent e956a74 commit bdf9dcc
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 73 deletions.
10 changes: 5 additions & 5 deletions specifications/xquery-40/src/errors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,8 @@
<p>It is a <termref def="dt-static-error">static error</termref> if an <termref
def="dt-expanded-qname">expanded QName</termref> used as an <nt def="ItemType">ItemType</nt>
in a <nt def="SequenceType">SequenceType</nt> is not defined
in the <termref def="dt-static-context"/> either as a <termref def="dt-type-alias"/>
in the <termref def="dt-static-context"/> either as a <termref def="dt-named-item-type"/>
in the <termref def="dt-in-scope-named-item-types"/>,
or as a <termref
def="dt-generalized-atomic-type">generalized atomic type</termref>
in the <termref def="dt-is-types">in-scope schema types</termref>.</p>
Expand Down Expand Up @@ -1057,9 +1058,8 @@ It is a static error if the name of a feature in
-->

<error spec="XQ" code="0140" class="ST" type="static">
<p> It is a <termref def="dt-static-error">static error</termref> if an item type alias refers
directly or indirectly to itself, unless at least one of the references in the chain is
<termref def="dt-shielded"/>.</p>
<p> It is a <termref def="dt-static-error">static error</termref> if a named item type declaration
is recursive, unless it satisfies the conditions defined in <specref ref="id-recursive-record-tests"/>.</p>
</error>

<error spec="XP" code="0141" class="TY" type="type">
Expand All @@ -1083,7 +1083,7 @@ It is a static error if the name of a feature in

<error spec="XQ" code="0146" class="ST" type="static">
<p> It is a <termref def="dt-static-error">static error</termref> if an two explicit or imported
item type declarations have the same name, or if an item type declaration has the same name
named item type declarations have the same name, or if a named item type declaration has the same name
as a <termref def="dt-generalized-atomic-type"/> in the static context of the query module.</p>
</error>

Expand Down
123 changes: 71 additions & 52 deletions specifications/xquery-40/src/expressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -631,21 +631,27 @@ inferred by static type inference as discussed in <specref

<item diff="add" at="A">
<p>
<termdef id="dt-item-type-aliases" term="item type aliases">
<term>Item type aliases.</term> This is a mapping from
<termref def="dt-expanded-qname">expanded QName</termref> to <code>ItemTypes</code>.</termdef></p>
<p><termdef id="dt-type-alias" term="type alias">A <term>type alias</term>
is an <termref def="dt-expanded-qname">expanded QName</termref> that
is mapped to an <code>ItemType</code> in the <termref def="dt-item-type-aliases"/> of
the <termref def="dt-static-context"/>.</termdef>
<termdef id="dt-in-scope-named-item-types" term="in-scope named item types">
<term>In-scope named item types.</term> This is a mapping from
<termref def="dt-expanded-qname">expanded QName</termref> to
<termref def="dt-named-item-type">named item types</termref>.</termdef></p>
<p><termdef id="dt-named-item-type" term="named item type">A <term>named item type</term>
is an <code>ItemType</code> identified by an <termref def="dt-expanded-qname"/>.</termdef>
</p>
<p>Item type aliases allow frequently used item types, especially complex item types such as
record types, to be given simple names, to avoid repeating the definition
every time it is used.</p>
<p>Named item types serve two purposes:</p>
<ulist>
<item><p>They allow frequently used item types, especially complex item types such as
record types, to be given simple names, to avoid repeating the definition
every time it is used.</p></item>
<item><p>They allow the definition of recursive types, which are useful for
describing recursive data structures such as lists and trees. For details see
<specref ref="id-recursive-record-tests"/>. </p></item>
</ulist>
<note>
<p role="xquery">In XQuery, named item types can be declared in the Query Prolog.</p>
<p role="xpath">Item type aliases can be defined in a <termref def="dt-host-language">host language</termref>
such as XQuery 4.0 and in XSLT 4.0, but not in XPath 4.0 itself.</p>
<p role="xpath">Named item types can be defined in a <termref def="dt-host-language">host language</termref>
such as XQuery 4.0 and in XSLT 4.0, but not in XPath 4.0 itself. They are available in XPath
only if the host language provides the ability to define them.</p>
</note>
</item>

Expand Down Expand Up @@ -4176,7 +4182,8 @@ the schema type named <code>us:address</code>.</p>
<termref def="dt-in-scope-namespaces"/> in the <termref def="dt-static-context"/>. If the
name is an unprefixed <code>NCName</code>, then it is taken as being in the
<termref def="dt-def-type-ns"/>.</p></item>
<item><p>If the name matches an entry in the <termref def="dt-item-type-aliases"/> in the <termref def="dt-static-context"/>,
<item><p>If the name matches an entry in the <termref def="dt-in-scope-named-item-types"/>
in the <termref def="dt-static-context"/>,
then it is taken as a reference to the corresponding item type. The rules that
apply are the rules for the expanded item type definition.</p></item>
<item><p>Otherwise, it must match the name of a type in the <termref def="dt-is-types">in-scope schema types</termref>
Expand Down Expand Up @@ -4225,7 +4232,7 @@ the schema type named <code>us:address</code>.</p>
<ulist>
<item><p>Using the QName of a type in the <termref def="dt-issd"/> that is an atomic type
or a <termref def="dt-pure-union-type"/>.</p></item>
<item><p>Using a QName that identifies a <termref def="dt-type-alias"/> that resolves
<item><p>Using a QName that identifies a <termref def="dt-named-item-type"/> that resolves
to a <termref def="dt-generalized-atomic-type"/>.</p></item>
<item><p>Using a <nt def="ParenthesizedItemType">ParenthesizedItemType</nt> where the parentheses enclose
a <termref def="dt-generalized-atomic-type"/>.</p></item>
Expand Down Expand Up @@ -4352,7 +4359,7 @@ the schema type named <code>us:address</code>.</p>
QName must identify a type in the <termref def="dt-issd"/>. This can be any <termref def="dt-schema-type"/>: either a simple type,
or (except in the case of attributes) a complex type. If it is a simple type then it can be an atomic, union, or
list type. It can be a built-in type (such as <code>xs:integer</code>) or a user-defined type. It must however
be the name of a type defined in a schema; it cannot be a <termref def="dt-type-alias"/>.</p>
be the name of a type defined in a schema; it cannot be a <termref def="dt-named-item-type"/>.</p>

<div4 id="id-simple-node-tests">
<head>Simple Node Tests</head>
Expand Down Expand Up @@ -5379,12 +5386,11 @@ name.</p>
<div4 id="id-recursive-record-tests" diff="add" at="issue295">
<head>Recursive Record Tests</head>

<p>The declared type of a field within a record test is a SequenceType, and as such
it may contain a reference to a <termref def="dt-type-alias"/> that is present in
the static context.</p>
<p>A <termref def="dt-named-item-type"/> <var>N</var> is said to be recursive if its
definition includes a direct or indirect reference to <var>N</var>.
</p>

<p>This allows recursive definitions to be created. For example, the following
XQuery declaration defines a linked list:</p>
<p>For example, the following XQuery declaration defines a linked list:</p>

<p><eg>declare item type my:list as record(value as item()*, next? as my:list);</eg></p>

Expand All @@ -5393,25 +5399,36 @@ name.</p>
<eg><![CDATA[<xsl:item-type name="my:list"
as="record(value as item()*, next? as my:list)"/>]]></eg>

<p>To ensure that finite instances of a recursive record test can exist, a cycle of references
is not allowed unless at least one of the references is <termref def="dt-shielded"/>.
<termdef id="dt-shielded" term="shielded">A reference to an item type is <term>shielded</term>
if it occurs within a <nt def="FieldDeclaration">FieldDeclaration</nt> that satisfies one
or more of the following conditions:</termdef> </p>


<p>A recursive named item type <var>N</var> is permitted only if it satisfies
all the following conditions:</p>

<ulist>
<item><p>The field declaration is optional (for example <code>next? as my:list</code>).</p></item>
<item><p>The type of the field declaration matches an empty sequence (for example
<code>next as my:list?</code>).</p></item>
<item><p>The type of the field declaration
is a subtype of <code>function(*)*</code>
(for example <code>next as (function() as my:list)</code>).</p>
<note><p>This rule allows a field declaration that matches an array test
(for example <code>next as array(my:list)</code>) or a map test
(for example <code>next as map(xs:integer, my:list)</code>).</p></note>
<item><p>The item type must be a record test.</p></item>
<item><p>Within the record test, every item type reference <var>R</var> that refers
directly or indirectly to <var>N</var> must satisfy one or more of the following
conditions, where <var>F</var> is the field declaration of <var>N</var>
in which <var>R</var> appears:</p>
<ulist>
<item><p><var>F</var> is an optional field declaration: for example
<code>next? as N</code>.</p></item>
<item><p>The SequenceType of <var>F</var> has an occurrence indicator
of <code>?</code> or <code>*</code>: for example <code>next as N?</code>
or <code>next as N*</code>.</p></item>
<item><p>The item type of <var>F</var> is a function test, map test, or array test:
for example <code>next as (function() as N)</code> or <code>next as array(N)</code>.</p></item>
</ulist>
<note>
<p>These conditions are designed to ensure that finite instances of <var>N</var>
can be constructed.</p>
</note>
</item>
</ulist>




<p>Instances of recursive record types can be constructed and interrogated in the normal way.
For example a list of length 3 can be constructed as:</p>
<p><eg>map{"value":1, "next":map{"value":2, "next":map{"value":3}}}</eg></p>
Expand All @@ -5422,7 +5439,7 @@ name.</p>
specification of the function <code>fn:random-number-generator</code>.</p></note>

<p>Recursive type definitions need to be handled specially by the subtyping rules;
a naïve approach of simply replacing each item type alias
a naïve approach of simply replacing each reference to a named item type
with its definition would make the assessment of the subtype relationship non-terminating.
For details see <specref ref="id-itemtype-subtype"/>.</p>

Expand Down Expand Up @@ -5849,7 +5866,7 @@ declare function t:flatten($tree as t:tree) as item()* {
names, equivalent forms such as <code>element()</code> and <code>element(*)</code>
are normalized.</p>

<p diff="chg" at="issue295">References to <termref def="dt-type-alias">type aliases</termref>
<p diff="chg" at="issue295">References to <termref def="dt-named-item-type">named item types</termref>
are handled as described in <specref ref="id-itemtype-subtype-aliases"/>.</p>

<p>The relationship <code>A ⊆ B</code> is true
Expand Down Expand Up @@ -6504,47 +6521,49 @@ declare function t:flatten($tree as t:tree) as item()* {
</olist>
</div4>
<div4 id="id-itemtype-subtype-aliases" diff="add" at="issue295">
<head>Type Aliases</head>
<p>This section describes how item types that reference <termref def="dt-type-alias">type aliases</termref>
<head>Named Item Types</head>
<p>This section describes how references to <termref def="dt-named-item-type">named item types</termref>
are handled when evaluating the subtype relationship.</p>
<p>Types can be classified as recursive or non-recursive. A recursive type is one that references
itself, directly or indirectly.</p>
<p>Where an item type contains a reference to a type alias that is non-recursive, the reference
<p>Named item types can be classified as recursive or non-recursive.
A recursive type is one that references itself, directly or indirectly. Only record
tests are allowed to be recursive.</p>
<p>Where an item type contains a reference to a named item type that is non-recursive, the reference
is expanded, recursively, as the first step in evaluating the subtype relationship. For example
this means that if <var>U</var> is a type alias for <code>union(xs:integer, xs:double)</code>,
this means that if <var>U</var> is a named item type with the expansion
<code>union(xs:integer, xs:double)</code>,
then <code>xs:integer ⊆ U</code> is true, because
<code>xs:integer ⊆ union(xs:integer, xs:double)</code> is true.</p>
<p>Recursive types are considered to be, in the terminology of the computer science
literature, <term>iso-recursive</term> (rather than <term>equi-recursive</term>).
This means that a recursive type name is not
treated as being equivalent to its expansion (at any depth).
For example, if the type alias <var>T</var>
refers to the type <code>record(A as item()*, B as T?)</code>, then the type
For example, if the named item type <var>T</var>
has the expansion <code>record(A as item()*, B as T?)</code>, then the type
<code>array(T)</code> is not considered to be equivalent to
<code>array(record(A as item()*, B as T?))</code>, despite the fact
that the two types have exactly the same instances.</p>
<p>The rules are therefore defined as follows:</p>
<ulist>
<item><p>If <var>B</var> is the type alias of a recursive type, then
<item><p>If <var>B</var> is a reference to a recursive named item type, then
<var>A</var> ⊆ <var>B</var> is true if and only if
<var>A</var> and <var>B</var>
are references to the same type alias.</p></item>
<item><p>If <var>A</var> is the type alias of a recursive type, then
are references to the same named item type.</p></item>
<item><p>If <var>A</var> is a reference to a recursive named item type, then
<var>A</var> ⊆ <var>B</var> is true if either:</p>
<ulist>
<item><p><var>A</var> and <var>B</var>
are references to the same type alias.</p></item>
are references to the same named item type.</p></item>
<item><p><code>record(*) ⊆ B</code>.</p>
<note><p>This is because only record types are allowed to be recursive.</p></note></item>
<note><p>This is because only record tests are allowed to be recursive.</p></note></item>
</ulist>
</item>
</ulist>

<note><p>The decision to make recursive types iso-recursive rather than equi-recursive
was made largely because it saves a great deal of implementation complexity without any serious
adverse effects for users. It practice, the rules for subtyping largely affect substitutability
of different function signatures, and any problems can be avoided by using type alias names
in function signatures consistently, especially when recursive types are involved.</p>
adverse effects for users. It practice, problems can be avoided by using named item type references
consistently (for example, avoiding having two named item types with
different names but identical definitions).</p>
</note>
</div4>

Expand Down
Loading

0 comments on commit bdf9dcc

Please sign in to comment.