tortuosit 486 Posted November 11, 2014 Hi Guys, I use: private "_test"; _test = 1; examplefunction = { blah; blubb; _test = _test + 1; }; <morecode> [] call examplefunction; [] call examplefunction; [] call examplefunction; [] call examplefunction; I need: _test to be exactly in the calling script scope. Like a semi global variable... Don't want to pass it via return values and arguments for some reasons... I need: if another script includes the same function code, that it has an own _test variable. Does it do that? BTW, is (_test == 6) after the code? I think I have observed that the code of a function is executed, even if it has not yet been called. Not sure here. Would be bad.` Thx Share this post Link to post Share on other sites
lappihuan 178 Posted November 11, 2014 (edited) If it is something player or object specific in your _test var you could use setVariable/getVariable to this object. Other than that i don't have another idea how to achieve your needs. As far as i know, the function will only be compiled not executed, so you execute the function 4 times _test would be 5. Edited November 11, 2014 by Lappihuan Share this post Link to post Share on other sites
jshock 513 Posted November 11, 2014 (edited) I'm really confused by your wording, do you need _test to be passed into another function, or _test can only be used in this function, or something else??? Ok read a bit closer and get/set variable would be your only option, but I don't see why you don't want to use returns or arguments, returns really are the point of a function... And from my knowledge functions get compiled, not executed until their called/spawned. Edited November 11, 2014 by JShock Share this post Link to post Share on other sites
Heeeere's johnny! 51 Posted November 11, 2014 (edited) Hi Guys,I use: private "_test"; _test = 1; examplefunction = { blah; blubb; _test = _test + 1; }; <morecode> [] call examplefunction; [] call examplefunction; [] call examplefunction; [] call examplefunction; I need: _test to be exactly in the calling script scope. Like a semi global variable... Don't want to pass it via return values and arguments for some reasons... I need: if another script includes the same function code, that it has an own _test variable. Does it do that? BTW, is (_test == 6) after the code? I think I have observed that the code of a function is executed, even if it has not yet been called. Not sure here. Would be bad.` Thx Uuuhm .... wut? :confused: Honestly, I barely have a clue what you are talking about. Alright, I get what you want, but hoping it might help you, let's take a crash course on scopes. For further explanaition, have a look at Killzone_Kid's blog, topic "Scopes". He explains it very deeply with a lot of code examples. if (TL;DR) then {read _this}: Basically, every "{" begins a new scope and a "}" ends one. That means, a _privateVariable created in there will not be usable outside this scope. Mostly, you can private variables from outside a scope inside it, too, BUT that does NOT apply to functions. Example: [color="#FF8040"][color="#191970"][b]if[/b][/color][color="#8B3E2F"][b]([/b][/color][color="#191970"][b]alive[/b][/color] [color="#000000"]player[/color][color="#8B3E2F"][b])[/b][/color] [color="#191970"][b]then[/b][/color] [color="#8B3E2F"][b]{[/b][/color] [color="#1874CD"]_damage[/color] [color="#8B3E2F"][b]=[/b][/color] [color="#191970"][b]damage[/b][/color] [color="#000000"]player[/color][color="#8B3E2F"][b];[/b][/color] [color="#191970"][b]hint[/b][/color] [color="#191970"][b]format[/b][/color] [color="#8B3E2F"][b][[/b][/color][color="#7A7A7A"]"Player damage: %1"[/color][color="#8B3E2F"][b],[/b][/color] [color="#1874CD"]_damage[/color][color="#8B3E2F"][b]][/b][/color][color="#8B3E2F"][b];[/b][/color] [color="#006400"][i]//Result: e.g. "Player damage: 0.1"[/i][/color] [color="#8B3E2F"][b]}[/b][/color][color="#8B3E2F"][b];[/b][/color] [color="#191970"][b]hint[/b][/color] [color="#191970"][b]format[/b][/color] [color="#8B3E2F"][b][[/b][/color][color="#7A7A7A"]"damage: %1"[/color][color="#8B3E2F"][b],[/b][/color] [color="#1874CD"]_damage[/color][color="#8B3E2F"][b]][/b][/color][color="#8B3E2F"][b];[/b][/color] [color="#006400"][i]//Result: "damage: " -> _damage is undefined outside the if block[/i][/color][/color] If you define a function like in your example, you can only use private variables from the surrounding scope by passing them into the function using "call", "spawn", "execVM" or some other language given method to do so. [color="#FF8040"][color="#1874CD"]_myVar[/color] [color="#8B3E2F"][b]=[/b][/color] [color="#7A7A7A"]"Hello, world"[/color][color="#8B3E2F"][b];[/b][/color] [color="#1874CD"]_myVar[/color] [color="#191970"][b]call[/b][/color] [color="#8B3E2F"][b]{[/b][/color] [color="#191970"][b]hint[/b][/color] [color="#191970"][b]format[/b][/color] [color="#8B3E2F"][b][[/b][/color][color="#7A7A7A"]"Message: %1."[/color][color="#8B3E2F"][b],[/b][/color] [color="#000000"]_this[/color][color="#8B3E2F"][b]][/b][/color][color="#8B3E2F"][b];[/b][/color] [color="#006400"][i]//result: "Message: Hello, world."[/i][/color] [color="#8B3E2F"][b]}[/b][/color][color="#8B3E2F"][b];[/b][/color][/color] Kudos to Killzone_Kid for his SQF to BBCode Converter. As you can see, I'm calling that function with "_myVar" as parameter. Parameters passed to a function are available inside that function by the word "_this". Keep that in mind as "_this" can be overwritten, so don't use it as a name for a custom variable. And finally, why in the blue hell do you not want to use arguments and return values??? What's the point of a function if you cannot use it's calculations? Regards, Johnny Edited November 11, 2014 by Heeeere's Johnny! Share this post Link to post Share on other sites
Tajin 349 Posted November 11, 2014 (edited) private "_test"; _test = 1; examplefunction = { blah; blubb; _test = _test + 1; }; <morecode> [] call examplefunction; [] call examplefunction; [] call examplefunction; [] call examplefunction; I think that might actually work. Either way, I would still rather use return values, just to be on the safe side and also because it makes the code clearer. Edited November 11, 2014 by Tajin Share this post Link to post Share on other sites
jshock 513 Posted November 11, 2014 Ok, maybe getting a better understanding of this as I read it five times over: I am assuming that your execVMing your above code, in that code you privatize the variable "_test" then initialize it as 1. You then have your function, which is compiled as the code runs over it, then you have 4 calls to that function, but you want "_test" to change along with each of those function calls (basically adding 1 to "_test" after each call). So the way you are doing this it isn't possible to get the desired results (I don't think). Firstly what is the point of calling the same function four times in a row? If you need to do the same thing 4 times, put a for loop around the code in the function and spawn the function, and then have the function return a value after it exits to for loop, which is now your new variable value. Secondly, everytime you call/spawn the function, it essentially is reset, it doesn't know what "_test" is unless you initialize it within the function or pass it via argument, an in-line function doesn't use "full-script" scoped variables, as far as I know, unless you use get/set or just make the variable global (at which point you could use it in your function without initializing it). So maybe if you explained why you don't want to use returns/arguments we may be able to answer you a bit better. Share this post Link to post Share on other sites
dreadedentity 278 Posted November 11, 2014 He probably can't always get the return value from his function but needs updated information, many situations can cause this, such as using the function in multiple scripts running at the same time. Therefore, you need to use a "client variable" which is available to the client no matter what script it's in. The only way I know to do that is with get/setVariable, as mentioned before Share this post Link to post Share on other sites
killzone_kid 1333 Posted November 11, 2014 Yes you can do this. As long as you define your _variable before you call function: [color="#FF8040"]func [color="#8B3E2F"][b]=[/b][/color] [color="#8B3E2F"][b]{[/b][/color] [color="#191970"][b]systemChat[/b][/color] [color="#191970"][b]str[/b][/color] [color="#1874CD"]_test[/color][color="#8B3E2F"][b];[/b][/color] [color="#8B3E2F"][b]}[/b][/color][color="#8B3E2F"][b];[/b][/color] [color="#1874CD"]_test[/color] [color="#8B3E2F"][b]=[/b][/color] [color="#7A7A7A"]"ok"[/color][color="#8B3E2F"][b];[/b][/color] [color="#191970"][b]call[/b][/color] func[color="#8B3E2F"][b];[/b][/color] [color="#006400"][i]//"ok"[/i][/color] [color="#1874CD"]_test[/color] [color="#8B3E2F"][b]=[/b][/color] [color="#FF0000"]123[/color][color="#8B3E2F"][b];[/b][/color] [color="#191970"][b]call[/b][/color] func[color="#8B3E2F"][b];[/b][/color] [color="#006400"][i]//123[/i][/color] [color="#1874CD"]_test[/color] [color="#8B3E2F"][b]=[/b][/color] [color="#1874CD"]_test[/color] [color="#8B3E2F"][b]+[/b][/color] [color="#FF0000"]456[/color][color="#8B3E2F"][b];[/b][/color] [color="#191970"][b]call[/b][/color] func[color="#8B3E2F"][b];[/b][/color] [color="#006400"][i]//579[/i][/color][/color] Made with KK's SQF to BBCode Converter This is why people use private command inside functions to avoid out of scope variables affecting in-scope variables. Share this post Link to post Share on other sites
lappihuan 178 Posted November 12, 2014 (edited) @KK Interesting, but how is it when you change the variable inside the function? (@work, can't test) As i come from PHP there is 'call by reference' so you define the variable that you want to have in 'call by reference' mode so it gets updated outside of the function when it changes inside it. function myFnc($var1,$var2,&$var3) { //$var3 will be call by reference $var1++; $var2++; $var3++; } $var1 = 99; $var2 = 99; $var3 = 99; myFnc($var1,$var2,$var3); echo $var1; //result is 99 echo $var2; //result is 99 echo $var3; //result is 100 In your example you only read the variable inside the function and only change it outside it, so can i assume that 'call by reference' is not possible in sqf? Edited November 12, 2014 by Lappihuan Share this post Link to post Share on other sites
Tajin 349 Posted November 12, 2014 Its not "not possible" its just "not necessary". If you can read the variable, you can also change it. Share this post Link to post Share on other sites
lappihuan 178 Posted November 12, 2014 yea, but changing inside from inside the scope is something else as change it outside from inside the scope.. as far as i understand it. Share this post Link to post Share on other sites
tortuosit 486 Posted November 12, 2014 (edited) Thanks guys. Ah, love KKs Blog, always a pleasure to read code explanations... sometimes Google sent me to him. And finally' date=' why in the blue hell do you not want to use arguments and return values??? What's the point of a function if you cannot use it's calculations?[/quote']Nonono. :D I use parameters and return values and do calculations. BUT: This is a small (probably not perfect) PRNG which I use as a random() replacement. I only wanted to pass one argument to the PRNG and get one value in return, just like it is the case with the internal random function. Without proper parameters I know, it is a dirty business. I expected _seedvar to be one variable and visible in in the example.sqf scope and inside the function. Mostly, you can private variables from outside a scope inside it, too ...what we always need scoping inside if{}, while{} etc... BUT that does NOT apply to functions. Oh no. This is my code. That _count is not too important as you may see, but _seedvar needs to be alive in the sqf's context. And I do not want to have it outside the sqf. [example.sqf] <code ...> // -- I want to put this part into a separate file and include it ////// private "_count"; _count = 0; _seedvar = a_seed; tort_prng = { _count = _count + 1; private["_i","_num","_out","_arr"]; _out = ""; for "_i" from 1 to 7 do { _num = sin(_i^3 + _count + _seedvar) + 1; _arr = toArray str(_num); if ((count _arr) > 6) then {_out = _out + toString([_arr select ((count _arr) - 2)]);}; }; _seedvar = (1000000 - (parseNumber (_out)) + _count) % 1000000; ((_this select 0) * parseNumber ("0." + _out)) }; ////////////////////////// <more code...> while-loop stuff _myrandomnumber = [2] call tort_prng; end while end script EDIT: Yes you can do this. As long as you define your _variable before you call function Aha! I did that. So my code should work properly... Cannot test now. And I was a bit tired of debugging and hint statements... :D I think Johnny says the opposite of KK. Edited November 12, 2014 by tortuosit Share this post Link to post Share on other sites
killzone_kid 1333 Posted November 12, 2014 @KKInteresting, but how is it when you change the variable inside the function? (@work, can't test) As i come from PHP there is 'call by reference' so you define the variable that you want to have in 'call by reference' mode so it gets updated outside of the function when it changes inside it. function myFnc($var1,$var2,&$var3) { //$var3 will be call by reference $var1++; $var2++; $var3++; } $var1 = 99; $var2 = 99; $var3 = 99; myFnc($var1,$var2,$var3); echo $var1; //result is 99 echo $var2; //result is 99 echo $var3; //result is 100 In your example you only read the variable inside the function and only change it outside it, so can i assume that 'call by reference' is not possible in sqf? By default all variables will be "called by reference". To stop this behaviour you need explicitly set them private: [color="#FF8040"]myfunc1 [color="#8B3E2F"][b]=[/b][/color] [color="#8B3E2F"][b]{[/b][/color] [color="#1874CD"]_a[/color] [color="#8B3E2F"][b]=[/b][/color] [color="#1874CD"]_a[/color] [color="#8B3E2F"][b]+[/b][/color] [color="#FF0000"]1[/color][color="#8B3E2F"][b];[/b][/color] [color="#8B3E2F"][b]}[/b][/color][color="#8B3E2F"][b];[/b][/color] myfunc2 [color="#8B3E2F"][b]=[/b][/color] [color="#8B3E2F"][b]{[/b][/color] [color="#191970"][b]private[/b][/color] [color="#7A7A7A"]"_a"[/color][color="#8B3E2F"][b];[/b][/color] [color="#1874CD"]_a[/color] [color="#8B3E2F"][b]=[/b][/color] [color="#1874CD"]_a[/color] [color="#8B3E2F"][b]+[/b][/color] [color="#FF0000"]1[/color][color="#8B3E2F"][b];[/b][/color] [color="#8B3E2F"][b]}[/b][/color][color="#8B3E2F"][b];[/b][/color] [color="#1874CD"]_a[/color] [color="#8B3E2F"][b]=[/b][/color] [color="#FF0000"]0[/color][color="#8B3E2F"][b];[/b][/color] [color="#191970"][b]call[/b][/color] myfunc1[color="#8B3E2F"][b];[/b][/color] [color="#191970"][b]hint[/b][/color] [color="#191970"][b]str[/b][/color] [color="#1874CD"]_a[/color][color="#8B3E2F"][b];[/b][/color] [color="#006400"][i]//1[/i][/color] [color="#1874CD"]_a[/color] [color="#8B3E2F"][b]=[/b][/color] [color="#FF0000"]0[/color][color="#8B3E2F"][b];[/b][/color] [color="#191970"][b]call[/b][/color] myfunc2[color="#8B3E2F"][b];[/b][/color] [color="#191970"][b]hint[/b][/color] [color="#191970"][b]str[/b][/color] [color="#1874CD"]_a[/color][color="#8B3E2F"][b];[/b][/color] [color="#006400"][i]//0[/i][/color][/color] Made with KK's SQF to BBCode Converter You cannot set private global vars though. Share this post Link to post Share on other sites
tortuosit 486 Posted November 14, 2014 (edited) Now it does not work. Outside script: [...] // no appearance of _seedvar at this point... #include "\@tort_DynamicWeather\script\fnc\tort_prng.sqf" <code> tort_prng.sqf: // Tortuosits simple random number generator // call: _myrandomnumber = [max] call prng; private "_seedvar"; prng = { private ["_i","_num","_out","_arr"]; _out = ""; for "_i" from 1 to 7 do { _num = sin(_i^3 + _seedvar) + 1; _arr = toArray str(_num); if ((count _arr) > 6) then {_out = _out + toString([_arr select ((count _arr) - 2)]);}; }; _seedvar = (1000000 - (parseNumber (_out))) % 1000000; ((_this select 0) * parseNumber ("0." + _out)) }; ArmA complains (I think it is at function compile time) about missing semicolon in line 4; (private "_seedvar";) usually then something is wrong before, if the semicolon exists. EDIT: My bad. It was a syntax error in another included script file. Edited November 14, 2014 by tortuosit Share this post Link to post Share on other sites
killzone_kid 1333 Posted November 14, 2014 Now it does not work.Outside script: [...] // no appearance of _seedvar at this point... #include "\@tort_DynamicWeather\script\fnc\tort_prng.sqf" <code> tort_prng.sqf: // Tortuosits simple random number generator // call: _myrandomnumber = [max] call prng; private "_seedvar"; prng = { private ["_i","_num","_out","_arr"]; _out = ""; for "_i" from 1 to 7 do { _num = sin(_i^3 + _seedvar) + 1; _arr = toArray str(_num); if ((count _arr) > 6) then {_out = _out + toString([_arr select ((count _arr) - 2)]);}; }; _seedvar = (1000000 - (parseNumber (_out))) % 1000000; ((_this select 0) * parseNumber ("0." + _out)) }; ArmA complains (I think it is at function compile time) about missing semicolon in line 4; (private "_seedvar";) usually then something is wrong before, if the semicolon exists. EDIT: My bad. It was a syntax error in another included script file. so you want your _seedvar variable to persist to the next script calling? You have to make it global then _seedvar -> seedvar Share this post Link to post Share on other sites
lappihuan 178 Posted November 14, 2014 By default all variables will be "called by reference". To stop this behaviour you need explicitly set them private: Since this seems to be the case, i think it's a very unpractical behavior of sqf. This can cause a lot of bugs and unexpected behavior for scripters that do not be aware of this. And even if you are aware of it, it's just annoying to define every variable that should NOT be "call by reference" than just define those that you want to be. I would really appreciate a change of this behavior in sqf. (ticket maybe?) Share this post Link to post Share on other sites
Tajin 349 Posted November 14, 2014 I doubt that will be changed as it could potentially break some existing scripts. Anyway just always generate your "private"-array and you'll be fine. The Poseidon editor has a tool that automatically generates it. If you're not using Poseidon, you can this instead: http://rising.at/projekte/ArmA/private.html Share this post Link to post Share on other sites
killzone_kid 1333 Posted November 14, 2014 Since this seems to be the case, i think it's a very unpractical behavior of sqf.This can cause a lot of bugs and unexpected behavior for scripters that do not be aware of this. And even if you are aware of it, it's just annoying to define every variable that should NOT be "call by reference" than just define those that you want to be. I would really appreciate a change of this behavior in sqf. (ticket maybe?) Granted someone may not know this and potentially get into trouble, but using unique names will already avoid this. Plus many many events in sqf start and finish in own scope (such as event handlers, triggers and other special scopes) so there is no way some variable can overlap by mistake (unless they are global vars, in which case people use unique names, like Bohemia uses BIS_everything). Spawn, execVM and execFSM have own scopes too. So really you could be in trouble only when you call function which calls function which calls function etc. You can also use http://killzonekid.com/arma-simple-private-variable-extractor/ if you are not sure. Share this post Link to post Share on other sites