Official ScriptUO EasyUO Scripts > Scripting Chat

What is the proper way to handle this

(1/1)

Dirty Bob:
So I just recently started sending parameters through gosub and I'm trying to figure out what is considered the correct way or proper way to handle those parameters through multiple subs. Is it proper to send a parameter to a new sub using a parameter from the current sub you're in like:


--- Code: ---gosub TimeAndSaveCheck #TIME %2
:or
gosub ScanForWorldSave %2

--- End code ---

I feel like I even forget at times what variables I'm trying to call on when I get a few subs deep. At the same time it's localized and reusable with variation and easy to trace back if you need to. This is a larger example of what I'm doing in one script using some pseudo code


--- Code: ---set %mainLoop TRUE
repeat
{
      gosub Step1 #TIME #JINDEX
      gosub Step2 #TIME #JINDEX
      gosub Step3 #TIME #JINDEX
}
until %mainLoop = FALSE

sub Step1
Do Work
gosub TimeAndSaveCheck %1 %2
return

sub Step2
Do Work
gosub TimeAndSaveCheck %1 %2
return

sub Step3
Do Work
gosub TimeAndSaveCheck #TIME %2
Do More Work
gosub ScanForWorldSave %2
return

sub TimeAndSaveCheck
if %1 > #TIME - 60
   return TRUE
gosub ScanForWorldSave %2
return FALSE

sub ScanForWorldSave
for %i %1 #JINDEX
{
    scanjournal %i
    if The_world_is_saving in #JOURNAL || The_world_will_save in #JOURNAL
    {
       wait 30s
       break
    }
}
return



--- End code ---

TrailMyx:
EasyUO arguments are pretty basic.  They are nothing more than normal variables with a special purpose. 

%0 = number of arguments passed
%1 = argument 1
%2 = argument 2
%n = argument n

You can assign values to these within your subroutine just like you can with any other variable.  But say like in this example:


--- Code: easyuo ---set %testval 3gosub TestSub %testvaldisplay ok %testvalstop sub TestSub  set %1 4return 
This will print "3" because there's no construct in EasyUO for "call by reference".  You'd actually have to change the appropriate %1, %2, %n value.  Note that this behavior makes recursion difficult (but not impossible)

Not sure if I actually understood your question, but this is still a good discussion.

Dirty Bob:
I don't think I asked the question very well, but I had been wondering about your [set %1 4] example. I had stayed away from doing that because I figured it might be an issue. I also just learned from your post there are EUO code boxes  on here, nice.

I guess what I'm asking more about is what is considered the better coding practice. I know the below code works, but is it good practice to do it this way or actually set the variable? The second way clearly takes more steps and the first way seems the best route to take, but it's all very simple and short.


--- Code: easyuo ---gosub ScanForWorldSave %2; ####### Compared to #######set %someVariable %2gosub ScanForWorldSave %someVariable 
But what about when you take that same argument through multiple subs. In this example below I'm needing to access #JINDEX that was passed when the first sub was called but I don't need to access it until it made its way through four other subs on the way. Is passing the argument over and over until you reach the point you need it a good practice like in the first way I did it below? Or is it better to just declare a variable to use when you need it later down the line like in the second way I did it below.

--- Code: easyuo ---gosub firstSub #TIME #JINDEX sub firstSubgosub secondSub %1 %2return sub secondSubgosub thirdSub %1 %2return sub thirdSubgosub fourthSub %1 %2return sub fourthSubgosub fifthSub %2return sub fifthSubjournalScan %1return ; ####### Compared to ####### gosub firstSub #TIME #JINDEX sub firstSubset %neededJINDEX %2gosub secondSubreturn sub secondSubgosub thirdSub return sub thirdSubgosub fourthSubreturn sub fourthSubgosub fifthSub return sub fifthSubjournalScan %neededJINDEXreturn  

Gaderian:
Your questions are about variable scope in general. I will offer my opinion (take it with a grain of salt...), expand on options that are available and show an example to define some of it. It should help you learn more about what the language options are and what the technical terms are for you to read about in the documentation.

For your first examples, when the code is in ThirdSub and calls FourthSub, now returns to ThirdSub... both %1 and %2 are the same thing. Yikes! So I would avoid that kind of construct, because eventually you will write something complex enough that it will betray you.

In your second examples, you are using a global variable %neededJINDEX. This is very common in most scripts and we all do it all the time. It is not reusable code because of the variable scope violation.

