extension functions, special forms

  • Hi Michael, I am back trying to assimilate your latest and greatest Saxon 8.1.1 with my extensions. I have converted my Exception handling and my HTTP post remote web services call extensions successfully. What remains is the user accessible closure() function...

    I realize that you didn't want to incorporate any of this code so far. But may I plead with you at least for allowing user-defined functions to be "special forms" that allow Expressions to be passed as arguments?

    That is, treat a user defined function with an initial argument of XPathContext and a declared argument(s) of Expression as a special form, where those argument(s) are NOT evaluated before the function is called.

    This would allow the user to implement special forms as we had them in LISP, i.e., those that control evaluation of arguments explicitly. One could implement user-defined cond/switch statements as well as my closure extension.

    I will once again dig into your code implementing the user-defined special-form function, but I would hope so much that this could be the last time I'd have to do it and you would seriously consider adopting this code in the same way that you have adopted my earlier patches for accessing fields as zero-argument functions.


    • O.K. trying to analyze what's new in your design. I take it FunctionProxy has dissolved into ExtensionFunctionCall and JavaExtensionLibrary. Fine.

      ExtensionFunctionCall has its class and method bound already and JavaExtensionLibrary does the job of matching the right Java method and create the ExtensionFunctionCall object. Good, that's nice and clean.

      ExtensionFunctionCall.iterate is where the call work starts. For my taste you're evaluating arguments too early. Let's hold off on evaluation until inside the call() method. Therein we can evaluate as needed, i.e., only if the formal argument is not an Expression. Also, that Expression special case only needs to be done in case of a Method and only if the XPathContext argument comes first. So, that's only a very pointed change. Easy to do ...

      Basically iterate() will just return call(...) and I'll remove all argValues arguments. Instead, evaluation is done on demand, and mostly in the setupParams method. Done. That was so easy!

      Now off to modifying the JavaExtensionLibrary ...

      • Michael Kay
        Michael Kay

        Part of the redesign is that you should be able to create your own mechanism for binding external functions without any source code change - I haven't proved that can be done, but it's the intent. Don't modify JavaExtensionLibrary, create an alternative (or a subclass), and register it using setExtensionBinder() on the Configuration object.

        After that you're in full control of the binding algorithm. If you only want to change the call mechanism and not the binding algorithm, you can also do that, by creating your own ExtensionFunctionFactory and registering that with the Configuration. Your ExtensionFunctionFactory can return a different kind of Expression to implement an extension function call, which means you're not tied to use the call mechanism in the ExtensionFunctionCall class.

        Michael Kay

    • Thanks Michael. It turns out so extremely easy! You did a great job refactoring this code! I will offer you my very pointed changes again, it is just a very few keystrokes to get it done.

      In JavaExtensionLibrary, all I had to do was to add an if clause in getConversionPreference(Expression arg, Class required) that reads:

      if(required == Expression.class) {
      return 120;

      and that was essentially it! I am thinking of adding another case to catch a final Expression[] argument which would allow variable length unevaluated argument lists.

      But before I do that I need to fiddle with the ExpressionTool again to keep it from eagerly evaluating my Closures.

    • O.K. I am done. The special form stuff is done and works like a charm. It was extremely easy. I have not done the &rest argument list handling into a final Expression[] argument quite yet. I will upload my patch to your patches page. Please, please consider adding them into your release because this is so totally straight-forward.

      Note that none of this patch contains anything about the closure function. I'll do this separately to give you a chance to opt into this one without the other one.

      Thanks, and as always, your code is so cool! I wish I could hire you.


    • All done, including the rest-argument. Tested, works. See later post and the patches area. Thanks.