irswat Posted November 9, 2016 Share Posted November 9, 2016 Is it possible to return multiple values from a function? Link to comment Share on other sites More sharing options...
FrankFamily Posted November 9, 2016 Share Posted November 9, 2016 If they are the same type you can return then in a single array, otherwise i think it's not posible. A workaround i think should work if you need to return values of different types would be to have variables for those values, then the function that needs to return them simply updates the variables when it runs and returns true as in "the values were updated" and whatever called that functions receives the true and reads the variables (or properties) Link to comment Share on other sites More sharing options...
irswat Posted November 9, 2016 Author Share Posted November 9, 2016 I was able to extrapolate the missing information using variables that were already being passed. Thanks FF. Link to comment Share on other sites More sharing options...
irswat Posted November 9, 2016 Author Share Posted November 9, 2016 Almost got the parser finished for my voice engine. I think it will be pretty cool. Link to comment Share on other sites More sharing options...
NexusComa Posted November 10, 2016 Share Posted November 10, 2016 I use what I call work variables ... Int v0 = 0Int v1 = 0Int v2 = 0 I use the same variables many times in my scripts over and over to do "temp" work.Such as values I need to be returned from a function, a loop counter, a temp flag ... Link to comment Share on other sites More sharing options...
irswat Posted November 10, 2016 Author Share Posted November 10, 2016 I've begun doing the same. LoopCounter, etc. Link to comment Share on other sites More sharing options...
subhuman0100 Posted April 1, 2021 Share Posted April 1, 2021 Yep, an old post. But it came up as the first search result for me, so others are probably stumbling on it. If they are the same type you can return then in a single array, otherwise i think it's not posible.You can. Just not natively. With a few caveats and conditions. First, this method requires SKSE.Setting a variable is great, if they're on the same script. What if they're not?If you're returning an int, that's 32 bits. Consider it 31 because we don't want to screw with the sign bit because then you can be bringing Two's Complement into play if you want to look at your returned value. But whatever you're returning probably doesn't actually utilize all those 31 readily-used bits. We're going to push three unsigned 10-bit ints into that 32-bit int, then extract them on the far side.So your function calculated your three ints for you. Let's call them int1, int2 and int3. Remember they're limited in this example to ten bits, so that means a max value of 1023 each. But we're gonna check that. int1 = Math.LogicalAnd(int1, 0x000003FF) ; ensure it\'s not more than 10 bits in length - the above mentioned check int2 = Math.LogicalAnd(int2, 0x000003FF) ; or else it will (in later steps) overflow into int3 = Math.LogicalAnd(int3, 0x000003FF) ; the next int\'s space int returnInt = Math.ShiftLeft(int1, 10) ; bits 1-10 of int1 are now in position 11-20 on returnInt returnInt = Math.LogicalOr(returnInt, int2) ; the previous line is still true, but now also bits 1-10 of int2 are in returnInt\'s bits 1-10 returnInt = Math.ShiftLeft(returnInt, 10) ; now int1 is bits 21-30 of returnInt, and int2 is bits 11-20 returnInt = Math.LogicanOr(returnInt, int3) ; our send value is done, the previous line is still true, but we\'ve now stuffed int3 into positions 1-10 return returnIntGetting it out is easier. int returnedInt = TheFunctionAbove() int newInt3 = Math.LogicalAnd(returnedInt, 0x000003FF) ; pull out ten bits returnedInt = Math.ShiftRight(returnedInt, 10) ; shift right 10 bits int newInt2 = Math.LogicalAnd(returnedInt, 0x000003FF) ; pull out next ten bits int newInt1 = Math.ShiftRight(returnedInt, 10) ; shift right ten again for yes, this is my final answer ; voilaJust note that it is LIFO, reverse order from what they went in. If you're dealing with smaller values you can stuff more in (can anyone say 31 bools?) and if larger values then you're limited to less. They don't have to be equal length. You can shoehorn an int20 and an int8 in there. Or add in a couple of bools for good measure. Link to comment Share on other sites More sharing options...
ReDragon2013 Posted April 1, 2021 Share Posted April 1, 2021 (edited) Yes you are right. Its possible, but what are the costs?Its much more faster (and easier to handle) to use script variables, and take these in different functions. Only functions inside scripts like Scriptname Utility Hiddenwhich do not have an own self, would have benefit from your posted method. Because script variables and properties are not allowed. By the way you do not need SKSE functions to compress/uncompress three 10-bit digits in one 32-bit int variable. You can use the operator * and % to do this as well. Edited April 1, 2021 by ReDragon2013 Link to comment Share on other sites More sharing options...
dylbill Posted April 1, 2021 Share Posted April 1, 2021 Another option is to use a form array. You can return multiple form types that way if you know what you're expecting. That won't work for returning say an Int and a CK form like Actor, but will work for CK forms. Another option is to use dummy Object References with a script attached. Doing this you can set up something similar to Structs that Bethesda uses in Fallout4. Example: Let's say you do want to return an Int and an Actor. First attach this script to a new misc object: Scriptname TM_ObjectRefScript extends ObjectReference Int Property MyInt Auto Hidden Actor Property MyActor Auto Hidden Then in another script you can set up a function like this: Actor Property PlayerRef Auto MiscObject Property DummyMisc Auto ;this has the TM_ObjectRefScript attached Event OnInit() ObjectReference MyRef = StructFunction() TM_ObjectRefScript ScriptRef = MyRef as TM_ObjectRefScript ;access script on returned MyRef Actor AnActor = ScriptRef.MyActor Int AnInt = ScriptRef.MyInt ScriptRef.MyActor = None ;clear MyActor so MyRef can be deleted. MyRef.Delete() EndEvent ObjectReference Function StructFunction() ObjectReference DummyRef = PlayerRef.PlaceAtMe(DummyMisc, 1, 0, 1) ;place invisible DummyMisc object at player TM_ObjectRefScript ScriptRef = DummyRef as TM_ObjectRefScript ;access script on DummyRef ScriptRef.MyActor = Game.FindRandomActorFromRef(PlayerRef, 1000) ScriptRef.MyInt = Utility.RandomInt(0, 100) Return DummyRef EndFunctionYou could also have the "Struct" Script extend MiscObject and not use an object reference at all, but the reason I suggested object reference is that you can have multiple of them and have different values for MyActor and MyInt on each. So you could have your function return an Array of those ObjectReferences which is basically an array of structs. Link to comment Share on other sites More sharing options...
subhuman0100 Posted April 1, 2021 Share Posted April 1, 2021 (edited) ReDragon2013, the tone of your post seems to be that you're disagreeing with me, however the contents of your post seem to agree with what I said: That the original thread's premise that you cannot return multiple values from a function is incorrect. You've pointed out another way it can be done.I think we're both saying the same thing: this original thread, from five years ago, that for some reason is still high up on google's search results, will mislead people if it's what they come to. I showed one way it can be done, you've shown another. I think this is a good thing, so maybe the next person searching for this answer will see what we posted instead of "it can't be done" As for this: Its much more faster(and easier to handle) to use script variablesI'd need to see some profiling data on the claim of faster. Note that I did specify Setting a variable is great, if they're on the same script. What if they're not?cross-script value returns, so there is an overhead in accessing a variable from another script, as well as added complexity.Maybe I should be clearer, I'm talking about scripts that don't included each other, or extend each other- cases where one isn't the parent or child of the other. Unrelated scripts, for example if one extended ObjectReference and the other extended Quest. You can use the operator * and % to do this as wellFor the shifts, you definitely can. Multiplying and dividing by powers of two is a shift, and that's what any decently-optimized compiler will have in its output. However I don't like to make assumptions about what may or may not be optimized in Papyrus.i.e. * 2^n becomes SHL (left shift) n bits and /2^n is SHR (right shift) n bits For me, it's easier to visualize it shifting ten bits, than it is to multiply or divide by 2^10. But you bringing that up is a good point, it may make more sense for others to see it as division and multiplication instead of a shift. But I'm not sure where you're going with the modulus. Could you explain that? Because right now, how I'm trying to figure it out, you'd need at least one of the return values before you could use modulus to get the next. Edit: RL called me AFK while I was posting, and dylbill posted in the interim. This is what I was hoping for. Answers to this question, for the next time someone stumbles upon it looking for answers. Edit 2: I'd really like the example using modulus, because as I think about it more, it seems to me that using modulus would fail catastrophically if one or more of the returned values was zero. Edited April 1, 2021 by subhuman0100 Link to comment Share on other sites More sharing options...
Recommended Posts