Objects and returning multiple values
Dr_Acula
Posts: 5,484
Is there a 'best practice" way to return multiple values (longs) from an object?
I have started with a PUB in the main program. Pass it one value and (say) it modifies one value. That is easy
Next is the scenario where you pass one value and it modifies two or more values.
Answer is to declare those variables as "global" variables in the VAR section.
Is that the best way though? Could you pass those variables as dummy values
result := mypub(value1, value2, value3)
and that pub has enough information to work out where, say, value2 is and hence can modify this?
Hmm - that won't work. Still needs to be a global VAR anyway.
The reason I'm asking is that I have some code in a "MAIN" routine and I want to port it over to an object. Now the values are no longer global.
What is the best way to do this?
Do you create a list of variables and pass the start of the list, and then the object can work out how to modify all those variables? What if you change the order of the list down the track? How much code space is wasted coding and decoding variables?
There are a number of solutions here. One is to use arrays and just pass the start of the array, and rather than calling variables names which mean things "xlocation" you refer to that as myarray[3]. This is possibly the most code efficient in terms of recreating local variables within an object, but it is harder to read.
Based on code I have seen in some objects I suspect the answer to this question is to declare lists of variables in the "main" program, pass the start address of the list, and put a comment at the beginning of the list "don't change the order of this list of variables!"
Is this the "best" way for an object to modify a number of global variables?
I have started with a PUB in the main program. Pass it one value and (say) it modifies one value. That is easy
result := mypub(value)
Next is the scenario where you pass one value and it modifies two or more values.
Answer is to declare those variables as "global" variables in the VAR section.
Is that the best way though? Could you pass those variables as dummy values
result := mypub(value1, value2, value3)
and that pub has enough information to work out where, say, value2 is and hence can modify this?
Hmm - that won't work. Still needs to be a global VAR anyway.
The reason I'm asking is that I have some code in a "MAIN" routine and I want to port it over to an object. Now the values are no longer global.
What is the best way to do this?
Do you create a list of variables and pass the start of the list, and then the object can work out how to modify all those variables? What if you change the order of the list down the track? How much code space is wasted coding and decoding variables?
There are a number of solutions here. One is to use arrays and just pass the start of the array, and rather than calling variables names which mean things "xlocation" you refer to that as myarray[3]. This is possibly the most code efficient in terms of recreating local variables within an object, but it is harder to read.
Based on code I have seen in some objects I suspect the answer to this question is to declare lists of variables in the "main" program, pass the start address of the list, and put a comment at the beginning of the list "don't change the order of this list of variables!"
Is this the "best" way for an object to modify a number of global variables?
Comments
You can always pass pointers to your variables. If you want to pass three longs to a method, for example:
The up-side is that you can use the same method with different variables and pass them in the order you choose. The rule, of course, is that you're passing pointers to known types (usually longs).
This is what I tend to do, or if I have an object that uses an array (like a lighting controller) I have a method in the object that provides the hub address of that array so that external code can get to it directly.
"Best" is highly subjective when there are several valid ways to accomplish a task. As long as what you're doing is not confusing, and you provide sensible access methods, that should be enough.
A good readable way to do this is to CON the indeces with an enum:
CON
#0
first_parm
second_parm
third_parm
...and then refer to the results as LONG[rval + second_parm] etc.
The former case saves space, the later may be better if ther are many callers and they don't want to be sharing the same returned data area.
In the former case you only have to pass a pointer to the vars as a parameter and may not need to use the reurn value at all.
and
This decouples things a little better. You can change (extend) the object without having problems in the Main ... even if the new parts of a return structure are not used there. Might make sense to have more than one arrays, at max. one for longs one for words and one for bytes.
Another level would be to only use
long ret_struct[ subf#RET_STRUCT_SIZE ]
in the main and the way of how this buffer is filled is completely implemented in the objects code. It simply provides getter functions which need the address of the ret_struct, but take care of returning the right value out of this structure.
Having object.get(x) is a bit cryptic in the parent code but allows for quick changes. It also allows using an array to define what variables to look at. (i.e. for serial logging)
Lawson
Whenever new is non-zero, that signals that you want a new computation instead of the value previously computed.
Another way to do it, without requiring new is to assume that sequential requests for the same result mean to acquire a new reading, viz:
-Phil