Initial Values of Strings

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.
andyfaff wrote:
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
jjweimer wrote:

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.
aclight wrote:
... 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

    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 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?
Thomas.Dane wrote:
...
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. ;)
chozo wrote:
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 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?

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!)
Thomas.Dane wrote:

Ah of course! I will leave it as the strlen.


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 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?


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.
Thomas.Dane wrote:

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
else if (length == 0)
  // someString is empty but not NULL
else
  // someString is not empty
endif
aclight wrote:
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:
String someString
Variable length = strlen(someString)
if (strlen(someString) > 0)
  ... do something ...
endif

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
chozo wrote:
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.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com