Entries in :: (5)

How do I execute a q function call with parameters over IPC?

Short answer:

q)phandle: hopen `:serverhost:5012
q)phandle (function; arg1; arg2 ..)
..
q)hclose phandle
q)


To invoke a function in another q process (i.e., a function that already exists in that q process), you need the following:

  1. a process handle to the other q process,
  2. the name of the pre-existing function in the other process, and
  3. the parameters you want to pass.

Then all you need to do is to apply the process handle to a list whose first element is the function name (as a symbol) and whose remaining elements are the arguments.

For example, let's start one q process, which will be our server, listening on TCP port 5012. In our server, we'll define a function square (we'll make the background color different for the server to make it easier to distinguish from the client):

$ q -p 5012             // server
..
q)\p                    // display the listening port
5012
q)square: {x * x}
q)square 3
9
q)

Next, we'll start up another q process (the client), create a process handle connected to the first q process (the server), and request the first process to compute square 5:

$ q                     // client
..
q)phandle: hopen `:localhost:5012
q)phandle (`square; 5)  // remote execution
25
q)

To call a function with more parameters, simply add them to the end of the list. We'll demonstrate by defining a 2-argument function on the server that calculates the length of a right triangle's hypotenuse:

q)hypotenuse: {sqrt sum square x,y}
q)hypotenuse[3;4]
5f
q)
q)phandle (`hypotenuse; 5; 12)
13f
q)

What if the function you're calling doesn't take any parameters? For example, we'll define a function in the server called serverTime that returns the local time according to the server:

q)serverTime: {[] .z.T}
q)serverTime[]
11:51:34.762
q)

You can't pass zero parameters over IPC:

q)phandle enlist `serverTime  // a list with just
'length                       // the function name
q)                            // is not allowed

However, you can pass whatever you like, and it won't matter:

q)phandle `serverTime`ignored
11:52:28.537
q)phandle (`serverTime; ())    // () is often used
11:52:40.923
q)phandle (`serverTime; ::)    // so is ::
11:52:47.338
q)

See :: (generic null).

So far, all of our examples involved a client invoking a predefined function on the server. You can also pass a function defined on the client to be executed on the server. To see this, let's define a global variable on the server:

q)SERVERGLOBAL: 47
q)

Now, on the client, we'll define a function called getSERVERGLOBAL to retrieve the value of SERVERGLOBAL on the server. Instead of passing the name of the function (i.e., `getSERVERGLOBAL), we pass the function's value:

q)getSERVERGLOBAL: {[] SERVERGLOBAL}
q)getSERVERGLOBAL[]
'SERVERGLOBAL                   // not defined here
q)phandle (getSERVERGLOBAL; ::) // note the missing `
47
q)

Notice that this operation does not cause getSERVERGLOBAL to become defined on the server:

q)getSERVERGLOBAL
'getSERVERGLOBAL
q)

This technique can be used to run built-in functions and anonymous functions (aka lambdas) on the server as well:

q)phandle (+; 2; 4)
6
q)phandle ({til SERVERGLOBAL - x}; 42)
0 1 2 3 4
q)

There is one more way to convey code to the server to run: you can pass the code in a string.

q)phandle "SERVERGLOBAL + 4"
51
q)

We prefer passing a function over a string, because - especially as the expression to be passed gets more complex - it's easier to read.

How do I set a breakpoint inside a q function?

Consider the following function, testfunc:

testfunc: {[]
x: `aaa;
y: `bbb;
z:: `ccc;
-1 "finished!";
}

Let's demonstrate the placement of a breakpoint prior to the assignment of global variable z. Although there is no explicit support for breakpoints in q, insertion of non-compliant code, such as breakhere; shown below, does the job (don't forget the trailing semicolon):

testfunc: {[]
x: `aaa;
y: `bbb;
breakhere;
z:: `ccc;
-1 "finished!"
}

We are tricking q into throwing a signal 'breakhere.

q)testfunc[]
{[]
x: `aaa;
y: `bbb;
breakhere;
z:: `ccc;
-1 "finished!"
}
'breakhere
q))

At this point, we can examine the local stack.

q))x
`aaa
q))y
`bbb
q))z
()
q))

kdb has suspended execution, leaving the remaining two lines of function testfunc unexecuted. : (colon) resumes execution.

q)):
finished!
-1
q)x
'x
q)y
'y
q)z
`ccc
q)

See: global amend (::)

How do I set the return value of a function?

Short answer:      : return_value

Unless you use : (return) or ' (signal) to specify otherwise, a q function returns the value of its last expression. Since functions are lists of expressions separated by semicolons, both of the following functions return 3:

q)single_expression: {3}
q)single_expression[]
3
q)last_expression: {1; 2; 3}
q)last_expression[]
3
q)

To return a value other than that of the last expression, use : (return):

q)explicit_return: {: 3; 4}
q)explicit_return[]
3
q)

The last expression in explicit_return (i.e., 4) is never reached.

Meanwhile, if a function that does not return via : (return) (or ' (signal)) does not have a final expression (i.e, no expression after its last semicolon), that function returns a generic null:

q)no_return: {3; }
q)no_return[]
q)null no_return[]
1b
q)type no_return[]
101h
q)no_return[] ~ (::)
1b
q)

Lastly, functions can exit in two other ways:

1. Calling the exit function:

q)die: {exit 0}
q)die[]
$

(By the way, you can add code to run automatically at exit using .z.exit.)

2. Signaling an error:

q)signal: {' "oops"}
q)signal[]
'oops
q)

See this related faq for more information on the use of ' (signal)

Given a value, how do I get the null of that value's type?

We take advantage of a property of q's indexing: If you request an item from a list (or a dictionary, for that matter) using an index that is out of range, q returns the null item for the list's type.

q)x: 1 2 3
q)x 3
0N
q)

Thus, we can take the item whose corresponding null we want, make a list from it, and then access that list with an out-of-range index:

q)NullOf: {[item] enlist[item] 1}
q)NullOf 1
0N
q)(::) ~ NullOf {x*x}
1b
q)null NullOf (.z.D; 1e; " "; type "foo")
1111b
q)

Remember, there is no null list. If you pass a list to NullOf, you get the empty list of the corresponding type:

q)NullOf 1 2 3
`int$()
q)

See also: .Q.ty

I’ve setup many views based on a single large table. How much of a performance penalty will I pay?

A view is syntactic sugar for a canned query. Unless the view is referenced, it does not expend computational resources.

See also: view, views, :: , .z.b and \b