Checking Exists(Function) from Inside Independent Modules

I am either still missing something about the behavior of Independent Modules or I have found a bug. Suppose I have the following in a procedure file:

#pragma IndependentModule=MyIM

Function DoIt()

     if(exists("JoeSmithModule#SuperDuperFunction")==6)
           Execute/Q/Z "JoeSmithModule#SuperDuperFunction(0)"
     else
           RunMyFunction(0)
     endif

     return 0
end


Should I expect this method ALWAYS to work as a clean way to determine whether JoeSmithModule is or is not present in the given experiment. In particular, should this method work regardless of HOW the module JoeSmithModule is loaded (via #include from the general procedure window or automatically from the Igor Extensions Folder) and regardless of WHEN JoeSmithModule is loaded (before or after the IM named MyIM)? I know that JoeSmithModule#SuperDuperFunction will NOT be found when JoeSmithModule is #included as part of a different Independent Module. Will my test method have any other well defined cases will it will NEVER work?

I ask because, I am running into a case where

print exists("JoeSmithModule#SuperDuperFunction")


returns 0 from within DoIt() yet returns 6 when issued on the command line.
I could be wrong, but I thought that previously Larry said that this behavior was expected, due to the ambiguity of the order in which independent modules are compiled.

I assume this is for your easy new notebook package interfacing with my window desktop package. If so, I think a workaround would be to always check the currently displayed desktop, and then inspect the value of the global variable. If it makes sense, then the independent module is present. If not, then call RunMyFunction(). Since you're using the /Z flag with Execute there shouldn't be any errors if Window Desktops is not present.
aclight wrote:
I could be wrong, but I thought that previously Larry said that this behavior was expected, due to the ambiguity of the order in which independent modules are compiled.


I too recalled something like this being the case.

The problem arises where I want a given package to "benefit by" but not "depend on" another package. In this case, the problem I have is that Easy New Notebook as an independent module does not recognize ScreenSizer as a module, even though ScreenSizer is loaded in the experiment because I have it set to be always loaded. I have even tried to run the Execute/Q/Z "ScreenSizer#Initialize(0)" function, only to go no-where. :-( Interestingly, interfacing with WindowDesktop works fine (at least in my current interation of Easy New Notebook).

Anyway, I understand that having ambiguous order for compilations can change how a compiler directive #if(exists("")) in one procedure behaves when checking for a function in a different module/independent module. I must say though, I still do not understand why changing the compile order of procedures should play havoc with the runtime return values of such things as if(exists("")) or the runtime behavior of Execute/Q/Z "MyFunction".

[update comment added]

OK. I think I see it now. Independent Modules are NEVER supposed to need anything else but what they bring with them and what Igor Pro provides. They may be able to piggy-back on functions in other procedures (whether globals or modules or independent modules). This latter "benefit" arises however only on a "luck-of-the-draw" basis -- sometimes an IM can see other procedures around it, sometimes it can not. One should NEVER plan or even try to plan for an IM to "benefit by" functions from other procedures, rather the default is to plan as though it will NEVER be able to do so.

That somewhat sucks, but not too badly. It just means Easy New Notebook will likely be a module with a #pragma hide=1.

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
jjweimer wrote:

The problem arises where I want a given package to "benefit by" but not "depend on" another package. In this case, the problem I have is that Easy New Notebook as an independent module does not recognize ScreenSizer as a module, even though ScreenSizer is loaded in the experiment because I have it set to be always loaded. I have even tried to run the Execute/Q/Z "ScreenSizer#Initialize(0)" function, only to go no-where. :-( Interestingly, interfacing with WindowDesktop works fine (at least in my current interation of Easy New Notebook).


Maybe they are compiled in alphabetical order? ACL_WindowDesktops then EasyNewNotebook then ScreenSizer? That would explain your findings, though it seems unlikely that they would be compiled in alphabetical order.

Alternately, maybe you could make ENN and SS both part of the same independent module. As long as you didn't have namespace issues with function and/or constant names, it seems like that would work. In the case where ENN is not used SS should still work, and you should be able to call functions and get returned values. It's somewhat less intuitive that you'd need to make these the same independent module, but I think it should work. Just call your independent module something more generic.
aclight wrote:
Maybe they are compiled in alphabetical order? ACL_WindowDesktops then EasyNewNotebook then ScreenSizer? That would explain your findings, though it seems unlikely that they would be compiled in alphabetical order.


As near as I can tell, the order of #include and the name of the package or module make no difference. As long as EasyNewNotebook is an IndependentModule and ScreenSizer is just a ModuleName, a run-time call to exists("ScreenSizer#Initialize") within EasyNewNotebook returns 0.

In other words, at run time, Independent Modules know only about a) the standard Igor Pro commands (operations and functions), b) the functions in procedure files #included by themselves and c) (potentially) functions within other independent modules. I gather that c) occurs because all independent modules are compiled before anything else. Here is where I suspect the order of compilation may play havoc with one independent module knowing or not knowing about another at run time.

I ended up making EasyNewNotebook a ModuleName rather than an IndependentModule, partially because of the above and partially because I realized, I may want to use it as a component of another package anyway.

Thanks for the suggestions.

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
THe way I do it is as follows:

    if(itemsinlist(OperationList("multiopenfiles", ";", "external" ))>0)
        filenames = Moto_askforlistoffiles()
    else
        open/r/d/T="????" fileID
        filenames = S_filename
    endif

and
Function/t Moto_askForListofFiles()
    execute/z "multiopenfiles/F=\".*;.xml;\"/M=\"Please select your data files.\""
    SVAR/z nv = S_filename
    if(SVAR_exists(nv))
        return nv
    else
        return ""
    endif
End


This is for operations. For functions use Functionlist
andyfaff wrote:
THe way I do it is as follows: ...


This does not work either. Here is a minimal example using two procedures, FRIC and FRAC.

// PROCEDURE FRIC

#pragma rtGlobals=1
#pragma IndependentModule=Fric

Function ShowIt()
    print "In Fric"
    print exists("Frac#GetIt")
    print "With list " + FunctionList("*",";","WIN:Frac.ipf")
    return 0
end

// PROCEDURE FRAC

#pragma rtGlobals=1
//#pragma ModuleName=Frac    // uncomment this or not -- it makes no difference

Function GetIt()
    print "In Frac"
    print exists("Fric#ShowIt")
    print "With list " + FunctionList("*",";","WIN:[FRIC]")
    return 0
end


On the command line, run fric#showit().
In Fric
0
With list

On the command line, run print FunctionList("*",";","WIN:Frac.ipf")
GetIt;

On the command line, run getit() [or frac#getit() when the modulename is uncommented]
In Frac
6
With list GetIt; <------ what???? this seems like a bug here!!!!

On the command line, run print FunctionList("*",";","WIN:[Fric]")
GetIt; <------- what???? this seems again like a bug!!!!!

On the command line, run setigoroption independentmoduledev=1
On the command line, run print FunctionList("*",";","WIN:[Fric]")
ShowIt; <------- correct response!

On the command line (still with independentmoduledev=1), run getit()
In Frac
6
With list ShowIt;

On the command line (still with independentmoduledev=1), run fric#showit()
In Fric
0
With list

------------------------

I think at least I have found a bug: functionlist("*",";","WIN:[independentmodulename]") returns the wrong value when independentmoduledev=0.

Otherwise, I would still state that IndependentModules cannot detect anything about the environment outside IgorPro, themselves, and other IndependentModules. This is true even at run time and even to the extend of not seeing functions in otherwise "global" procedures (ie, non modular).

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
Quote:
This does not work either. Here is a minimal example using two procedures, FRIC and FRAC.


I wonder about the asymmetries between your FRIC and FRAC procedures. In one case, you use #pragma IndependentModule, in the other case, #pragma ModuleName. The FunctionList calls are also subtly different. I tried this with

//PROCEDURE FRIC
#pragma rtGlobals=1
#pragma IndependentModule=Fric
 
Function ShowIt()
//variable/G FracLoaded = -1
    print "In Fric"
    print exists("FRAC#GetIt")
    print "With list " + FunctionList("*",";","WIN:[FRAC]")
//  execute/p "FracLoaded = exists(\"FRAC#GetIt\")"
    return 0
end

//PROCEDURE FRAC
#pragma rtGlobals=1
#pragma IndependentModule=Frac
 
Function GetIt()
//variable/G FricLoaded = -1
    print "In Frac"
    print exists("FRIC#ShowIt")
    print "With list " + FunctionList("*",";","WIN:[FRIC]")
//  execute/p "FricLoaded = exists(\"FRIC#ShowIt\")"
    return 0
end

and got
•fric#showit()
  In Fric
  6
  With list ShowIt;
•frac#getit()
  In Frac
  6
  With list GetIt;

from the command line. Is this not what you wanted?

Best regards,
Wolfgang Harneit

REM: I did SetIgorOption IndependentModuleDev=0 before, my environment is IP6.1.0.6/WinXP
harneit wrote:
Quote:
This does not work either. Here is a minimal example using two procedures, FRIC and FRAC.


I wonder about the asymmetries between your FRIC and FRAC procedures. In one case, you use #pragma IndependentModule, in the other case, #pragma ModuleName. The FunctionList calls are also subtly different. ...


Yes. Precisely. My intent was to test the asymmetric case, especially with regard to whether IndependentModules are able (or unable) to "see" functions in non-independent modules.

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
jjweimer wrote:
My intent was to test the asymmetric case, especially with regard to whether IndependentModules are able (or unable) to "see" functions in non-independent modules.

I still get the same answers when using my procedure pair regardless of whether I use #pragma IndependentModule or #pragma ModuleName. I did use however print "With list " + FunctionList("*",";","WIN:[FRAC]") instead of your print "With list " + FunctionList("*",";","WIN:Frac.ipf").
--
Wolfgang Harneit
harneit wrote:

I still get the same answers when using my procedure pair regardless of whether I use #pragma IndependentModule or #pragma ModuleName. I did use however print "With list " + FunctionList("*",";","WIN:[FRAC]") instead of your print "With list " + FunctionList("*",";","WIN:Frac.ipf").


Be careful! The sequence of steps that you take makes a big difference!

1) Create Fric and Frac as given in my original statements. Save both procedure files in User Procedures.
2) Quit from Igor Pro
3) Open Igor Pro and open the macro procedure window
4) Put the commands #include "Fric.ipf" and #include "Frac.ipf" in the window. Recompile.
5) On the command line, type frac#getit(). The response will be ... In Frac ... 6 ... With list GetIt;
6) On the command line, type fric#showit(). The response will be ... In Fric ... 0 ... With list
7) SetIgorOption independentmoduledev=1
8) On the command line, type frac#getit(). The response will be ... In Frac ... 6 ... With list ShowIt;
9) On the command line, type fric#showit(). The response will be ... In Fric ... 0 ... With list

