Adding members to structures and API compatibility

Hi,

I've encouraged users to write functions which have the same signature as

TestAnalysisFunction_V3.

Function TestAnalysisFunction_V3(panelTitle, s)
    string panelTitle
    STRUCT AnalysisFunction_V3& s

End

/// @brief The structure passed into `V3` and later analysis functions
Structure AnalysisFunction_V3
    /// one of @ref EVENT_TYPE_ANALYSIS_FUNCTIONS
    variable eventType

    /// raw data wave for interacting with the DAC hardware (locked to prevent
    /// changes using `SetWaveLock`). The exact wave format depends on the hardware.
    /// @sa GetHardwareDataWave()
    WAVE rawDACWave

    /// active headstage index, `[0, NUM_HEADSTAGES[`
    variable headStage

    /// number of rows in `rawDACWave` which will be filled with data at the
    /// end of DAQ. The total number of rows in `rawDACWave` might be higher
    /// due to alignment requirements of the data acquisition hardware.
    ///
    /// Always `NaN` for #PRE_DAQ_EVENT events.
    variable lastValidRowIndex

    /// number of rows in `rawDACWave` with already acquired data
    variable lastKnownRowIndex

    /// Potential *future* number of the sweep. Once the sweep is finished it will be
    /// saved with this number. Use GetSweepWave() to query the sweep itself.
    variable sweepNo

    /// Number of sweeps in the currently acquired stimset of the passed headstage
    variable sweepsInSet

    /// Analysis function parameters set in the stimset's textual parameter
    /// wave. Settable via WBP_AddAnalysisParameter().
    string params
EndStructure

Now the obvious thing happened and I have to add another member to AnalysisFunction_V3.

Can that break something on the user side? I can assume that they are not passing the structure into an XOP.

AFAIK, structures are passed in and out without the inside routines knowing what the outside routines use or do not use. So, it should not fail when you put a new variable (e.g. mynewparam) in the structure but never call on it or use it outside the structure (e.g. via TAF.mynewparam). OTOH, when a function calls the OLD structure that does not have the mynewparam and then tries to use TAF.mynewparam, it should break if not at compile then certainly at run time.

At least, that is my understanding if not also supported by some (limited) mucking about in my own routines.

Thanks Jeffrey.

> it should break if not at compile then certainly at run time.

Well that would be a problem. How would it compile but fail at runtime? I can't think of any code which does that.

Oh! You are right. Of course it would have to break at compile time first. Igor is not compiling line by line during runtime as with python.

Speaking of this, didn't Igor compile macros line by line at runtime some time ago?

> Of course it would have to break at compile time first.

Good! This would be totally fine.

> Speaking of this, didn't Igor compile macros line by line at runtime some time ago?

This is still the case now AFAIK.

In reply to by thomas_braun

thomas_braun wrote:

> Of course it would have to break at compile time first.

Good! This would be totally fine.

> Speaking of this, didn't Igor compile macros line by line at runtime some time ago?

This is still the case now AFAIK.

Then I might not be surprised when a call made within a macro to a structure variable TAF.mynewvariable would only fail at runtime.

To conclude, I am fairly certain in principle and by experience that a procedure will never fail to compile or fail to run when new parameters are added to a structure inside of it but the new parameters are never called/used outside of the structure. I've done this type of coding a number of times in my own procedures.

OTOH, I am also certain that calls to structures to try to access parameters that do not exist in the structure will fail at compile time if not at run time (in macros). @WaveMetrics could address the latter point better. Also, I can think of a simple brute force test. Make a structure with only one parameter. Call it from a function and try to access a second (non-existent) parameter. Change the function to a macro and repeat the test.

I can't think of how this would break anything, as long as the function that accepts the structure doesn't expect the value of the new field to be initialized to a useful value. In other words, it can't rely on the caller setting the value if the caller might not know about the value.

It's often good practice to include a version field as the first field of a structure so that functions that use the structure can be written more intelligently (this often means so they don't crash). But with Igor code, you don't need to worry about a crash(*).

 

(*) "You" means the typical user, not necessarily thomas_braun, who should not take this statement as a challenge :)

@jjweimer Yes, macros are interpreted, so you only get errors at runtime. But structures aren't allowed in macros, so they are guaranteed to fail to compile if code tries to use a non-existent structure member.

So to conclude I would say:

Adding members to Igor Pro structures is API compatible if you only use these structures in Igor Pro functions.

Thanks all for your replies.