This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 22732 - [F+O 3.0] Function-lookup and the dynamic context
Summary: [F+O 3.0] Function-lookup and the dynamic context
Status: RESOLVED FIXED
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: Functions and Operators 3.0 (show other bugs)
Version: Candidate Recommendation
Hardware: PC All
: P2 normal
Target Milestone: ---
Assignee: Michael Kay
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-07-19 07:38 UTC by Michael Kay
Modified: 2013-08-10 02:04 UTC (History)
1 user (show)

See Also:


Attachments

Description Michael Kay 2013-07-19 07:38:33 UTC
Under function-lookup we say:

If the function that is retrieved by fn:function-lookup has dependencies on the static or dynamic context, the context that applies is the static and/or dynamic context of the call to the fn:function-lookup function itself. The context thus effectively forms part of the closure of the returned function.

(We say this in a Note, surely it should be in normative text?)

Have we considered all the implications? I suspect not.

Let's say there is a public function f with a reference to a private global variable v:

declare %private variable v := 3;

declare %public function f() {$v};

And now suppose that we find f by means of a call to function-lookup(), and then invoke the returned function item. What does it return?

Given the spec as written, the answer is that the reference to $v is resolved, both statically and dynamically, by reference to the variables in scope for the call to function-lookup(). If that call is in a different module there will typically be no $v variable in scope, so the result is an error. If the call is written like this:

let $v := 5 return function-lookup("f", 0)()

then the result should be 5.

This appears to me quite unacceptable, because it means that when compiling function f, we cannot make any assumptions about what the reference to $v means. We can't even make assumptions about its type.

Similarly: consider namespaces. If the body of the function is {<p:local/>}, do we really expect the namespace prefix p to be resolved using the namespaces in the static context of the call to function-lookup()? 

I can't imagine this is what we intended. The performance implications (not being able to make assumptions about global variables and namespaces when compiling f, just in case there is a dynamic call) are horrible. If we had intended this, someone would surely have written some tests to demonstrate the effect.

What is the alternative? I'll make some suggestions in another comment.
Comment 1 Michael Kay 2013-07-19 07:49:10 UTC
To restore what I think we intended when we wrote this rule, I suggest we change it to say:

If the function that is retrieved by fn:function-lookup has *dynamic* dependencies on the static or dynamic context....

and then think about how to define what "dynamic dependencies" are. What we want here is to allow static binding to the things that you would normally expect to be statically bound (like namespaces), and dynamic binding to the things that can't be statically bound (like a decimal format, or a collation whose value is not known until run-time.)

I can't think of any way of doing this other than enumerating which context dependencies are considered dynamic. This might not be easy: for example the collation name in "order by" is fixed statically, and we would presumably like to bind it statically, whereas collation names passed to functions are in general only known dynamically.

For variables (consider my original example) there is the complication that we would really like f to be able to bind both to the (static) declaration of $v, and to its (dynamic) value (3). This is tricky to achieve because our current semantics for variable references speak as if we did a run-time lookup of the variable name.
Comment 2 Michael Kay 2013-07-19 08:00:00 UTC
Another approach would be to say that this rule does not apply to user-defined functions. In the case where the result of function-lookup() is a user-defined function:

(a) dependencies on the static context should be resolved by reference to the static context of the module in which the function declaration appears

(b) dependencies on the dynamic context (for example, the values of variables) should be resolved in the same way as if the function were called directly from another function in the same module.

This seems much simpler.
Comment 3 Michael Kay 2013-07-19 13:08:53 UTC
Perhaps the reason this is a Note in F+O is that the definitive rules are in the language book, specifically 

3.1.5.1 Evaluating Static and Dynamic Function Calls

This makes it fairly clear that there is a distinction between built-in functions and user-defined functions, and that only the first kind carry context information around with them: so it's broadly along the lines of the proposal in comment #2.

This leaves a few relatively minor problems to be fixed:

(a) the Note in F+O function-lookup() is a poor summary of the situation; it should refer to 3.1.5.1 in the language book. 

