Hi Sebastian,
A quick comment for your code : it is better to use it sparsely, because inspect:functions is quite slow.
If you want to improve perfs, create first a map. Here is the code that I am using for this kind of "overloading"
declare variable $common:MapIntrospecting := common:map_inspect_functions();
declare function common:name-function($fun as function(*)){fn:data(inspect:function($fun)/@name)};
declare function common:map_inspect_functions() { map:new(for $fun in inspect:functions() return map:entry(common:name-function($fun),$fun)) };
(this one has to be modified accordingly to your %dispatch annotation, i.e. add where exists(inspect:function($f)[annotation[@name='dispatch:default'][literal[1]=$id]]))
and the dispatcher becomes simply
declare function common:dispatcher(nodes as node()*,$fun as function(*)) as item()* {
let $disptchedfun := map:get($common:MapIntrospecting,common:name-function($fun)) return
if (empty($disptchedfun)) then $fun($nodes) else $disptchedfun($nodes) )
};
>By „map of functions“ did you mean what "inspection:functions()“ is doing?
No, I am talking about a map that can take any item a keys, and any item as values. For instance, in the code above, I would prefer to write the following dispatcher
declare function common:dispatcher(nodes as node()*,$fun as function(*)) as item()* {
let $disptchedfun := map:get(common:MapIntrospecting(),$fun) return
if (empty($disptchedfun)) then $fun($nodes) else $disptchedfun($nodes) )
};
Its is simply a question of performance : in the first mechanism, you have first to "serialize" the function as a string (calling the inspect:function), then to look to a map(string, function), to finally get the correct function call. In the second you directly access to the function, avoiding an expensive call (inspect:function).
However, most probably this enhancement would be of less impact in your code, if you don't call this dispatcher trillions of time.
>I don’t get it: how would you be able to overload the query eval function?
exactly as above. It is something a little bit more elaborate than the following code
declare function common:evil_eval($nodes as node()*,$expr as xs:string) as item()* {
try {
let $fun := map:get($common:MapIntrospecting,$expr) return
if (empty($fun)) then xquery:eval('$xml'||$expr,map{'$xml' := $nodes})
else $fun($nodes)
}
catch *("ouch")
};
Hope this helps
Cheers,
Jean-Marc