Changing qualifiers before passing them on

From Remeis-Wiki
Jump to navigation Jump to search

changing qualifiers before passing them on

In S-Lang (and thus also isis) it is possible to pass options to functions as qualifiers rather than arguments. This is useful, e.g., if you only want to specify certain options sometimes and use a predefined value else.

Defining a function, qualifiers can be used as (from the [help for "qualifier"])LINK DOES NOT EXIST ANYMORE? :

define echo (text)
{
   variable fp = qualifier ("out", stdout);
   () = fputs (text, fp);
}
echo ("hello");              % writes hello to stdout
echo ("hello"; out=stderr);  % writes hello to stderr

To pass a bunch of qualifiers as a single struct instead of comma separated set of name-value pairs, you need to let the parser know that you are using a structure-valued argument. Use a double semicolon to do so:

variable quals = struct{ out=stderr };
echo("hello";; quals);

Sometimes it is just useful to switch the behavior of a function via a qualifier without a value (or the NULL value) by just checking for its existence via qualifier_exists("qualifier_name") (again from the S-Lang help):

define echo (text)
{
   variable fp = stdout;
   if (qualifier_exists ("use_stderr"))
     fp = stderr;
   () = fputs (text, fp);
}
echo ("hello"; use_stderr);  % writes hello to stderr

Qualifiers can also be passed on from one function to another function that is called in the definition: __qualifiers() returns the active set of qualifiers as a structure. You can just use it directly with a double semicolon to pass the qualifiers as shown above:

define line_segment (x0, y0, x1, y1)
{
   moveto (x0, y0);
   lineto (x1, y1 ;; __qualifiers());
}

So any qualifier specified in line_segment is directly passed to lineto.


But what if you want to modify some of the qualifiers first? Just use [[1]] (or the equivalent dereference operator) and take advantage of the facts that

  • it is NULL-safe and
  • more than one structure may have the same field name, in which case the value is given by the last structure:
define get_pixel_array(dat, gainf, range)
{
   variable pix = qualifier("pixel", [0:31]);
   variable arr = Struct_Type[length(pix)];
   variable i;
   _for i(0, length(arr)-1)
      arr[i] = vtoen(dat, gainf, range;; struct { @__qualifiers(), pixel=[pix[i]] });
   return arr;
} 

More complicated solution: Just save the structure returned by the function __qualifiers() into a variable, change/add/remove fields in that structure and then pass the new structure on. But be careful not to produce errors if no qualifier is used:

define get_pixel_array(dat, gainf, range)
{
   variable pix = qualifier("pixel",[0:31:1]);
   variable arr = Struct_Type[length(pix)];
   variable i;
   
   variable qual = __qualifiers();
   if (typeof(qual) == Null_Type){ % if there are no qualifiers, there also is no struct
      qual = struct{pixel};
   }else if (struct_field_exists(qual,"pixel") == 0){
      qual=struct_combine(qual, "pixel");
   }

   _for i(0,length(arr)-1,1)
   {
      qual.pixel=[pix[i]];
      arr[i] = vtoen(dat,gainf,range;; qual);
   }
   return arr;
} 

Usually, it would probably be easier to change the original function but for example in this case for just a quick trouble shooting, I did not want to mess around with my function vtoen, which usually takes the qualifier pixel to know which pixels to sum up after gain correction. However, if you want an array of all individual pixels instead, i.e., loop through the entries in pixel while leaving other qualifiers untouched, the presented option is a quick workaround to still be able to access the other possible qualifiers (as, e.g., time or flag filtering).

If you want to look at how the struct for qualifiers looks like, you can do:

define qual(){ return __qualifiers(); }
variable test = qual(;noval, someval=1, anarray=["a","b"]);
print(test);