marchitek Posted March 23, 2022 Posted March 23, 2022 Is there a way to pass (associative) array to function as parameter? I can see in documentation INT_VAR and STR_VAR, but missing ARRAY_VAR. Quote
argent77 Posted March 23, 2022 Posted March 23, 2022 Not directly. You can pass the array name to the function and use EVAL to access the array. Example: DEFINE_ACTION_FUNCTION MyFunc STR_VAR array = ~~ BEGIN ACTION_PHP_EACH EVAL ~%array%~ AS key => value BEGIN PRINT ~%key% => %value%~ END END ACTION_DEFINE_ASSOCIATIVE_ARRAY MyArray BEGIN ~first~ => ~1~ ~second~ => ~2~ ~third~ => ~3~ END LAF MyFunc STR_VAR array = ~MyArray~ END Quote
marchitek Posted March 24, 2022 Author Posted March 24, 2022 It works! I wasn't aware that inside function I can read variables outside function scope. Thanks! Quote
marchitek Posted March 25, 2023 Author Posted March 25, 2023 Year has passed and I'm already quite proficient with passing arrays to functions. Now I would you like to ask you about returning arrays from functions. But not simple arrays, those are easy to return with `RET_ARRAY` keyword. I'm wondering if there is good way to return array of arrays. Here is simple example: DEFINE_ACTION_FUNCTION test_function RET_ARRAY test_arrays BEGIN ACTION_DEFINE_ASSOCIATIVE_ARRAY test_1 BEGIN abc => 123 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_2 BEGIN abc => 234 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_arrays BEGIN 1 => test_1 2 => test_2 END END LAF test_function RET_ARRAY test_arrays END ACTION_PHP_EACH test_arrays AS key => value BEGIN PRINT ~%key%: %value%~ ACTION_PHP_EACH ~%value%~ AS key => value BEGIN PRINT ~%key%: %value%~ END END This only prints: 1: test_1 2: test_2 However desired output would be: 1: test_1 abc: 123 2: test_2 abc: 234 That is because test_1 and test_2 get cleared after function ends. In this exact example I could simply return also test_1 and test_2, but I'm looking for solution that would work when exact number of nested arrays is dynamic and not known upfront. Is there any way to accomplish that? Quote
subtledoctor Posted March 25, 2023 Posted March 25, 2023 46 minutes ago, marchitek said: ACTION_DEFINE_ASSOCIATIVE_ARRAY test_1 BEGIN abc => 123 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_2 BEGIN abc => 234 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_arrays BEGIN 1 => test_1 2 => test_2 END I'm not sure this is sufficient to make the function realize you are putting array names into this second arrays. It just seems like "test_1" and "test_2" are plain strings. Which is fine I guess, since the name of any array or string variable is ultimately just a string. But you have to let Weidu distinguish between a string-as-string and a string-as-variable-name. So: 50 minutes ago, marchitek said: ACTION_PHP_EACH test_arrays AS key => value BEGIN PRINT ~%key%: %value%~ ACTION_PHP_EACH ~%value%~ AS key => value BEGIN PRINT ~%key%: %value%~ END END Perhaps add an EVAL in the second/interior ACTION_PHP_EACH command? Also I would use different variables in each, just to keep things clear. So something like: ACTION_PHP_EACH test_arrays AS key_outer => value_outer BEGIN PRINT ~%key_outer%: %value_outer%~ ACTION_PHP_EACH EVAL ~%value%~ AS key_inner => value_inner BEGIN PRINT ~%key_inner%: %value_inner%~ END END ...Maybe? Quote
marchitek Posted March 25, 2023 Author Posted March 25, 2023 Unfortunately, array definitions and loops are correct here. Both this: ACTION_DEFINE_ASSOCIATIVE_ARRAY test_1 BEGIN abc => 123 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_2 BEGIN abc => 234 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_arrays BEGIN 1 => test_1 2 => test_2 END ACTION_PHP_EACH test_arrays AS key => value BEGIN PRINT ~%key%: %value%~ ACTION_PHP_EACH ~%value%~ AS key => value BEGIN PRINT ~%key%: %value%~ END END and this: DEFINE_ACTION_MACRO test_macro BEGIN ACTION_DEFINE_ASSOCIATIVE_ARRAY test_1 BEGIN abc => 123 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_2 BEGIN abc => 234 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_arrays BEGIN 1 => test_1 2 => test_2 END END LAM test_macro ACTION_PHP_EACH test_arrays AS key => value BEGIN PRINT ~%key%: %value%~ ACTION_PHP_EACH ~%value%~ AS key => value BEGIN PRINT ~%key%: %value%~ END END prints desired output: 1: test_1 abc: 123 2: test_2 abc: 234 The problem is that function scoping, which is super cool 99% of the time, here works against me. Quote
subtledoctor Posted March 25, 2023 Posted March 25, 2023 Any reason not to just use a macro, instead? Quote
kjeron Posted March 25, 2023 Posted March 25, 2023 Arrays in weidu only store strings/integers. The following is only storing the strings "test_1" and "test_2", not their arrays. ACTION_DEFINE_ASSOCIATIVE_ARRAY test_arrays BEGIN 1 => test_1 2 => test_2 END Any given string can reference both a variable and an array at the same time. Neither of the following interfere with each other: OUTER_SET test = 5 ACTION_DEFINE_ARRAY test BEGIN a b c d e f END As such, Weidu references an array only&always when it expects to do so (immediately after ACTION_DEFINE_ASSOCIATIVE_ARRAY, PHP_EACH, $, RET_ARRAY, etc..., excluding necessary EVALs.) If you want to return multiple arrays from a function, you must declare each of them as a RET_ARRAY in the function definition and the function call. DEFINE_ACTION_FUNCTION array_test STR_VAR a = ~~ b = ~~ c = ~~ d = ~~ RET_ARRAY EVAL ~%a%~ EVAL ~%b%~ EVAL ~%c%~ EVAL ~%d%~ BEGIN ACTION_DEFINE_ARRAY ~%a%~ BEGIN 0 1 2 3 etc END OUTER_SPRINT $~%b%~(0) value0 OUTER_SPRINT $~%b%~(1) value1 OUTER_SPRINT $~%b%~(etc) valueetc ACTION_DEFINE_ASSOCIATIVE_ARRAY ~%c%~ BEGIN 0 => 0 1 => 1 2 => 2 etc => etc END END LAF array_test STR_VAR a = test_1 b = test_2 RET_ARRAY test_1 test_2 END ACTION_DEFINE_ARRAY test_arrays BEGIN test_1 test_2 END ACTION_PHP_EACH test_arrays AS k => v BEGIN PRINT ~%k%:%v%~ ACTION_PHP_EACH ~%v%~ AS _ => op BEGIN PRINT ~%_%:%op%~ END END Quote
marchitek Posted March 25, 2023 Author Posted March 25, 2023 (edited) 2 hours ago, subtledoctor said: Any reason not to just use a macro, instead? Usual reasons to prefer functions over macros. Ofc this is not type of problem that blocks me from finishing my mod. It's just technical nuisance. Still, I'm curious if someone has some trick for that. 2 hours ago, kjeron said: If you want to return multiple arrays from a function, you must declare each of them as a RET_ARRAY in the function definition and the function call. That's pity. Technically it should be possible to have it resolved dynamically, since WeiDU arrays have dynamic size. But TBH I don't have good idea how syntax of this could look like to fit into general flavor. Maybe something like `RET_ARRAYS array` when "array" is arrays of array references to return. So WeiDU could iterate over this "array" and perform `RET_ARRAY` on each of them. *** Just for the record. Simplest solution for my example since arrays are statically defined in code would be: DEFINE_ACTION_FUNCTION test_function RET_ARRAY test_arrays test_1 test_2 // <- return all arrays here BEGIN ACTION_DEFINE_ASSOCIATIVE_ARRAY test_1 BEGIN abc => 123 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_2 BEGIN abc => 234 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_arrays BEGIN 1 => test_1 2 => test_2 END END LAF test_function RET_ARRAY test_arrays test_1 test_2 END // <- get all arrays there ACTION_PHP_EACH test_arrays AS key => value BEGIN PRINT ~%key%: %value%~ ACTION_PHP_EACH ~%value%~ AS key => value BEGIN PRINT ~%key%: %value%~ END END However, I was wondering for solution that would allow this for situation when we don't know all arrays upfront (e.g. when number of nested arrays is depending on state of overwrite directory etc). *** I think I came up with some workaround. It uses fact that RET_ARRAY works for arrays with composite keys. This way we can have macro to "box" array of arrays into one array with composite key and "unbox" macro to get our original array back. Here are macros: DEFINE_ACTION_MACRO BOX_ARRAY BEGIN ACTION_CLEAR_ARRAY ~%BOX_ARRAY%_box~ ACTION_PHP_EACH ~%BOX_ARRAY%~ AS key_0 => value_0 BEGIN ACTION_PHP_EACH ~%value_0%~ AS key_1 => value_1 BEGIN ACTION_DEFINE_ASSOCIATIVE_ARRAY ~%BOX_ARRAY%_box~ BEGIN ~%key_0%~, ~%value_0%~, ~%key_1%~ => ~%value_1%~ END END END END DEFINE_ACTION_MACRO UNBOX_ARRAY BEGIN ACTION_CLEAR_ARRAY ~%UNBOX_ARRAY%~ ACTION_PHP_EACH ~%UNBOX_ARRAY%_box~ AS key => _ BEGIN ACTION_CLEAR_ARRAY ~%key_1%~ ACTION_DEFINE_ASSOCIATIVE_ARRAY ~%UNBOX_ARRAY%~ BEGIN ~%key_0%~ => ~%key_1%~ END END ACTION_PHP_EACH ~%UNBOX_ARRAY%_box~ AS key => value BEGIN OUTER_SPRINT $~%key_1%~(~%key_2%~) ~%value%~ END END Here is example of usage: DEFINE_ACTION_FUNCTION test_function RET_ARRAY test_arrays_box BEGIN ACTION_DEFINE_ASSOCIATIVE_ARRAY test_1 BEGIN abc => 123 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_2 BEGIN abc => 234 END ACTION_DEFINE_ASSOCIATIVE_ARRAY test_arrays BEGIN 1 => test_1 2 => test_2 END OUTER_SPRINT BOX_ARRAY test_arrays LAM BOX_ARRAY END LAF test_function RET_ARRAY test_arrays_box END OUTER_SPRINT UNBOX_ARRAY test_arrays LAM UNBOX_ARRAY ACTION_PHP_EACH test_arrays AS key => value BEGIN PRINT ~%key%: %value%~ ACTION_PHP_EACH ~%value%~ AS key => value BEGIN PRINT ~%key%: %value%~ END END It produces desired output: 1: test_1 abc: 123 2: test_2 abc: 234 Still hoping for some "native" method. *** On a side note. I'm thinking about performance consequences of how WeiDU handles arrays. Passing array to function is done by reference, so it is super fast. In other words, when we pass array to function we pass only string that refers to it, without coping actual array content. However when function returns array, it is returned by value, so whole array is copied. Here is some nice practical consequence of it: However, I guess it can cause some performance problem when we pass and return big array back and forth. Something to keep in mind, but I haven't tested that closely. I just noticed recently that disk operation is not that big % of whole installation time and I started to pay attention to such things. Ofc this can only make difference for mods that do mass editing of game files. Edited March 25, 2023 by marchitek Quote
DavidW Posted August 22, 2023 Posted August 22, 2023 Very belated comment on this: instead of using an array of arrays, use a 2-dimensional array. WEIDU returns those just fine. Quote
Recommended Posts
Join the conversation
You are posting as a guest. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.