Line 5 shows an error in Igor Pro (I think the response here should be either ShowIt or an empty list ... certainly not the name of the enclosing function).
Lines 6 and 9 show that independent modules have no sense of things compiled after them, even at run time and regardless of the state of independentmoduledev.

The difference between "WIN:[FRIC]" and "WIN:Fric.ipf" is, the former searches in independent modules (Fric in this case), while the latter searches in procedure files (Fric.ipf in this case). Searching with "WIN:Fric.ipf" should properly find nothing when Fric.ipf includes the #pragma IndependentModule=Fric statement.

I have found that any differences from the above behavior are often due to Igor Pro "remembering" instances of module names and independent module names even when you change them unless you kill the containing procedure file and reload it from scratch.

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
The correct syntax for the functions is given below. Thanks greatly to Jim Prouty for providing the examples that led to the epiphany.

---------------
PROCEDURE FRAC.ipf

#pragma rtGlobals=1
#pragma ModuleName=Frac
Function GetIt()
   print "In Frac (module)"
   print "ShowIt? " + num2str(exists("Fric#ShowIt"))
   print "With Fric list " + FunctionList("*",";","WIN:Fric.ipf [Fric]")  // note the strict syntax required!
   return 0
end
---------------
---------------
PROCEDURE FRIC.ipf

#pragma rtGlobals=1
#pragma IndependentModule=Fric
Function ShowIt()
   print "In Fric (independent module)"
   print "GetIt? " + num2str(exists("ProcGlobal#Frac#GetIt"))
   print "With Frac list " + FunctionList("*",";","WIN:[ProcGlobal]") // note the strict syntax required!
   return 0
end
---------------


•setigoroption independentmoduledev=0
•fric#showit()
In Fric (independent module)
GetIt? 6
With Frac list GetIt;
•frac#getit()
In Frac (module)
ShowIt? 6
With Fric list
•setigoroption independentmoduledev=1
•fric#showit()
In Fric (independent module)
GetIt? 6
With Frac list GetIt;
•frac#getit()
In Frac (module)
ShowIt? 6
With Fric list ShowIt;

Static functions add another level of fun to the mix.

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH