Keyword inheritance allows IDL routines to accept keyword parameters not defined in their function or procedure declaration and pass them on to the routines that they call. Routines are able to accept keywords on behalf of the routines they call without explicitly processing each individual keyword. The resulting code is simple, and requires significantly less maintenance. Keyword inheritance is of particular value when writing:
There are two steps required to use keyword inheritance in an IDL routine:
When using keyword inheritance, the following points should be kept in mind:
As described above, there are two possible mechanisms used by IDL to pass inherited keywords. The one used by a routine is determined by the formal parameter list of the routine.
You can cause inherited keyword parameters to be passed to a routine by value by adding the keyword parameter _EXTRA to the formal argument list of that routine. Passing parameters by value means that you are giving the called routine a copy of the value of the passed parameter, and not the original. As such, any changes made to the value of such a keyword is not passed back to the caller.
When a routine is defined with the formal keyword parameter _EXTRA, and keywords that are not recognized by that routine are passed to it in a call, IDL constructs an anonymous structure to contain the keyword inheritance information. Each tag in this structure has the name of an inherited keyword, and the value of that tag is a copy of the value that was passed to that keyword. If no unrecognized keywords are passed in a call, the value of the _EXTRA keyword will be undefined, indicating that no inherited keyword parameters were passed.
If extra keyword parameters have been passed by value, their values are stored in an anonymous structure. The inheriting routine has the opportunity to modify these values and/or to filter them prior to passing them to another routine. The CREATE_STRUCT, N_TAGS, and TAG_NAMES functions can all be of use in performing such operations. For example, here is an example of adding a keyword named COLOR with value 12 to an _EXTRA structure:
PRO SOMEPROC, _EXTRA = ex
if (N_ELEMENTS(ex) NE 0) $
THEN ex = CREATE_STRUCT(’COLOR’, 12, ex) $
ELSE ex = { COLOR : 12 }
SOME_UNDERLYING_PROC, _EXTRA=ex
END
The use of N_ELEMENTS is necessary because if the caller does not supply any inherited keyword, the variable EX will have an undefined value, and an attempt to use that value with CREATE_STRUCT will cause an error to be issued. Hence, we only use CREATE_STRUCT if we know that inherited keywords are present.
You specify that a routine accepts inherited keywords by reference, by adding the keyword _REF_EXTRA to the formal argument list of the routine. When a routine is defined with _REF_EXTRA, inherited keywords are passed using IDL’s standard parameter passing mechanism, as with any other variable. Unlike regular variables however, the values of these keywords are not available within the routine itself. Instead, the names of these keywords are passed as a string array to the routine as the value of the _REF_EXTRA keyword. The presence of a name in the _REF_EXTRA value indicates that a keyword of that name was passed, and its value is available to be passed on in a function or procedure call (using either _EXTRA or _STRICT_EXTRA). If no unrecognized keywords are passed in a call, the value of the _EXTRA keyword will be undefined, indicating that no inherited keyword parameters were passed.
If inherited keywords passed by reference are modified by a called routine, those changes will be passed back to the caller.
The pass by reference keyword inheritance mechanism is especially useful when writing object methods.
If extra keyword parameters have been passed by reference, you can direct different inherited keywords to different routines by specifying a string or array of strings containing keyword names via the _EXTRA keyword. For example, suppose that we write a procedure named SOMEPROC that passes extra keywords by reference:
PRO SOMEPROC, _REF_EXTRA = ex
ONE, _EXTRA=['MOOSE', 'SQUIRREL']
TWO, _EXTRA='SQUIRREL'
END
If we call the SOMEPROC routine with three keywords:
SOMEPROC, MOOSE=moose, SQUIRREL=3, SPY=PTR_NEW(moose)
The two available keyword inheritance mechanisms have different strengths and weaknesses. The one to choose depends on the requirements of your routine:
One of the most common uses for the keyword inheritance mechanism is to create wrapper routines that extend the functionality of existing routines. This example shows how to write such a wrapper, using both available inheritance mechanisms.
In most wrapper routines, there is no need to return modified keyword values back to the calling routine — the aim is simply to provide the complete set of keywords available to the existing routine from the wrapper routine. Hence, the by value form (_EXTRA) of keyword inheritance can be used.
For example, suppose that procedure TEST is a wrapper to the PLOT procedure. The text of such a procedure is shown below:
PRO TEST, a, b, _EXTRA = e, COLOR = color
PLOT, a, b, COLOR = color, _EXTRA = e
END
This wrapper passes all keywords it does not accept directly to PLOT using keyword inheritance. If such a keyword is not accepted by the PLOT procedure, it is quietly ignored. If you wish to catch such errors, you would re-write TEST to use the _STRICT_EXTRA keyword in the call to PLOT:
PRO TEST, a, b, _EXTRA = e, COLOR = color
PLOT, a, b, COLOR = color, _STRICT_EXTRA = e
END
This definition of the TEST procedure causes unrecognized keywords (any keywords other than COLOR) to be placed into an anonymous structure assigned to the variable e. If there are no unrecognized keywords, e will be undefined.
For example, when procedure TEST is called with the following command:
TEST, x, y, COLOR=3, LINESTYLE = 4, THICK=5
variable e, within TEST, contains an anonymous structure with the value:
{ LINESTYLE: 4, THICK: 5 }
These keyword/value pairs are then passed from TEST to the PLOT routine using the _EXTRA keyword:
PLOT, a, b, COLOR = color, _EXTRA = e
Note that keywords passed into a routine via _EXTRA override previous settings of that keyword. For example, the call:
PLOT, a, b, COLOR = color, _EXTRA = {COLOR: 12}
specifies a color index of 12 to PLOT.
It is extremely simple to modify the by value (_EXTRA) version of the TEST procedure from the previous section to use by reference keyword inheritance. It suffices to change the _EXTRA keyword to _REF_EXTRA in the formal parameter list:
PRO TEST, a, b, _REF_EXTRA = e, COLOR = color
PLOT, a, b, COLOR = color, _STRICT_EXTRA = e
END
This definition of the TEST procedure causes unrecognized keywords (any keywords other than COLOR) to be passed to PLOT using the normal IDL parameter passing mechanism. However, their values are not visible within TEST itself. Instead, a string array containing the inherited keyword names is assigned to the variable e. If there are no unrecognized keywords, e will be undefined.
For example, when procedure TEST is called with the following command:
TEST, x, y, COLOR=3, LINESTYLE = 4, THICK=5
variable e, within TEST, contains an anonymous structure with the value:
[ ‘LINESTYLE‘, ‘THICK‘ ]
These inherited keywords are then passed from TEST to the PLOT routine using the _EXTRA keyword. Note that keywords passed into a routine via _EXTRA override previous settings of that keyword. For example, the call:
PLOT, a, b, COLOR = color, _EXTRA = {COLOR: 12}
specifies a color index of 12 to PLOT. Also note that we are passing a structure (the by value format used by _EXTRA) as the value of the extra keyword to a routine that uses the by reference keyword inheritance mechanism (_REF_EXTRA). There is no problem in doing this, because each routine establishes its own inheritance mechanism independent of any other routines that may be calling it. However, any keyword values that are changed within PLOT will fail to be returned to the caller due to the use of the by-value mechanism.
The pass by reference keyword inheritance mechanism allows you to change the value of a variable in the calling routine’s context from within the routine, whereas the pass by value mechanism does not. To demonstrate this difference between _EXTRA and _REF_EXTRA, consider the following simple example procedures:
PRO HELP_BYVAL, _EXTRA = ex
HELP, _EXTRA = ex
END
PRO HELP_BYREF, _REF_EXTRA = ex
HELP, _EXTRA = ex
END
Both HELP_BYVAL and HELP_BYREF are simple wrappers to the HELP procedure. The HELP procedure accepts a keyword named OUTPUT that passes back a value to the caller. Observe the result when we call each wrapper, specifying OUTPUT as an inherited keyword parameter:
HELP_BYVAL, OUTPUT = out & HELP, out
IDL prints:
% At HELP_BYVAL 2 /dev/tty
% $MAIN$
EX UNDEFINED = <Undefined>
Compiled Procedures:
$MAIN$ HELP_BYVAL
Compiled Functions:
OUT UNDEFINED = <Undefined>
This occurs because the HELP call within HELP_BYVAL is passed a variable that cannot be used to return a value, due to the use of by value keyword inheritance. It therefore reverts to the default of writing to the user’s screen, and no value is returned to the caller for the OUTPUT keyword.
Now run HELP_BYREF:
HELP_BYREF, OUTPUT = out & HELP, out
IDL prints:
OUT STRING = Array[8]
HELP_BYREF returns the value of the HELP OUTPUT keyword as desired.