PDA

View Full Version : undefined keywords



hcrisp
10-24-2008, 11:49 AM
How do I determine inside a function if a keyword was defined or not? Using PARAM_PRESENT seems to give false positives.

For example, if my function was:

PRO myfunction, MYKEY=mykey
IF PARAM_PRESENT(mykey) THEN PRINT, 'mykey is present' $
ELSE PRINT, 'mykey is not present'
END

and I make the following calls, I get:

WAVE> info, junk
JUNK UNDEFINED = <Undefined>
WAVE> myfunction, MYKEY=junk
%%%Compiled module: MYFUNCTION.
mykey is present

MYKEY may be present, but it isn't defined!

rwagner
10-24-2008, 03:39 PM
Take a look at KEYWORD_SET:

With KEYWORD_SET
The KEYWORD_SET function returns FALSE when:
1.
the keyword is set to zero or an undefined variable.
2.
the keyword is not used in the call.

PARAM_PRESENT distinguishes between these cases by returning TRUE in case 1 and FALSE in case 2.

hcrisp
10-27-2008, 11:32 AM
KEYWORD_SET will not work in cases where 0 is passed as the mykey value and I first need to check if the key was defined. I.e., take following two cases:

Case 1:
WAVE> myfunction, MYKEY=0

Case 2:
WAVE> info, junk
JUNK UNDEFINED = <Undefined>
WAVE> myfunction, MYKEY=junk

In both cases KEYWORD_SET returns false.
In both cases PARAM_PRESENT returns true.

I don't think there is a function that tells me if the keyword was both present and defined. SIZE will tell me if it is defined, but not if it was present. Catch-22!

allan
10-27-2008, 12:22 PM
> KEYWORD_SET will not work in cases where 0 is passed
> as the mykey value and I first need to check if the key
> was defined.

in this case you can do:
if n_elements(mykey) ne 0 then if mykey ne 0 then . . .

allan

hcrisp
03-12-2009, 08:04 AM
I have a follow-up question for this post which may be confusing. I hope I don't lose you. My question is, what is the most straightforward way to write a wrapper around a PV-WAVE function, especially one that has many keywords? I would like to think I can just call the PV-WAVE function with all keywords specified, and if they are undefined, then it will treat them accordingly. Sadly, this is not the case.

For example, say I write a wrapper like this:


FUNCTION myfirfilt, h, x, OFFSET=offset
result = FIRFILT(h, x, OFFSET=offset)
RETURN, result
END

I don't get the right result if I omit the keyword offset in the call, like so:


x = ((indgen(1024)+64) MOD 256) GT 128
h = firdesign(101, 0.1, /lowpass)
plot, myfirfilt(h, x)
oplot, firfilt(h, x), color=230 ; notice the 2 curves are not the same!


I believe this is because FIRFILT() is checking if OFFSET is PARAM_PRESENT and not if it is undefined. So instead of a one-line call in the wrapper, do I have to write a bunch of CASE statements or construct a string call and use EXECUTE? Neither way would be an elegant way to code it.

donb
03-12-2009, 11:42 AM
When writting PV-WAVE routines, it's the responsibility of the called routine (procedure or function) to see if a value is passed for a specific keyword, and to set a default value if it's not passed by the caller.

As such, you should modify your code to be:

FUNCTION myfirfilt, h, x, OFFSET=offset
IF NOT KEYWORD_SET(offset) THEN offset=default_value
result = FIRFILT(h, x, OFFSET=offset)
RETURN, result
END

There is no need for CASE statements or building EXECUTE strings for this type of parameter checking.

Hope this helps,

Don B.

hcrisp
03-12-2009, 01:18 PM
DonB,

I see two problems with your answer.

First, if I pass OFFSET=0, then that code will erroneously assign default_value to offset instead of using 0.

Second, on a general level, this may require unnecessary duplication of code. In this case if OFFSET is not included as a keyword, FIRFILT by default sets it to N_ELEMENTS(h.b)/2. One extra line of code. But other functions may go to a lot more work when a keyword is not defined. Think 50 lines of code. Why would I want to duplicate it outside the function call?

Doesn't it make more sense to change FIRFILT to check if OFFSET is defined?

allan
03-12-2009, 08:32 PM
good catch, hcrisp;

in firfilt.pro offset was processed like:

IF KEYWORD_SET(offset) THEN shft = LONG(offset(0)) $
ELSE shft = length_filt/2
IF param_present(offset) AND (NOT KEYWORD_SET(offset)) THEN shft = 0

this is more complicated than is necessary and gives the
wrong result if offset is present but undefined;

this problem is fixed in the development version of
pv-wave, and the fix will be in the next full release;
in the meantime you can implement the fix yourself by
replacing the above code block with

IF N_ELEMENTS(offset) THEN shft = LONG(offset(0)) $
ELSE shft = length_filt/2

notice that n_elements is all that is required to process
this keyword; n_elements is always the simplest way to design keyword processing: if the keyword is undefined
or not equal to the correct number of elements then the
default action is taken; then wrapper code can use the
same keywords, just like you expected:

FUNCTION myfirfilt, h, x, OFFSET=offset
result = FIRFILT(h, x, OFFSET=offset)
RETURN, result
END

if a routine processes its keywords with something other than n_elements then wrapper code must usually build a
string containing the command to execute(); for example
see wave/lib/std/contourfs.pro;

hcrisp
03-13-2009, 08:51 AM
Thanks, Allan. I will make using N_ELEMENTS the best practice of writing lower-level functions so they can be extended easily with wrappers. I was thinking of writing a PARAM_DEFINED() which calls SIZE, but N_ELEMENTS is straightforward enough.

Thanks for the contourfs.pro reference as well. That is what I thought I would have to do in cases where the function wasn't written with extensibility in mind. (Of course, if you guys in VNI could clean up the badly-written code, that would be great too!)

allan
03-13-2009, 10:13 AM
you are welcome, hcrisp;
i should point out that interpreter efficiency may be the
reason that kernel routines do not use wrapper-friendly
keyword logic; the pv-wave interpreter has low-overhead
relative to some other language interpreters, and this is
partly attributable to the sacrifice of some convenience for
speed;