There are about 5 categories of variables in Easyuo.
1) standard variables (%myvar, %yourvar - or whatever you wish to name it) which have global scope in the current script, but not in scripts running in parallel tabs.
2) variables passed on call/gosub statements (%0, %1, %2, etc (I shorthand refer to these as %#, but that isn't official) these are set with the call/gosub statement behind the scenes - so it is easy to insert code in the future that will cause relying on these to break)
3) registry written variables prefixed with '*' (*myvar, *yourvar, etc.) - sometimes these are called persistent or global. There are a few library routines available to read and write these. I would recommend the one that TrailMyx wrote, because when well planned out it is easier to follow.
4) namespace variables that are local (only available in the name space in the current script) are used to define more restrictive scope
5) namespace variables that are global (available to any script in any tab of the current Easyuo instance... when in that namespace)

My personal experiences are to not rely on the value of %0, %1, %2, etc variables other than in 2 places:
* Immediately at the start of a sub or called routine.
* Immediately after the return of a sub or exited routine, when the sub needs to return more than 1 value (1 value can be returned with the return statement - which populates #RESULT) and I usurped some %# variable(s). I have done that in ad hoc code that I consider temporary, but it's not a method for general programming structure. There are more reliable methods available which I would recommend (namespace local/namespace copy).

TrailMyx mentioned they are 'regular variables' meaning you can set and use these, but they come with the caveat that the next gosub/call may overwrite your values.

%0 is the number of parameters passed with the most recent gosub/call statement. It is overwritten with each gosub/call statement, so it is only valid at the start of the sub/library.
So the proper way to validate that your %# variables is to test how many parameters were passed into this subroutine or library by testing %0. If %0 = 0 ... no parameters were passed. If %0 = 3 - it means the optional parameter you coded for %4 was not passed and you should be supplying a default value at the beginning of your subroutine. ;)

If you want to protect your subroutine/library local variables, then you want to look at namespace commands. Namespace variables have the prefix: ! (!myvar, !yourvar, etc.)


--- Code: easyuo ---gosub setupgosub main   %characterdata1 %characterdata2 %characterdata3halt sub main namespace push namespace local main if %0 > 0  set !chard1 %1 if %0 > 1  set !chard2 %2 if %0 > 2  set !chard3 %3 else  set !chard3 defaultvalue while %end_condition = #false  {  ; do work  gosub Process1 !chard3  } namepace popreturn sub setup ; here define initialization or character specific data set %characterdata1 blah set %characterdata2 yes set %characterdata3 42return sub Process1 namespace push ; preserve the former namespace so we can return to it later namespace local Process1 if %0 > 0  set !chard1 %1  ; This chard1 is isolated from the !chard1 in the sub main else  set !chard1 some_default_value ; This chard1 is isolated from the !chard1 in the sub main  ; do work  namespace pop ; we are returning the former namespace that was in effect before the last namespace push commandreturn 
So the use of namespace can allow you to reuse the variable name !chard1 in a different namespace and it won't overwrite any other namespace that has a variable with seemingly the same name of !chard1.

In the namespace, the variable is prefixed with other variable name stuff that keeps it in this semi-private scope.

When coding for namespace variables, and you are trying to debug a situation - never underestimate the value of knowing what your present namespace is via the variables #NSNAME and #NSTYPE. Paying attention to those variables helps to keep scope issues sanely manageable.

%# variables are constantly overwritten by gosub/call statements... hence not reliable other than at the start of the routine. Technically you could set a value to pass back using those. It is rarely useful to do that. Instead use the namespace copy commands. You will thank yourself later for having learned how to do that and for keeping your coding style consistent. ;)

When using %# variables for passed parameters, always combine these with a test of %0 so you know if the %# variable you wish to take your value from really was just passed and not left over from some earlier gosub/call to a different routine.

When it comes to any programming, most often there are options for how to get to the desired result. Hopefully this gives you a little more background on what options are available.

Gaderian

Dirty Bob:
I guess scope was exactly what I was asking about. That's a lot of information that I have a ton of questions about after going through the documentation just now. I'm sure I'll be asking some more, but I'll go mess with some test scripts to see how many I can answer myself.   


--- Quote from: Gaderian on May 17, 2020, 08:58:10 PM ---For your first examples, when the code is in ThirdSub and calls FourthSub, now returns to ThirdSub... both %1 and %2 are the same thing. Yikes! So I would avoid that kind of construct, because eventually you will write something complex enough that it will betray you.
--- End quote ---

That was precisely what led me to pondering all of this in the first place. It was a simplified example of something I was doing in a script and it just seemed not right. I also thought about just always passing those first two arguments even when not needed to make it "standard" and that seemed ridiculous. I was trying to solve a problem with arguments that is clearly better to solve in other ways. I just want to learn good practices as I feel it'd help me in the future with any language.

I appreciate all of the help from you guys.

Navigation

[0] Message Index

Go to full version