To "fn" or not to "fn"

by Evan Lenz

That is the question. Have you ever noticed that when people call built-in XQuery functions like string(), count(), and collection(), they sometimes prefix the function name with "fn:" and sometimes they don't? Why? When is it necessary to include the "fn" prefix, and when is it okay to leave it out? Or perhaps you've noticed that sometimes MarkLogic complains when you leave it out and sometimes it doesn't? This blog post is an attempt to clear up any confusion around this and help you define your own policy or preference on this most important issue that affects us all. (Still reading? Okay, I'll go on.)

The prefix "fn" is special in XQuery, because it's pre-defined to correspond to the namespace URI for built-in XPath functions. The upshot is that the following line is implicit in every XQuery module you write (unless you override it):

declare namespace fn = "http://www.w3.org/2005/xpath-functions";

This means that you can call functions like fn:string() and fn:concat(), because the "fn" namespace is already defined for you. But if you leave the prefix off a function call, then you'd be relying on the default function namespace, which is often the same as the "fn" namespace, and so it often works. (Ay, there's the rub.) Don't worry, I'll explain what I mean by "often."

But first, it's worth pointing out that things are a bit different in XSLT, where the prefix "fn" does not have any special standing. If you want to write "fn:collection()" in XSLT, you'd need to explicitly bind the "fn" prefix in your stylesheet:

<xsl:stylesheet xmlns:fn="http://www.w3.org/2005/xpath-functions" …>

Of course, nobody does that in practice, because "collection()" works just fine, and in fact always works fine without a prefix in XSLT. In other words, the XPath function namespace is always (not just often) the default function namespace in XSLT, and there's no way to override it.

The difference in XQuery is that you can override the default function namespace, using a declaration like this:

declare default function namespace "http://example.com/my-function-ns";

If you don't include a line like this in your code, then it's up to your XQuery implementation to determine what the "default default" function namespace is. The XQuery spec "recommends" that implementations set that "default default" to the XPath function namespace (the "default default default"?), but it also allows them to override it. As it happens, MarkLogic is an implementation that overrides it...at least part of the time.

Okay, now I'll explain what I mean by "often." In XQuery, there are two kinds of modules: main modules and library modules. MarkLogic sets the default function namespace to the "fn" namespace for main modules, but for library modules, the default function namespace is set to the module namespace. The nice thing about this is that, in library modules, you aren't immediately forced to use a prefix on the functions that you define:

declare function my-function() { … };

On the other hand, this means that you need to use the "fn:" prefix on any calls you make to the built-in XPath functions. So a typical scenario is that "collection()" works fine in your main module, but you have to write "fn:collection()" in your library module. This can get annoying if, say, you decide you want to re-use some of the code in your main module by moving it to a library module. Cut-and-paste doesn't cut it; you'll have to add "fn:" in a bunch of places. I think we can all agree that this is a sea of troubles worth taking arms against.

The question is how you want to deal with it. I see two general approaches to avoiding the above pain:

  1. Always use the "fn:" prefix, OR
  2. Explicitly declare the "fn" namespace as the default function namespace in library modules, so you never have to use the "fn" prefix.

Both methods are safe, so it largely comes down to personal preference. One thing to note about #2 is that you'll need to start using a prefix on your own module function definitions and function calls (something you have to do anyway when you're calling them from elsewhere). If we really wanted to argue about it, I could give other reasons for one or the other (my preference is #2), but I'll leave that discussion to the comments (bring it on!), lest the native hue of resolution be sicklied o'er...

Before I leave you, I want to make sure you know how to accomplish #2 and forever rid yourself of the need of remembering to type "fn:". Just put the following boilerplate in the prolog of each of your library modules:

declare default function namespace "http://www.w3.org/2005/xpath-functions";

Happy coding!

Comments

  • It appears that MarkLogic now allows you to call the built-in functions without the "fn" prefix, even in library modules where you haven't declared the "xpath-functions" namespace as the default (more precisely, where you have no default function namespace declaration at all). I know it's working that way in ML 7; I don't know which version introduced the behavior. The behavior now appears to be this: if you have not explicitly declared a default function namespace, then, for an unprefixed function call, MarkLogic will first try to find a function with that name among the library module's function definitions, and, failing that, will then try to find a built-in function with that name. However, if you have explicitly declared a default function namespace, it will still enforce that. (Doing so for "xpath-functions" is still a good idea, now to prevent unforeseen clashes with user-defined function names.)
    • I've just tried it with ML-6 and there the automatic resolving of fn functions does not work. So this behavior must have been introduced with ML-7.
  • Good post, Evan. Personally, I prefer #1, mostly for the sake of consistency. As you point out, the default function namespace can vary depending on the situation, and whether I'm reading or writing I don't want to be bothered thinking about what it is in the current module. By always using the prefix, it's always clear. 
    • Thanks, Dave. Various reasons I prefer #2: * more interoperable code (rather than relying on an implementation default which could cause your code to break without an explicit declaration) * less cluttered, easier to read code * many years of habit writing XSLT * consistency with my ongoing habit of writing XSLT * adding the declaration to my editor's template for .xqy files means I never have to remember the namespace URI Reasons one might prefer #1: * sometimes you have to edit other people's code, say, if you're on a team, and you don't have control over the default function namespace * you don't have to prefix your own module's function declarations and calls Fortunately, the processor will let me know right away if I need to type "fn:" when editing other people's code. And in the latter case, since each module usually has a unique namespace, I'll still have to prefix my user-defined function calls when I'm calling from within another module. So, for me, the reasons for #2 far outweigh the reasons for #1. :-)
  • Gists 2 and 4 are showing a funny character at my end (a small square). Was that intended as a hellip character?