If you really want to know wether a WordPress Query Var is set or not, you need to check directly for it.
All set query vars are stored into a global accessible array of the WP_Query class.
It has a default instance that is bound to the global $wp_query variable. With that in mind it is possible to create a qv_isset() function that is working precicesly:
function qv_isset($var_name) {
$array = $GLOBALS['wp_query']->query_vars;
return array_key_exists($var_name, $array);
}
What makes this so easy is that array_key_exists() returns true or false.
Normally to test any PHP variable if it is set or not, you can use isset(). But it has a shortcoming: If a variable is NULL, it will say that it is not set - even if it is. Comparable to what has been written about empty() here as well, it will say comparably for '' (empty string), NULL, 0 etc. .
Anyway, we do not need to rely on that function to check wether or not a queryvar has been set as we can make use of array_key_exists() here.
Now for your code:
function qv_get($var_name, $default = null) {
return qv_isset($var_name) ? get_query_var($var_name) : $default;
}
mcs_textbook_chapter($dialect, qv_get('cls'), qv_get('ch'));
Or with other words: If your function already has (that many) optional parameters, take a look how you can best feed it. Unset variables are NULL (like said above with isset()), so this is useful to pass them as unset optional parameters as well.