Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Equivalence of map and function types #730

Closed
michaelhkay opened this issue Sep 28, 2023 · 12 comments
Closed

Equivalence of map and function types #730

michaelhkay opened this issue Sep 28, 2023 · 12 comments
Labels
Bug Something that doesn't work in the current specification XPath An issue related to XPath

Comments

@michaelhkay
Copy link
Contributor

michaelhkay commented Sep 28, 2023

It is stated in XPath §3.6.4.2, and probably elsewhere, that

The function signature of a map matching type map(K, V), treated as a function, is function(xs:anyAtomicType) as V?

But V is a sequence type, not an item type, so you can't just tag a '?' onto the end of it. What is intended here by V? is a sequence type that is the union of V and empty-sequence().

@michaelhkay
Copy link
Contributor Author

Further this sentence still uses language that suggests that it's meaningful to talk of "the function signature" of a map; yet we know that a map matches many types of the form map(K,V) and therefore has many function signatures.

We often try to pretend that for a given map, there is one map type map(K,V) that is more specific than any other map type that the map conforms to. This is not the case, as is easily shown by looking at the empty map.

@dnovatchev
Copy link
Contributor

It is stated in XPath §3.6.4.2, and probably elsewhere, that

The function signature of a map matching type map(K, V), treated as a function, is function(xs:anyAtomicType) as V?

But V is a sequence type, not an item type, so you can't just tag a '?' onto the end of it. What is intended here by V? is a sequence type that is the union of V and empty-sequence().

All such subtleties and misunderstandings are due to the fact that we do not have (but do need) at present a None in XPath.

None is not the same as the empty sequence ().

None is the contents of [].

And [] is different from [()] whose (of the latter) contents is the empty sequence ():

image

I think we need to have None in XPath in order to avoid such misunderstandings, and wrong function definitions as fn:void returning empty-sequence() when in fact its return type is None. In fact, if we have None in the language, then we will not need fn:void at all.

We also need a function contents(collection) and this function, as in the screenshot example above can return None.

By definition, any attempt to reference a None would result in error. Thus we wouldn't have to explain why using the empty sequence is sometimes OK but sometimes this results in error.

@michaelhkay
Copy link
Contributor Author

@dnovatchev Could you explain please how having the type None available would solve this problem? We're not talking here about functions that don't return a value.

@dnovatchev
Copy link
Contributor

@dnovatchev Could you explain please how having the type None available would solve this problem? We're not talking here about functions that don't return a value.

Correct, I got carried away by the proposed use of empty-sequence() which would be the wrong solution (see below).

Further this sentence still uses language that suggests that it's meaningful to talk of "the function signature" of a map; yet we know that a map matches many types of the form map(K,V) and therefore has many function signatures.

We often try to pretend that for a given map, there is one map type map(K,V) that is more specific than any other map type that the map conforms to. This is not the case, as is easily shown by looking at the empty map.

As for the signature of a map, it is quite clear:

function(xs:anyAtomicType) as item()*

The empty map is the extreme case of function of 0 arguments that produces None.

@michaelhkay
Copy link
Contributor Author

As for the signature of a map, it is quite clear: function(xs:anyAtomicType) as item()*

If only it were clear! The matter has caused immense confusion over the years, resulting in recent reopening of the thread at w3c/qt3tests#28 and challenging of currently accepted test results.

The root cause of the problem is that for "intentional functions" (i.e not maps and arrays), a function has a signature as a self-contained property and there is no argument about what the signature is. For maps and arrays it's less clear that the concept of having a signature is useful, because maps and arrays don't have a type label of any kind; as with sequences, types are essentially predicates rather than properties, and the "instance of" operator involves inspecting the actual contents.

Perhaps the solution is indeed to say that the signature of a map is function(xs:anyAtomicType) as item()* (it doesn't matter what the signature is if nothing depends on it), but then to say separately that the instance of relation for a map doesn't depend on this signature, but rather on the equivalence

$M (a map) is an instance of function(xs:anyAtomicType) as R if and only if

(a) $M is an instance of map(xs:anyAtomicType, R), and
(b) empty-sequence() is a subtype of R.

We also need to say that map(K, V) is a subtype of function(xs:anyAtomicType) as R if and only if

(a) V is a subtype of R, and
(b) empty-sequence() is a subtype of R.

@dnovatchev
Copy link
Contributor

dnovatchev commented Oct 6, 2023

Perhaps the solution is indeed to say that the signature of a map is function(xs:anyAtomicType) as item()* (it doesn't matter what the signature is if nothing depends on it), but then to say separately that the instance of relation for a map doesn't depend on this signature, but rather on the equivalence

💯

$M (a map) is an instance of function(xs:anyAtomicType) as R if and only if

(a) $M is an instance of map(xs:anyAtomicType, R), and (b) empty-sequence() is a subtype of R.

We also need to say that map(K, V) is a subtype of function(xs:anyAtomicType) as R if and only if

(a) V is a subtype of R, and (b) empty-sequence() is a subtype of R.

We will obviously need other "empty-types" such as empty-map() and empty-array()

It is logical and convenient to have just one type nothing() that is a subtype of all these 3 empty-types, so in all these 3 cases we will simply specify the type as nothing().

@dnovatchev
Copy link
Contributor

The XPath 3.1 Specification defines empty-sequence() as:

"The sequence type empty-sequence() matches a value that is the empty sequence."

This by definition falls short of matching an empty array: [ ] or an empty map: map{ }.

Thus the proposed type nothing() that is a subtype of empty-sequence(), empty-array(), and empty-map() is designed to be used as a substitute for any of these 3 types, conveying essentially the same meaning in a much easier to understand, friendlier way.

@michaelhkay
Copy link
Contributor Author

michaelhkay commented Oct 6, 2023

If we defined the three types empty-sequence(), empty-array(), and empty-map() then their intersection would be empty, so a type that is a subtype of all three would indeed have no instances, which is a good definition of the nothing() type. Of course nothing() is also a subtype of every other type, for example it is a subtype of xs:integer. Note also that we already have a name for the type with no instances: it is called xs:error. It's arguably not a very good name, but I'm not sure that giving it additional names would be very useful.

Reading your post again, I wonder if you're actually looking for a type that is the union of empty-sequence(), empty-map(), and empty-array(), rather than the intersection?

@dnovatchev
Copy link
Contributor

dnovatchev commented Oct 6, 2023

Reading your post again, I wonder if you're actually looking for a type that is the union of empty-sequence(), empty-map(), and empty-array(), rather than the intersection?

If it is the union, (per my understanding, which may be wrong) then we will need to provide one of the 3 "simple types" every time and this is exactly what we want to avoid.

On a related topic: do we still need fn:void, when now we can simply define the return type of what would have been its argument-function(s) to be nothing() ?

michaelhkay added a commit to michaelhkay/qtspecs that referenced this issue Oct 6, 2023
@michaelhkay michaelhkay added Bug Something that doesn't work in the current specification XPath An issue related to XPath PR Pending A PR has been raised to resolve this issue labels Oct 6, 2023
@dnovatchev
Copy link
Contributor

@michaelhkay Shall we have a separate issue for the nothing() type?

@michaelhkay
Copy link
Contributor Author

By all means raise a separate issue if you think there are problems that it would solve.

michaelhkay added a commit to michaelhkay/qtspecs that referenced this issue Oct 31, 2023
@michaelhkay
Copy link
Contributor Author

Fixed by #736.

@ChristianGruen ChristianGruen removed the PR Pending A PR has been raised to resolve this issue label Mar 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something that doesn't work in the current specification XPath An issue related to XPath
Projects
None yet
Development

No branches or pull requests

3 participants