SVAR_Exists

Is there a way of re-testing SVAR status? The code below will fail as the second test of SVAR_Exists does not work as expected, recycling the result of the first test:
string/G  globalString="test string";
SVAR/Z gStr=$"globalString";

if(SVAR_Exists(gStr))
  print gStr;
endif;

killStrings globalString;

if(SVAR_Exists(gStr))
  print "gStr: cannot be true...";
endif;


The second print will cause an error. Any way around this?
I don't have much of an answer for you. You could put another

 SVAR/Z gStr=$"globalString"

assignment before the second test. When I checked, Igor didn't complain about this, but it seems that it could get unwieldy, depending on your code.

I also thought to try testing if the string was null using

if(numtype(strlen(gStr))==2)

but this line provoked the error "attempt to use a null string variable." This seems to qualify as a good working example of Catch-22.
At the time the SVAR reference gStr to the global string "globalString" was created it indeed existed. Even after killing the global string the reference was still valid - I am guessing that SVAR_Exists does not in fact check the current status of the SVAR gStr but just reads the gStr status which is written down internally by SVAR. Therefore SVAR_Exists should always be called just after a SVAR reference.

In fact like noted by jtigor, if you change your example code to
string/G  globalString="test string"
SVAR/Z gStr=$"globalString"
 
if(SVAR_Exists(gStr))
  print gStr
endif
 
killStrings globalString
 
SVAR/Z gStr=$"globalString"
if(SVAR_Exists(gStr))
  print "gStr: cannot be true..."
endif


it works as you anticipated your code to work. But I am sure that some of the IGOR staff will have the correct answer, these are just my thoughts ...

--
Gregor Kladnik
ALOISA beamline @ Elettra synchrotron
That looks like a SVAR limitation.

For waves the corresponding code
Function doStuffWave()

    Make $"myWave"
    Wave myWaveRef = $"myWave"
 
    if(WaveExists(myWaveRef))
        print "exist"
    endif

    KillWaves myWaveRef  
     
    if(WaveExists(myWaveRef))
        print "seems to exist"
    endif
End

does what you expect.

You can write a wrapper
Function/S getGlobalString()

    SVAR/Z gStr=$"globalString"
   
    if(!SVAR_Exists(gStr))
        Abort "missing global string"
    endif
   
    return gStr
End


and use it like
SVAR gStr = $getGlobalString()
.

Although in principle I would not use global strings and variables a lot.
SVAR, NVAR and WAVE statements all have dual function: a compile-time function, and a run-time function.

At compile time, they signal to the compiler that a given name used in your code refers to a string variable, numeric variable or wave. That allows the compiler to create the correct kind of code to deal with the particular object.

At runtime, they signal Igor to actually look up the real object and store a pointer to the object in the NVAR, SVAR or WAVE variable. This look-up must happen at a time when the object actually exists (or in your case, when it doesn't exist). A common error in Igor coding is to assume that these things are just like C or C++ variable declarations, which have only a compile-time function. That causes people to put them too early in their code, before the objects are created. That leads to unexpected NULL variable or NULL wave error messages.

In your case, the first instance of SVAR connects gStr to the existing global string variable. Then you kill the variables. But gStr still has a pointer to the dead string, so SVAR_Exists() gives an apparently wrong answer. Repeating the SVAR statement after KillStrings re-loads gStr, and this time it will not find globalString, and SVAR_Exists() will return FALSE.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Thanks all for the comments. The solution is as pointed to, to redo the SVAR status, so the SVAR_Exists looks again, and comes up with correct status.
Are there any further comments on the observation below? Does this just indicate incorrect thinking about the nature of SVAR/NVAR objects? Intuitively one (me, at least) would think of them as behaving like "normal" variables. But then, intuition isn't always what you think it should be.

Apologies for quoting myself.

jtigor wrote:
I also thought to try testing if the string was null using

if(numtype(strlen(gStr))==2)

but this line provoked the error "attempt to use a null string variable." This seems to qualify as a good working example of Catch-22.

Quote:
Are there any further comments on the observation below? Does this just indicate incorrect thinking about the nature of SVAR/NVAR objects? Intuitively one (me, at least) would think of them as behaving like "normal" variables.


For the most part you can think of SVARs and NVARs behaving as normal variables but to be precise, they are *references* to variables.

There is a difference between a null string variable and a null reference:
Function Test1()
    // str is an existing string variable that is null because nothing was ever assigned to it
    String str
    Print strlen(str)       // Prints NaN because str is uninitialized
   
    // sv is a reference to a non-existent string variable
    SVAR sv = root:nameOfAStringThatDoesNotExist
    Print strlen(sv)        // Generates error because sv does not refer to any string variable
End


In the case of str, the string exists but its value is NULL.

In the case of sv, the string does not exist.

strlen can handle an existing string whose value is NULL - it returns NaN.

strlen can not handle a non-existent reference to a string variable - it generates an "SVAR reference to string failed" error.

If there is a chance that an SVAR may not point to an existing string variable then you need to use SVAR_Exists.

As this thread illustrates the reference stored in an SVAR depends on the state of affairs at the time the SVAR statement executes. This is the the analogous to the problem of creating a WAVE reference before the wave exists:

Function Test2()
    Wave/Z w = root:jack        // w will be NULL if jack does not yet exist
    Print WaveExists(w)
    Make/O root:jack
    Wave/Z w = root:jack        // w now guaranteed to refer to jack
    Print WaveExists(w)
End