Guest Posted August 8, 2002 One of the major limitations of the OFP script language is that it doesn't allow user defined functions that return values. This makes any more serious script writing a real pain. Using global variables to transfer values between two scripts dosn't cut it since the script language interpretation is in real-time. If several instances of the same script are running simultaneously then there will be a resource conflict over the global vars it is using. We can therefor rule out using global variables for return values from scripts. I think that most scripters would agree that a modification of the exec function would be very, very welcome and desired. Currently, there is one solution. It is not a good one, but it is a solution. The limitation of it is that you can only use the functionallity within the script that it is defined. It looks something like this (this is just for illustrations, I havn't checked the code in detail, so there might be errors, but you'll get the idea): </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> _a = 3 _b = 2 _c = 1 ; Call first function _aSumTwoValues = +_a _bSumTwoValues = +_b _returnLabelSumTwoValues  = "AfterSum" goto "SumTwoValues" #AfterSum _result = +_resultSumTwoValues ; Call second function _aSubtractTwoValues= +_result _bSubtractTwoValues = +_c _returnLabelSubtractTwoValues =  "AfterSubtraction" goto "SubtractTwoValues" #AfterSubtraction _result2 = +_returnSubtractTwoValues ; end function calls ; now we have that _result2 = (a+b)-c exit ; Function 1: A + B #SumTwoValues  _returnSumTwoValues = _aSumTwoValues + _bSumTwoValues goto _returnLabelSumTwoValues ; function 2: A-B #SubtractTwoValues  _returnSubtractTwoValues = _aSubtractTwoValues + _SubtractTwoValues goto _returnLabelSubtractTwoValues <span id='postcolor'> This works in principle, but it is extremely clumsy and it requires the abuse of numerous local variables What would be desirable would be: Main script: main.sqs </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> _a = 3 _b = 2 _c = 1 _res = [_a,_b] exec "sum.sqs" _res2 = [_res,_c] exec "subtract.sqs" <span id='postcolor'> Sum.sqs: </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> return (this select 0) + (this select 1) <span id='postcolor'> Subtract.sqs: </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> return (this select 0) - (this select 1) <span id='postcolor'> Share this post Link to post Share on other sites
WhoCares 0 Posted August 8, 2002 You might try to work with a global list and a global index to this list. Each time you call a subroutine you give it the current value of the index, store the index in a local variable of the calling routine and increment it afterward. The subroutine stores the result at the index position of the global list and the calling routine can read it with its local copy of the index. The list must be big enough to handle all concurrent function calls. If none of the called routines is time consuming (eg. waiting for a trigger) you can also make it circular (if the index comes to the end of the list it starts with 0 again) to save memory. Just an idea, never tried it  (and of course, return values would be easier Edit: You might need another one or two global boolean lists, to indicate when the subroutine has written the result and whether the result has been read by the calling routine. With all this you might even try to make a slot handler, where other scripts get assigned unused result slots to optimize memory usage. Share this post Link to post Share on other sites
Guest Posted August 8, 2002 Yes, that was my first idea too actually. The problem is however that you would need one such global list and global index per script (in addition to a local index variable per call to the function so you know where to get your value). I am terrified of global variables in OFP since I am pretty sure that it doesn't have any real-time safeguards and that there could be severe timing and resource sharing conflicts. Example situation: </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> globalIndex = 0 ; call function 1 globalIndex = globalIndex + 1 _myLocalIndex = globalIndex ; call function 2 globalIndex = globalIndex + 1 _myLocalIndex = globalIndex <span id='postcolor'> Now imagine how this could look like if somebody called function 1 and 2 simultaneously: Order of execution: </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> 1) globalIndex = globalIndex + 1; function 1 2) globalIndex = globalIndex + 1; function 2 3) _myLocalIndex = globalIndex; function1 4) _myLocalIndex = globalIndex;function 2 <span id='postcolor'> Instead of getting _myLocalIndex to be 1 for the first call and 2 for the second we get that they are equal to 2 in both cases; the call for function1 will be getting function 2's values. Share this post Link to post Share on other sites
suma 8 Posted August 9, 2002 </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (denoir @ Aug. 08 2002,15:53)</td></tr><tr><td id="QUOTE">I think that most scripters would agree that a modification of the exec function would be very, very welcome and desired.<span id='postcolor'> Unfortunatelly the thing you suggest cannot be accompished via any modification of "exec". Exec spawns parallel execution of another script and returns immediatelly - therefore reliably returing value from it is not possible. We are aware this is serious limitation of the scripting language - but I am afraid you will have to live with it as it, as it is very unlikely that any OFP patches will make any fundamental changes like this. Share this post Link to post Share on other sites
vektorboson 8 Posted August 9, 2002 I don't think that "exec" must be changed, but I would like to see a "function"-possibility implemented, that you could do something like this: </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> : myfunction _params = _this _a = _this select 0 _b = _this select 1 _result = _a + _b return _result <span id='postcolor'> It's just like programming a function in C/C++ or Pascal a.s.o. Then you could invoke this function into a script with something like this: </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> include "myfunction.sqs" <span id='postcolor'> But I don't know if this would be hard to implement. Share this post Link to post Share on other sites
WhoCares 0 Posted August 9, 2002 But this is exactly what denoir asked for, a return value that could be used in the calling routine. @denoir: yepp, multithreading is a killer for this approach and the scripts might be most likely handled in this way. A way around this would be a central slot handler routine, but this is not easy to implement as well... Share this post Link to post Share on other sites
Guest Posted August 9, 2002 </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote </td></tr><tr><td id="QUOTE"> We are aware this is serious limitation of the scripting language - but I am afraid you will have to live with it as it, as it is very unlikely that any OFP patches will make any fundamental changes like this. <span id='postcolor'> Well, then it is going to be on the top of my wish list for OFP2 Actually, I was too pessimistic about the global list solution. I did an experiment with 15 simultaneous executions and there was no synchronization problem. The principle I used is the follwing (credit and thanks goes to Spinor for the code): This is to initialize the system, e.g. in the init.sqs: </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> ;initialization----------------------------- sCurrentID = 0 sIDStack = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] sResultStack = []; sResultStack ReSize 16 ;------------------------------------------- <span id='postcolor'> This is the calling routine. The only line that has to be customized is the exec command. <arguments> are any parameters you pass to the function. The additional argument _ID is necessary. It stores the functions ID number (as refering to the stacks): </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> ;call routine--------------------------------- sCurrentID = (sCurrentID + 1) Mod 16; _ID = sCurrentID; sIDStack Set [_ID, true] [...<arguments>...,_ID] exec "<subscript>.sqs" @!(sIDStack select _ID) _result = sResultStack select _ID ;------------------------------------------- <span id='postcolor'> This is the return routine in the function script. It simply writes the result in rResultStack and notifies the calling script that its finished: </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE"> ;return routine----------------------------- ;don't forget to define _ID and _result !!! sResultStack Set [_ID, _result] sIDStack Set [_ID, false] ;------------------------------------------- <span id='postcolor'> Share this post Link to post Share on other sites
LauryThorn 0 Posted August 9, 2002 @denoir Man, you are developing a new language here! Share this post Link to post Share on other sites
Spinor 0 Posted August 9, 2002 @denoir: </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote </td></tr><tr><td id="QUOTE">I did an experiment with 15 simultaneous executions and there was no synchronization problem.<span id='postcolor'> after you told me about possible problems with a global stack I did exactly the same @Suma Could you explain how simultaneous scripts are executed? E.g. is there a command interpreter for each script that runs independently from the others or is there one command interpreter into which the commands from all scripts are fed alternately? If the latter is true, what blocks are fed into the interpreter? E.g. for the above system presented by denoir to run safely it would be necessary that a line of code from one script is executed in one go. Share this post Link to post Share on other sites
suma 8 Posted August 9, 2002 </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Spinor @ Aug. 09 2002,15:06)</td></tr><tr><td id="QUOTE">Could you explain how simultaneous scripts are executed? E.g. is there a command interpreter for each script that runs independently from the others or is there one command interpreter into which the commands from all scripts are fed alternately?<span id='postcolor'> There is one command interpreter. </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote </td></tr><tr><td id="QUOTE">If the latter is true, what blocks are fed into the interpreter?<span id='postcolor'> Atomic execution block is: until you use any wait condition (&, @, ~) or until 100 lines is executed (this is to avoid lockups caused by infinite loops). If your script is never using "goto" backwards or wait instructions and if it is shorted than 100 lines, it can be considered atomic. Share this post Link to post Share on other sites
bn880 5 Posted August 9, 2002 Like Suma said, that's not a small mod to the exec function. You can not treat scripts as functions in the current implementation. Good idea though with the stack, you can also resize the stack every time you increase the ID count I think. So it would make it fully dynamic. Share this post Link to post Share on other sites
kegetys 2 Posted August 9, 2002 </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Suma @ Aug. 09 2002,16:28)</td></tr><tr><td id="QUOTE">until you use any wait condition (&, @, ~)<span id='postcolor'> Sorry for going a bit offtopic, but what is the difference between these three? Share this post Link to post Share on other sites
Spinor 0 Posted August 9, 2002 @Suma Thanks alot, this info is very helpful Share this post Link to post Share on other sites
bn880 5 Posted August 9, 2002 </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Kegetys @ Aug. 09 2002,09:36)</td></tr><tr><td id="QUOTE"></span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Suma @ Aug. 09 2002,16:28)</td></tr><tr><td id="QUOTE">until you use any wait condition (&, @, ~)<span id='postcolor'> Sorry for going a bit offtopic, but what is the difference between these three?<span id='postcolor'> ~<float> lets you pause for <float> seconds @<condition> waits for <contidion> to = ture &<float> waits for <float> = DayTime Share this post Link to post Share on other sites
Guest Posted August 9, 2002 </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Quote (Suma @ Aug. 09 2002,15:28)</td></tr><tr><td id="QUOTE">Atomic execution block is: until you use any wait condition (&, @, ~) or until 100 lines is executed (this is to avoid lockups caused by infinite loops). If your script is never using "goto" backwards or wait instructions and if it is shorted than 100 lines, it can be considered atomic.<span id='postcolor'> Great. Thanks Suma So to conclude then: global lists will work fine as long as you don't mess with the indexing variables after 100 lines after the call of the function. That is very good. Now I can reduce my matrix manipulation code by at least 80% Share this post Link to post Share on other sites
Doolittle 0 Posted February 11, 2003 I just saw this old post and thought it was cool that BIS did put in functions. So cool they listen like that. Glad you guys asked for it too. Doolittle Share this post Link to post Share on other sites
MaxPower44 1 Posted February 11, 2003 We have still function ?? plus.sqf </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE">private{_a,_b}; _a = _this select 0; _b = _this select 2; _a + _b<span id='postcolor'> We can use like it : </span><table border="0" align="center" width="95%" cellpadding="3" cellspacing="1"><tr><td>Code Sample </td></tr><tr><td id="CODE">plus = loadfile "plus.sqf" _a = 10 _b = 5 _c = [_a,_b] call plus<span id='postcolor'> My code works and I imagine that my parameter is putting in a stack ? What is the problem ? Maybe i don't understand a technicality ? Share this post Link to post Share on other sites
bn880 5 Posted February 11, 2003 Max, the reason we have sqf is Denoir asking for it. Share this post Link to post Share on other sites
MaxPower44 1 Posted February 11, 2003 Oh  !!! I don't read the date of this post .... Perhaps can you answer a little question : I have make a function which use _count {private _count} _count is'nt passed in parameter but i call this function in a loop which use _count (to loop), and the function modify the _count in the loop, why? what's wrong in my function ? PS: thx Denoir & BIS for the call function Share this post Link to post Share on other sites
Guest Posted February 11, 2003 There is really no point in digging up such an old thread. MaxPower - post your question in a new thread, and if I may suggest post a little more detailed explanation of your problem, I'm not sure that I quite get what you want to do. Closing Share this post Link to post Share on other sites