Riddle 4 Answer
So apparently this is an annual series now…
Anyway, Dan Nugent and Akash were both on the right track, but neither had it exactly right: when a
qsql
query inside a function is executed, relative names used in it resolve against globals in the current namespace, not the namespace that was in effect when the function was created (i.e. the one returned by running {(get x). 3 0}
on the function).(Note that this actually applies to any type of global (e.g. an atom, a vector, etc.) referenced from a query inside a function, but for convenience, I’ll be writing this post assuming a function is what’s being referenced.)
I will admit to making this a bit of a trick question, as the way I constructed the example was designed around the most common case, which is entirely consistent with Dan’s and Akash’s answers. Here's a snippet showing the full behavior:
Compare to this snippet, where I reference the function from outside the% q KDB+ 3.3 2015.09.02 Copyright (C) 1993-2015 Kx Systems m32/ 16()core 8192MB adavies aaron-daviess-mac-pro.local 192.168.1.151 NONEXPIRE q)f:{x+1} q)\d .foo q.foo)g:{select f a from x} q.foo)\d .bar q.bar).foo.g([]a:1 2 3) {select f a from x} 'f q.foo))\ q.bar)f:{x+2} q.bar).foo.g([]a:1 2 3) a - 3 4 5 q.bar)
qsql
query:This can become problematic if you try to create a group of functions in a namespace, some of which reference each other in queries, and then call those functions from outside that namespace. I’ve found two solutions for this, both unfortunately rather inelegant.% q KDB+ 3.3 2015.09.02 Copyright (C) 1993-2015 Kx Systems m32/ 16()core 8192MB adavies aaron-daviess-mac-pro.local 192.168.1.151 NONEXPIRE q)\d .foo q.foo)f:{x+1} q.foo)g:{f select a from x} q.foo)\d . q).foo.g([]a:1 2 3) a - 2 3 4 q)
- You can “copy” the function you need from the global space to a local variable by referencing it from outside any
qsql
queries:% q KDB+ 3.3 2015.09.02 Copyright (C) 1993-2015 Kx Systems m32/ 16()core 8192MB adavies aaron-daviess-mac-pro.local 192.168.1.151 NONEXPIRE q)\d .foo q.foo)f:{x+1} q.foo)g:{f0:f;select f0 a from x} q.foo)\d . q).foo.g([]a:1 2 3) a - 2 3 4 q)
- You can do the name resolution yourself, by leveraging the
get
results to automatically reference the correct namespace:% q KDB+ 3.3 2015.09.02 Copyright (C) 1993-2015 Kx Systems m32/ 16()core 8192MB adavies aaron-daviess-mac-pro.local 192.168.1.151 NONEXPIRE q)\d .foo q.foo)f:{x+1} q.foo)g:{select((` sv`,((get .z.s). 3 0))`f)a from x} q.foo)\d . q).foo.g([]a:1 2 3) a - 2 3 4 q)
% q KDB+ 3.3 2015.09.02 Copyright (C) 1993-2015 Kx Systems m32/ 16()core 8192MB adavies aaron-daviess-mac-pro.local 192.168.1.151 NONEXPIRE q)\d .util q.util)r:{(` sv`,((get x). 3 0))y} q.util)\d .foo q.foo)f:{x+1} q.foo)g:{select((.util.r .z.s)`f)a from x} q.foo)\d . q).foo.g([]a:1 2 3) a - 2 3 4 q)
Labels: riddle, riddle answer, tip