(b) the semantics in the language book rely on a built-in function item carrying context information around with it, and the spec for function-lookup() needs to say normatively how this is derived (viz from the context of the call to function-lookup().

(c) the rules in both the XQuery and XPath language books distinguish the two kinds of function according to whether the implementation of the function is a "FunctionBody", which doesn't allow for user-defined functions to be written in a different host language (such as XSLT). Perhaps the XPath version should say "FunctionBody, or its equivalent in the some other host language". Or perhaps the XSLT book should say that xsl:function defines a function whose implementation is "a FunctionBody with equivalent semantics to the sequence constructor contained in the xsl:function declaration".
Comment 4 Ghislain Fourny 2013-07-23 14:57:06 UTC
I think that the intent of the note was to say "If the function that is retrieved by fn:function-lookup is context-dependent, ..." with the same meaning of "context-dependent" as in F&O (sensitive to the context in which it is called).
A user-defined function is never context-dependent if I am correct, so that this excludes them.
Basically, it means that fn:function-lookup behaves similarly to its static counterpart (named function references).
Comment 5 Ghislain Fourny 2013-07-23 16:14:29 UTC
I am wondering if does not suffice to add the exact same wording as for named function references, since the idea and behavior is the same.

i.e.

"If the function retrieved by fn:function-lookup has an implementation-dependent implementation, then the implementation of the function returned by fn:function-lookup is associated with the static context of the expression calling fn:function-lookup, and to the dynamic context in which it is currently being evaluated."



Also, both for named function references and for fn:function-lookup, I am wondering if, when this association is made, we should not explicitly define a brand new function based on the underlying, context-dependent one. The way I would picture it is:
- if no context association is made, the function that is returned is _exactly_ that from the dynamic context.
- if a context association is made, it is a different function, obtained by copying the one in the dynamic context, removing its name and associating DC and SC with the implementation-defined implementation.


Then we could fine-tune, like only make the association if the function is context-dependent (currently, we always associate a context if it has an implementation-dependent implementation, but it has no effect at all if the function is not context-dependent).

I hope it makes sense.
Comment 6 Michael Kay 2013-08-05 01:51:32 UTC
Copy of proposal in https://lists.w3.org/Archives/Member/w3c-xsl-query/2013Jul/0086.html (member-only)


ACTION A-574-01 MK concerning bug 22732 (function-lookup()) to propose detailed changes to implement items (a) and (b) in comment #3. Before the F2F.

1. Change the properties of fn:function-lookup() to say focus-dependent instead of focus-independent.

2. Change the first paragraph in the Rules of fn:function-lookup() (F+O 16.1.1) to read:
A call to fn:function-lookup returns the function obtained by looking up the expanded QName supplied as $name and the arity supplied as $arity in the named functions component of the dynamic context (specifically, the dynamic context of the call to fn:function-lookup).

Furthermore, if that function has an implementation-dependent implementation (in practice: if it is a context-dependent built-in function), then the implementation of the function returned by fn:function-lookup is associated with the static and dynamic context of the call to fn:function-lookup.


3. Change the last paragraph of the Notes of fn:function-lookup() (F+O 16.1.1)

If the function that is retrieved by fn:function-lookup is *context-dependent*, that is, if it has dependencies on the static or dynamic context of its caller, the context that applies is the static and/or dynamic context of the call to the fn:function-lookup function itself. The context thus effectively forms part of the closure of the returned function. In practice this applies only where the target of fn:function-lookup is a built-in function, because user-defined functions never depend on the static or dynamic context of the function call. The rule applies recursively, since fn:function-lookup is itself a context-dependent built-in function.

These specifications do not define any circumstances in which the dynamic context will contain functions that are not present in the static context, but neither do they rule this out. For example an API  *may* provide the ability to add functions to the dynamic context. Equally, these specifications do not define any mechanism for creating context-dependent functions other than the built-in context-depedendent functions, but neither do they rule out the existence of such functions.
Comment 7 Michael Kay 2013-08-10 02:04:42 UTC
The proposal copied in comment #6 was accepted.