I've been looking at this source code provided by developers of a library called libuv. In some of the example code they pass a function as a parameter for another function but none of the required parameters are passed. How are the parameters being filled out? The function I'm looking at is uv_fs_open.
Here is the link to the source (look around line 1000 for the function code): https://github.com/libuv/libuv/blob/202195c2f45ced200ccf880ff4502eee94f11ab5/src/unix/fs.c
Here is the example code:
int main() {
loop = uv_default_loop();
int r = uv_fs_open(loop, &open_req, path, O_RDONLY, S_IRUSR, open_cb);
if (r) {
fprintf(stderr, "Error at opening file: %s.\n",
uv_strerror(uv_last_error(loop)));
}
uv_run(loop, UV_RUN_DEFAULT);
return 0;
}
void open_cb(uv_fs_t* req) {
int result = req->result;
if (result == -1) {
fprintf(stderr, "Error at opening file: %s.\n",
uv_strerror(uv_last_error(loop)));
}
uv_fs_req_cleanup(req);
uv_fs_read(loop, &read_req, result, buf, sizeof(buf), -1, read_cb);
}
libuv uses a pattern called callback baton for its async functions. The rationale is very simple: let's assume you want to do something asynchronously. So you pass a callback function as a function pointer to call when it's done. libuv's functions do their job asynchronously and call the function you specified when they're done.
However, if you have more than one places where you call these functions, once the callback is called, you are going to need to tell which request the callback is called for. That is the purpose of the baton object. In the case of your example code, that's the open_req
variable (of the type uv_fs_t
).
You can read more about libuv's file system operations here.