When variables are first created, their values are 0 unless otherwise set. When strings are first created, they are NULL. This sometimes throws an error should the coding not be carefully done.
Helpful would be when strings by default are created as "empty" (equivalent to string SomeStr="") in analogy to variable SomeVar=0 (default).
On the face of it this seems perfectly reasonable. This could cause some hassle in developing xops though. In C there is a difference between:
char *msStr = NULL;
and
char *msStr = 0x1234567;
where that memory address has zero length. One often tests for whether an C operation has succeeded by testing for non NULLness of the pointer, not whether the memory area pointed to by the pointer has zero length. One form has no information, the other has information (just not a lot).
Also, it may be a big igor language change, possibly breaking pre-existing code.
On the face of it this seems perfectly reasonable. .....
One wonders why such things are not the same with variables then? Consistency seems a bit off.
Anyway, unlike in XOP coding, testing for NULL strings AFAIK is generally atypical of Igor coding (versus testing for empty strings), perhaps a compromise would be that NULL Igor strings be flagged as errors at compile time, rather than waiting until run-time to generate an error. This would go directly to the heart of my concerns.
In addition, recommending that newly created strings be designated with something at creation, even if an empty value "", would seem be a good point to emphasize about doing proper Igor coding.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
One wonders why such things are not the same with variables then? Consistency seems a bit off.
In C/C++, if you create a variable without assigning it a value, it will take the value of whatever the memory used by the variable has. Usually this value is nonsense. But since variables are an actual type (a double) they have to have some value (that is, they can't be null) and I suspect that Igor, and many other programming languages, initialize the value of variables to 0 to save some typing and because 0 is often a useful value for a variable to have.
jjweimer wrote:
Anyway, unlike in XOP coding, testing for NULL strings AFAIK is generally atypical of Igor coding (versus testing for empty strings), perhaps a compromise would be that NULL Igor strings be flagged as errors at compile time, rather than waiting until run-time to generate an error. This would go directly to the heart of my concerns.
Usually in Igor you don't have to worry too much about null strings. All (or at least most) Igor functions that return strings return an empty string or a non empty string, but not a null string. And when programmers create a string variable in code, they should assign it a value before using it. Usually a value of empty string is not very useful, so even if strings were initialized as empty I'm not sure how that would help prevent problems. Errors are good, in a sense, because they alert you of problems. If you didn't get an error, it might be a lot harder to track down bugs.
... Errors are good, in a sense, because they alert you of problems. If you didn't get an error, it might be a lot harder to track down bugs.
Good in a sense except when they are in an obscure portion of code that only runs on occasion and that one forgets to test thoroughly via run-time examples before distributing a package. :-)
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
I really wish I could pass the strings with null values. This would be useful in hierarchy of functions with optional string variables. For example:
function smith1([str]) string str
smith2(str) end
function smith2([str]) string str
str=selectstring(paramisdefault(str),str,"jones") print str end
This won't work because I can't call smith2 from within smith1 unless I have assigned a value to str in smith1. But that renders the paramisdefault check in smith2 useless. I could assign it a value like "", but that is different from null, and might subvert whatever smith2 is supposed to be doing. Anyone else had this problem?
Just came across this thread for an error I was getting. In testing whether a user had entered a string or not in a button action procedure I was using the following:
Function GIXS_BCnewSample(ba) : ButtonControl STRUCT WMButtonAction &ba
if(strlen(sampleName) == 0)// i.e. if no string was entered - user hits cancel return -1 endif
This strlen test doesn't pass as the string is null. I guess it is best practice to always define as String newString="". Perhaps there should be some kind of best practice section on the forum/in the manual for tips like this?
Tom
P.S. Am I right in thinking that I can also test the result with V_flag which is returned as 1 for cancel and 0 otherwise?
...
P.S. Am I right in thinking that I can also test the result with V_flag which is returned as 1 for cancel and 0 otherwise?
Yes, you can test for the pressed button, but a case where the user clicked ok while leaving the field blank will still result in an empty string which you have to test for if needed.
Somewhat related to your posted code: It seems you have a sophisticated panel code there with an action function using structures and stuff, and then you use a simple DoPrompt which BLOCKS all execution until it's gone? Seems a bit risky to me, especially since the the function gets executed on every possible occassion (even mouse movements) repeatedly. I usually write a simple panel instead (ends up to be about the same number of code lines) and let the code flow to handle other events while the user still decides whether he likes to interact with an annoying panel or not. ;)
Yes, you can test for the pressed button, but a case where the user clicked ok while leaving the field blank will still result in an empty string which you have to test for if needed.
Ah of course! I will leave it as the strlen.
chozo wrote:
It seems you have a sophisticated panel code there with an action function using structures and stuff, and then you use a simple DoPrompt which BLOCKS all execution until it's gone? Seems a bit risky to me, especially since the the function gets executed on every possible occassion (even mouse movements) repeatedly.
I happened to notice this in the debugger when I put my break point at the start of the function! Is there any reason that this happens? The case2: does only execute on button press though so it's fine, was your concern that I could have annoying dialogues popping up all the time?
chozo wrote:
I usually write a simple panel instead (ends up to be about the same number of code lines) and let the code flow to handle other events while the user still decides whether he likes to interact with an annoying panel or not. ;)
With all my panel controls I write a new procedure when making a dummy layout and usually opt for "Prefer structure-based" when, to be honest I am not sure what the benefits are over the simpler action procedure! Any guidelines for when you should use simple and when to use structure-based? (sorry to go off-topic!)
Then you should make sure to properly initialize the string. ;)
Quote:
I happened to notice this in the debugger when I put my break point at the start of the function! Is there any reason that this happens? The case2: does only execute on button press though so it's fine, was your concern that I could have annoying dialogues popping up all the time?
There are two ways of writing action functions at the moment, an ‘old-fashioned’ one (which may not be recommended by the Igor staff anymore) and a shiny one. The ‘old-fashioned’ way is to pass all parameters as strings, variables, etc. and work with this. In the case of a button, the only parameter is its name. It looks like this:
Function GIXS_BCnewSample(ctrlName) : ButtonControl String ctrlName
... End
The benefit (and the drawback) is that such an action function only will be invoked upon actually pressing that button and you don’t have to check for weird cases when this is the only thing you want. But you don’t get any informations passed into the function.
You have to use the structure approach when you want the function to be invoked in cases other than pressing the button and/or you need the additional information. You get all possible stuff from the structure, but the function will be executed when any of these things happen: Control being killed, Mouse down, Mouse up, Mouse up outside control, Mouse moved, Mouse enter, Mouse leave (see help), and actually pressing the button I think.
Since you first move your mouse around and then click or do some other stuff, the function will probably execute several times before your case 2 will come into play. Just have fun looking at numbers lining up with putting print ba.eventCode at the beginning. So, if you need all that, then you have to go this way. I personally use the structure approach very rarely because I usually like to keep these functions as small as possible.
Quote:
With all my panel controls I write a new procedure when making a dummy layout and usually opt for "Prefer structure-based" when, to be honest I am not sure what the benefits are over the simpler action procedure! Any guidelines for when you should use simple and when to use structure-based? (sorry to go off-topic!)
For the first part, see above. But when saying you should use a simple panel, I meant actually that you may want to write a small NewPanel with two controls or so instead of the DoPrompt. I’m not really sure what exactly is blocked and what is still possible, when igor waits for the DoPrompt, but I think this approach is prone to errors especially when you expect something to happen in the background (for example doing a calculation). You better stay away from this when using background functions. I had some funny moments in the past with DoPrompt and its evil brother PauseForUser.
This strlen test doesn't pass as the string is null.
For what it's worth, you can test for the presence of a null string variable by using strlen(). If the string is NULL, strlen() will return NaN, not 0. So you could do this:
String someString Variable length = strlen(someString) if(numtype(length) == 2) // someString is NULL elseif(length == 0) // someString is empty but not NULL else // someString is not empty endif
For what it's worth, you can test for the presence of a null string variable by using strlen(). If the string is NULL, strlen() will return NaN, not 0. So you could do this:
And, going a bit further, since *any* test involving a NaN returns false, if you invert the test you don't even have to have two parts for the "bad string" case:
For the first part, see above. But when saying you should use a simple panel, I meant actually that you may want to write a small NewPanel with two controls or so instead of the DoPrompt. I’m not really sure what exactly is blocked and what is still possible, when igor waits for the DoPrompt, but I think this approach is prone to errors especially when you expect something to happen in the background (for example doing a calculation). You better stay away from this when using background functions. I had some funny moments in the past with DoPrompt and its evil brother PauseForUser.
Yes, DoPrompt uses a modal dialog for it's input. And, indeed, that will stop background tasks and things like NIDAQ Tools MX getting fresh data from an acquisition. BUT- CtrlBackground has a keyword "dialogsOK" that allows you to tell Igor that it's OK to run your background task while dialogs (like the Simple Input Dialog) are up. Note that it can be dangerous- if your background task does something like killing a wave that the dialog is using, it can cause Igor to crash.
char *msStr = NULL;
and
char *msStr = 0x1234567;
where that memory address has zero length. One often tests for whether an C operation has succeeded by testing for non NULLness of the pointer, not whether the memory area pointed to by the pointer has zero length. One form has no information, the other has information (just not a lot).
Also, it may be a big igor language change, possibly breaking pre-existing code.
April 11, 2010 at 06:54 pm - Permalink
One wonders why such things are not the same with variables then? Consistency seems a bit off.
Anyway, unlike in XOP coding, testing for NULL strings AFAIK is generally atypical of Igor coding (versus testing for empty strings), perhaps a compromise would be that NULL Igor strings be flagged as errors at compile time, rather than waiting until run-time to generate an error. This would go directly to the heart of my concerns.
In addition, recommending that newly created strings be designated with something at creation, even if an empty value "", would seem be a good point to emphasize about doing proper Igor coding.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
April 12, 2010 at 06:58 am - Permalink
In C/C++, if you create a variable without assigning it a value, it will take the value of whatever the memory used by the variable has. Usually this value is nonsense. But since variables are an actual type (a double) they have to have some value (that is, they can't be null) and I suspect that Igor, and many other programming languages, initialize the value of variables to 0 to save some typing and because 0 is often a useful value for a variable to have.
Usually in Igor you don't have to worry too much about null strings. All (or at least most) Igor functions that return strings return an empty string or a non empty string, but not a null string. And when programmers create a string variable in code, they should assign it a value before using it. Usually a value of empty string is not very useful, so even if strings were initialized as empty I'm not sure how that would help prevent problems. Errors are good, in a sense, because they alert you of problems. If you didn't get an error, it might be a lot harder to track down bugs.
April 12, 2010 at 09:49 am - Permalink
Good in a sense except when they are in an obscure portion of code that only runs on occasion and that one forgets to test thoroughly via run-time examples before distributing a package. :-)
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
April 12, 2010 at 10:09 am - Permalink
string str
smith2(str)
end
function smith2([str])
string str
str=selectstring(paramisdefault(str),str,"jones")
print str
end
This won't work because I can't call smith2 from within smith1 unless I have assigned a value to str in smith1. But that renders the paramisdefault check in smith2 useless. I could assign it a value like "", but that is different from null, and might subvert whatever smith2 is supposed to be doing. Anyone else had this problem?
April 12, 2010 at 12:44 pm - Permalink
STRUCT WMButtonAction &ba
switch( ba.eventCode )
case 2: // mouse up
String sampleName
Prompt sampleName, "Enter sample name"
DoPrompt "Sample Name", sampleName
if ( strlen(sampleName) == 0 ) // i.e. if no string was entered - user hits cancel
return -1
endif
This
strlen
test doesn't pass as the string is null. I guess it is best practice to always define asString newString=""
. Perhaps there should be some kind of best practice section on the forum/in the manual for tips like this?Tom
P.S. Am I right in thinking that I can also test the result with V_flag which is returned as 1 for cancel and 0 otherwise?
March 15, 2012 at 05:59 am - Permalink
Yes, you can test for the pressed button, but a case where the user clicked ok while leaving the field blank will still result in an empty string which you have to test for if needed.
Somewhat related to your posted code: It seems you have a sophisticated panel code there with an action function using structures and stuff, and then you use a simple DoPrompt which BLOCKS all execution until it's gone? Seems a bit risky to me, especially since the the function gets executed on every possible occassion (even mouse movements) repeatedly. I usually write a simple panel instead (ends up to be about the same number of code lines) and let the code flow to handle other events while the user still decides whether he likes to interact with an annoying panel or not. ;)
March 15, 2012 at 07:50 am - Permalink
Ah of course! I will leave it as the strlen.
I happened to notice this in the debugger when I put my break point at the start of the function! Is there any reason that this happens? The
case 2:
does only execute on button press though so it's fine, was your concern that I could have annoying dialogues popping up all the time?With all my panel controls I write a new procedure when making a dummy layout and usually opt for "Prefer structure-based" when, to be honest I am not sure what the benefits are over the simpler action procedure! Any guidelines for when you should use simple and when to use structure-based? (sorry to go off-topic!)
March 15, 2012 at 10:10 am - Permalink
Then you should make sure to properly initialize the string. ;)
There are two ways of writing action functions at the moment, an ‘old-fashioned’ one (which may not be recommended by the Igor staff anymore) and a shiny one. The ‘old-fashioned’ way is to pass all parameters as strings, variables, etc. and work with this. In the case of a button, the only parameter is its name. It looks like this:
String ctrlName
...
End
The benefit (and the drawback) is that such an action function only will be invoked upon actually pressing that button and you don’t have to check for weird cases when this is the only thing you want. But you don’t get any informations passed into the function.
You have to use the structure approach when you want the function to be invoked in cases other than pressing the button and/or you need the additional information. You get all possible stuff from the structure, but the function will be executed when any of these things happen: Control being killed, Mouse down, Mouse up, Mouse up outside control, Mouse moved, Mouse enter, Mouse leave (see help), and actually pressing the button I think.
Since you first move your mouse around and then click or do some other stuff, the function will probably execute several times before your case 2 will come into play. Just have fun looking at numbers lining up with putting
print ba.eventCode
at the beginning. So, if you need all that, then you have to go this way. I personally use the structure approach very rarely because I usually like to keep these functions as small as possible.For the first part, see above. But when saying you should use a simple panel, I meant actually that you may want to write a small
NewPanel
with two controls or so instead of theDoPrompt
. I’m not really sure what exactly is blocked and what is still possible, when igor waits for theDoPrompt
, but I think this approach is prone to errors especially when you expect something to happen in the background (for example doing a calculation). You better stay away from this when using background functions. I had some funny moments in the past withDoPrompt
and its evil brotherPauseForUser
.March 15, 2012 at 11:19 am - Permalink
For what it's worth, you can test for the presence of a null string variable by using strlen(). If the string is NULL, strlen() will return NaN, not 0. So you could do this:
Variable length = strlen(someString)
if (numtype(length) == 2)
// someString is NULL
else if (length == 0)
// someString is empty but not NULL
else
// someString is not empty
endif
March 15, 2012 at 03:17 pm - Permalink
And, going a bit further, since *any* test involving a NaN returns false, if you invert the test you don't even have to have two parts for the "bad string" case:
Variable length = strlen(someString)
if (strlen(someString) > 0)
... do something ...
endif
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
March 16, 2012 at 09:13 am - Permalink
Yes, DoPrompt uses a modal dialog for it's input. And, indeed, that will stop background tasks and things like NIDAQ Tools MX getting fresh data from an acquisition. BUT- CtrlBackground has a keyword "dialogsOK" that allows you to tell Igor that it's OK to run your background task while dialogs (like the Simple Input Dialog) are up. Note that it can be dangerous- if your background task does something like killing a wave that the dialog is using, it can cause Igor to crash.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
March 16, 2012 at 09:18 am - Permalink