Author Topic: What is the proper way to handle this  (Read 2839 times)

0 Members and 1 Guest are viewing this topic.

Offline Dirty BobTopic starter

  • Newbie
  • *
  • Posts: 5
  • Activity:
    0%
  • Reputation Power: 1
  • Dirty Bob has no influence.
  • Respect: 0
  • Referrals: 0
    • View Profile
What is the proper way to handle this
« on: May 17, 2020, 10:17:45 AM »
0
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: [Select]
gosub TimeAndSaveCheck #TIME %2
:or
gosub ScanForWorldSave %2

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: [Select]
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


« Last Edit: May 17, 2020, 10:19:36 AM by Dirty Bob »

Offline TrailMyx

  • Officially retired from UO
  • Administrator
  • *
  • *
  • Posts: 13301
  • Activity:
    0%
  • Reputation Power: 154
  • TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!TrailMyx is awe-inspiring!
  • Gender: Male
  • Viper!
  • Respect: +1349
  • Referrals: 33
    • View Profile
    • ScriptUO
Re: What is the proper way to handle this
« Reply #1 on: May 17, 2020, 11:24:43 AM »
0
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
  1. set %testval 3
  2. gosub TestSub %testval
  3. display ok %testval
  4. stop
  5.  
  6. sub TestSub
  7.   set %1 4
  8. return
  9.  

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.
Please read the ScriptUO site RULES
Come play RIFT with me!

Offline Dirty BobTopic starter

  • Newbie
  • *
  • Posts: 5
  • Activity:
    0%
  • Reputation Power: 1
  • Dirty Bob has no influence.
  • Respect: 0
  • Referrals: 0
    • View Profile
Re: What is the proper way to handle this
« Reply #2 on: May 17, 2020, 12:29:59 PM »
0
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
  1. gosub ScanForWorldSave %2
  2. ; ####### Compared to #######
  3. set %someVariable %2
  4. gosub ScanForWorldSave %someVariable
  5.  

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
  1. gosub firstSub #TIME #JINDEX
  2.  
  3. sub firstSub
  4. gosub secondSub %1 %2
  5. return
  6.  
  7. sub secondSub
  8. gosub thirdSub %1 %2
  9. return
  10.  
  11. sub thirdSub
  12. gosub fourthSub %1 %2
  13. return
  14.  
  15. sub fourthSub
  16. gosub fifthSub %2
  17. return
  18.  
  19. sub fifthSub
  20. journalScan %1
  21. return
  22.  
  23. ; ####### Compared to #######
  24.  
  25. gosub firstSub #TIME #JINDEX
  26.  
  27. sub firstSub
  28. set %neededJINDEX %2
  29. gosub secondSub
  30. return
  31.  
  32. sub secondSub
  33. gosub thirdSub
  34. return
  35.  
  36. sub thirdSub
  37. gosub fourthSub
  38. return
  39.  
  40. sub fourthSub
  41. gosub fifthSub
  42. return
  43.  
  44. sub fifthSub
  45. journalScan %neededJINDEX
  46. return
  47.  
  48.  


Offline Gaderian

  • Elite
  • *
  • *
  • Posts: 486
  • Activity:
    0%
  • Reputation Power: 10
  • Gaderian barely matters.Gaderian barely matters.
  • Respect: +50
  • Referrals: 3
    • View Profile
Re: What is the proper way to handle this
« Reply #3 on: May 17, 2020, 08:58:10 PM »
+1
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
  1. gosub setup
  2. gosub main   %characterdata1 %characterdata2 %characterdata3
  3. halt
  4.  
  5. sub main
  6.  namespace push
  7.  namespace local main
  8.  if %0 > 0
  9.   set !chard1 %1
  10.  if %0 > 1
  11.   set !chard2 %2
  12.  if %0 > 2
  13.   set !chard3 %3
  14.  else
  15.   set !chard3 defaultvalue
  16.  while %end_condition = #false
  17.   {
  18.   ; do work
  19.   gosub Process1 !chard3
  20.   }
  21.  namepace pop
  22. return
  23.  
  24. sub setup
  25.  ; here define initialization or character specific data
  26.  set %characterdata1 blah
  27.  set %characterdata2 yes
  28.  set %characterdata3 42
  29. return
  30.  
  31. sub Process1
  32.  namespace push ; preserve the former namespace so we can return to it later
  33.  namespace local Process1
  34.  if %0 > 0
  35.   set !chard1 %1  ; This chard1 is isolated from the !chard1 in the sub main
  36.  else
  37.   set !chard1 some_default_value ; This chard1 is isolated from the !chard1 in the sub main
  38.  
  39.  ; do work
  40.  
  41.  namespace pop ; we are returning the former namespace that was in effect before the last namespace push command
  42. return
  43.  

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
« Last Edit: May 17, 2020, 09:45:38 PM by Gaderian »
"Go ahead ask me: 'Should I use hard waits or timers?'"
You say:"Should I"
Gaderian:"Timers!"
You Say:"use hard waits or timers?"

The serious side of timer use is illustrated here: http://www.scriptuo.com/index.php?topic=12094.msg101926#msg101926

However, every time I go back and look at this [AutoLooter] script, I realize I had wrote it in my zen state of EUO scripting - so it makes my brain hurt.

Offline Dirty BobTopic starter

  • Newbie
  • *
  • Posts: 5
  • Activity:
    0%
  • Reputation Power: 1
  • Dirty Bob has no influence.
  • Respect: 0
  • Referrals: 0
    • View Profile
Re: What is the proper way to handle this
« Reply #4 on: May 18, 2020, 08:51:09 AM »
0
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.   

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.

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.
« Last Edit: May 18, 2020, 08:52:46 AM by Dirty Bob »

Tags: