Author Topic: NameSpace Question: Maintaining namespace integrity with many:many relationship.  (Read 2972 times)

0 Members and 1 Guest are viewing this topic.

Offline lydaanTopic starter

  • Jr. Member
  • **
  • Posts: 70
  • Activity:
    0%
  • Reputation Power: 3
  • lydaan has no influence.
  • Respect: +6
  • Referrals: 0
    • View Profile
I, like probably many, was very confused and intimidated by NameSpace management for a long time. I recently started managing sub-variable integrity manually, and the relevance of namespaces finally became clear.

Instead of passing variables %0-%n to a static %sub_variable, and then deleting them at the exit of the sub, EUO already has tools to manage this for you. By declaring a local namespace for the sub and clearing it and recalling the previous namespace, all that legwork is handled for you (for the majority of scenarios).

My question has to do with push/pop and I'm looking for confirmation or correction on what I understand to be limitations. I am not an expert, but I believe I have the logic of namespace worked out.

Quote
*FYI*: For the context of this thread I will assume that any Sub will populate a sub-local namespace, and as such I will purposefully conflate "namespace," with "sub." I want to frame namespace management in the context of sub-local variable management so that namespaces novices like myself can more easily interpret a namespace use case.

This will likely be most people's first experience/need for NameSpace Management. The NameSpace function has more usages than sub-variable management, but grasping this specific usage will translate to understanding when other uses are necessary.

*Properly defining "many," without making assumptions (every sub will populate a sub-local namespace) quickly degrades into a recursive argument nightmare.

For those unfamiliar with NameSpace Push and Pop:
;---------------------------------------------------------------
NameSpace Push saves the current namespace as a temporary variable. Probably something like (pseudo-code) #pushed_nsname|type. All of a namespace's defined child !variables are stored within their parent namespace address, regardless of whether it was "pushed," or not.

NameSpace Pop sets the name space to the LAST "pushed," namespace AND can only be called once per push/pop (EUO seems to clear #pushed_nsname|type when pop is called).

If NameSpace Push is called multiple times before the cursor parses a NameSpace Pop, EUO will overwrite #pushed_nsname|type every time, destroying NameSpace Pop integrity.

As long as a sub maintains a 1:1 relationship, as in the called sub will only be called directly and does not call other subs, Push/Pop works fine.

Example of 1:1:
Code: easyuo
  1. ;current namespace = default namespace = local std
  2. body:
  3. ...
  4. gosub one_to_one
  5. ...
  6. goto body
  7.  
  8. sub one_to_one ;Sub One_To_One will only ever be called directly and never calls other subs.
  9.    namespace push ;Saves the current (local std) namespace, including
  10.                   ;   any defined !variables for recall with pop.
  11.    namespace local one_to_one ;Changes the current (local std) namespace to "local one_to_one."
  12.    ;Sub One_To_One Body.
  13.    ;Do Sub One_To_One things setting local !variables and referencing local !variables
  14.    ;   as well as setting script %variables to be passed to the script,
  15.    ;   and referencing script %variables previously defined.
  16.    ...
  17.    namespace clear ;Deletes all !variables for the current (local one_to_one) namespace.
  18.    namespace pop ;Changes the current (local one_to_one) namespace
  19.                  ;   back to the last_pushed (local std) namespace
  20.                  ;   and restores the stored !variables for it.
  21. return

But as soon as any directly called sub calls an/other sub(s), or a sub can be called directly and/or by an/other sub(s), or both/all (1:many || many:1 || many:many), push/pop integrity breaks down, and namespace integrity must be maintained manually. Luckily EUO also has #system_variables to handle this: #nsname and #nstype.
   *Note: There is more nuance to defining "many," but in the context of this thread,
              where I assume that all subs will populate a sub-local namespace,
              it is safe to assume my definitions above are correct.

My solution for this conundrum, for when I develop a new subroutine, is to assume that all subs will populate a sub-local namespace and have a many:many call relationship and manually store and delete #nsname and #nstype, and edit this out if I want to. Conversely I could assume this is not the case and add this in after the fact, but that doesn't change the solution.

Example solution for all relationship states (1:1 || 1:many || many:1 || many:many):
Code: easyuo
  1. sub many_to_many
  2.    set %many_to_many_nsname #nsname ;store the current #nsname and #nsntype
  3.    set %many_to_many_nstype #nstype ;before populating another namespace
  4.    namespace local many_to_many ;or whatever the sub is named
  5.    ;Do sub many_to_many things
  6.    ...
  7.    namespace clear
  8.    namespace %many_to_many_nstype %many_to_many_nsname
  9.    deletevar %many_to_many_nsname
  10.    deletevar %many_to_many_nstype
  11. return

This solution works the same as push/pop, except with several advantages:
   1. You don't have to know the final state of a sub's namespace relationship (n:n).
   2. It frees up push/pop for specified use elsewhere in your script/subs, if you prefer.
   3. You may ignore the current state of push/pop in publicly published subs.
   4. Each current namespace is permanently stored until all calls are returned.

The only disadvantage I can think of is that it costs 3 more lines/parse processes per potential push/pop, but that is immediately nullified when a potential push/pop push is overwritten.

Back to my original question, am I over-thinking this or is this a relevant solution?
In simpler terms, "Am I doing this right?" Or is there a better way?

Thanks for your time.
« Last Edit: September 21, 2021, 11:13:05 PM by lydaan »

Offline Gaderian

  • Elite
  • *
  • *
  • Posts: 486
  • Activity:
    0%
  • Reputation Power: 10
  • Gaderian barely matters.Gaderian barely matters.
  • Respect: +50
  • Referrals: 3
    • View Profile
Lines of code is fairly inconsequential for script speed. If your #LPC is 10 you do 10 lines in a time slice. If your LPC is 200, you do 200 lines in your timeslice. So with a moderate LPC having 3 lines of code makes a negligible difference.
So write code you need and adjust LPC later if needed.

I believe namespace push and pop can go many levels deep. I do not think you can reuse a namespace as unique, but enter the same namespace.
Use a systime based namespace name to be unique/or combine with random-if you need to. This would only be for very common used routines like a gump wait sub.
"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 lydaanTopic starter

  • Jr. Member
  • **
  • Posts: 70
  • Activity:
    0%
  • Reputation Power: 3
  • lydaan has no influence.
  • Respect: +6
  • Referrals: 0
    • View Profile
lol, thanks. you made me retest it... I didn't expect push/pop to be fully recursive (you know... EUO things and all). thanks for that. exactly what I was looking for. I overlooked something and solved a problem that didn't exist.
« Last Edit: September 22, 2021, 12:58:15 PM by lydaan »

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
I never really thought too much into it.  Generally I abused the stack-style of management knowing that you needed a pop for every push.  I'd allow for persistent namespaces for data required locally throughout a script or globally between scripting instances.  So for that I might push/pop but not clear so that the data will be there the next time I entered that particular context.

The push/pop allows for pretty fast context switching, and can get you into trouble if you're not balancing your flow well (i.e. exiting a sub without poping).

So perhaps you might be overthinking it a bit just because pushing and popping are really just one intended method to switch context, and as you point out you can also directly access the NSNAME and NSTYPEs.
« Last Edit: September 22, 2021, 01:05:40 PM by TrailMyx »
Please read the ScriptUO site RULES
Come play RIFT with me!

Offline lydaanTopic starter

  • Jr. Member
  • **
  • Posts: 70
  • Activity:
    0%
  • Reputation Power: 3
  • lydaan has no influence.
  • Respect: +6
  • Referrals: 0
    • View Profile
Quote
Generally I abused the stack-style of management knowing that you needed a pop for every push

I just assumed it wasn't recursive, so I didn't test for it. Turns out EUO gets to be recursive, but your scripts can't. It makes a lot more sense now after Gaderian made me test for it.

Quote
allow for persistent namespaces for data required locally throughout a script

I have something like this in a sub I'm designing, but am unsure as of yet if I will just copy variables or declare them in a unique namespace. need more testing to decide.

Quote
perhaps you might be overthinking it a bit

At this point, definitely. I can think why you might need access to NSNAME and NSTYPE, and how you would use them, but have no idea when such complexity would be necessary.

Thanks for the reply. I was feeling like an idiot, now I realize I was just being foolish.

Offline Gaderian

  • Elite
  • *
  • *
  • Posts: 486
  • Activity:
    0%
  • Reputation Power: 10
  • Gaderian barely matters.Gaderian barely matters.
  • Respect: +50
  • Referrals: 3
    • View Profile
+1
TrailMyx proved that EUO allows recursion with the CLAW.
You may find old documentation about limits to how many subs deep you can go, but I think Cheffe removed that limit at some point. You can still run out of memory.
My work on the bodfiller this summer proved that you can reenter the name space. The code reuses a few routines at different levels and it works fine. If the namespace is named the same thing (hard coded value) then you are in that same namespace each time you call it. When you need a unique namespace you have to get a little more clever.
Most scripts that want a unique namespace just use #systime to append to the namespace, but you could duplicate a namespace expecting it to be unique on a very fast setup with a high #LPC value. It would be rare, but it could happen - so if you need to guarantee it you would set an initialization value into the namespace and give yourself a slight idle moment to re-push the new namespace.

Here is an example of what I am trying to explain in untested code - just to show the logical points. This is the more generic verson, the complex version would be to maintain a unique id of all the namespaces in use to assign the next namespace, or keep a global variable increment counter - which I really feel is an ugly approach, but either of these mentioned options would avoid the 'sleep 1' (pauses the script for 1ms when it enters a namespace that existed already - which can only happen in rare instances anyway).
Code: easyuo
  1. sub unique_runner
  2.  set %namespacename Unique_ , #systime
  3.  namespace push %namespacename
  4.  if !Initialized <> N/A
  5.   {
  6.   namespace pop ; back out of already used namespace
  7.   sleep 1
  8.   set %namespacename Unique_ , #systime
  9.   namespace push %namespacename
  10.   }
  11.  set !Initialized #true
  12. ... ; continue with sub logic
  13.  
  14.  namespace pop
  15. return

A couple good variables rules to remember:
-TM's comment about matching push/pop is important, because if you execute a mis-matched push/pop combo you will end up in a different namespace than where you logically expect to be. When debugging namespace issues, pay attention to the #NSNAME and #NSTYPE to isolate when you find yourself in the wrong namespace.
-Variables prefixed with % or # are essentially global.
-Always verify %0 to know which %Nth passed parameters are valid at the start of a sub.

I thought I had namespace all figured out with my first large personal project. I added in some very useful routine that I stole from somewhere and it had the mis-matched push/pop issue. My project randomly failed because I was left in a namespace that was not mine and it took me a long time to be able to figure out what was wrong. I didn't figure that a prolific and well respected script author would have missed something like mis-matched push/pop in a utility routine, but it had happened. I think it took me a couple evenings after work staring it down to learn that lesson... (In my defense of seeming foolish, I had tested the code in it's own basic script before adding it to the large project, so I never noticed the namespace issue).

When I do large namespace global projects, I create an external menu that will display the current values of all namespace global variables I want to follow, which allows monitoring the values in real time without adding code into the project.
"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 lydaanTopic starter

  • Jr. Member
  • **
  • Posts: 70
  • Activity:
    0%
  • Reputation Power: 3
  • lydaan has no influence.
  • Respect: +6
  • Referrals: 0
    • View Profile
Now that I understand that for every push there should be a pop, push/pop already handles many:many.

This is the solution I came up for a more complex situation I'm dealing with:
Code: easyuo
  1. sub clientAction
  2.    namespace push
  3.    if clientAction notin #nsname || clientAction in #nsname && #nstype <> local
  4.       namespace local clientAction0
  5.    else 3
  6.       str right #nsname 1
  7.       set #strres #strres + 1
  8.       namespace local clientAction . #strres
  9.    ...
  10.    namespace clear
  11.    namespace pop
  12. return

glad I asked about how I assumed push/pop works. this new solution solves some other problems, like maintaining counter integrity within a sub. I realize that this solution will only work if the sub will never call itself indirectly.

If I need a sub to do that in the future, for some reason I don't as of yet, know, I'll just make a string handler to make a list of namespaces for every active namespace in order of declaration and then cut the last added value from the string_list for every pop.

I might do this anyway as an exercise, but at this point I'm distracting myself from writing a directory for all event macros.

Thanks for the help and ideas.

;-------

Ok, I didn't want to work on writing event macros, anyway...
Code: easyuo
  1. sub clientAction
  2.    namespace push
  3.    if local_clientAction notin %activeNamespaceList
  4.       namespace local clientAction
  5.    else 2
  6.       str count %activeNamespaceList local_clientAction
  7.       namespace local clientAction . #strres
  8.    set %activeNamespaceList %activeNamespaceList , | , #nstype , _ , #nsname
  9.    ...
  10.    gosub namespacePop clear
  11. return
  12.  
  13. sub namespacePop
  14.    if %1 = clear && %0 = 1
  15.       namespace clear
  16.    str count %activeNamespaceList |
  17.    set #strres #strres - 1
  18.    str left %activeNamespaceList #strres
  19.    set %activeNamespaceList #strres
  20.    namespace pop
  21. return
« Last Edit: September 23, 2021, 02:04:48 AM by lydaan »

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
The trick to get EasyUO to act recursively is to mimic how traditional languages allow for independent variable space to be ready upon each instance or iteration of a recursive loop.  As Gad points out, you just create a new namespace uniquely named, and also pass the count as a return value back to the previous instance to keep track of unraveling the recursive loop.  You typically get a very functional function that doesn't have alot of code.  Here's the specific instance taken from the CLAw that shows this functionality.  Here it's traversing a tokenized binary tree that has been pre-parsed and organized.

So EasyUO can't recurse on its own, but with a bit of scripting magic it can be coerced into similar functionality.

Code: easyuo
  1. sub EvaluateRuleChain
  2.   namespace push
  3.   namespace local RULES , %4
  4.   set !chain %1
  5.   set !findid %2
  6.   set !findtype %3
  7.   set !loot_match #FALSE
  8.   set !level %4 + 1
  9.   str del !chain 1 9
  10.   set !tempchain #STRRES
  11.   set !present_logic #FALSE
  12.   set !logic_toggle #FALSE
  13.   set !present_logic_operator N/A
  14.   namespace copy RULE* from local RULES
  15.   set !tempindex !rulechain_index . !tempchain - 1
  16.   set !chainindex 0
  17. EvaluateRuleChain_loop1:
  18.   set !temp_rule RULECHAIN_rule , !tempchain , _ , !chainindex
  19.   set !temp_rule ! . !temp_rule
  20.   set !temp_ruleindex RULEITEM , !temp_rule
  21.   if RULECHAIN notin ! . !temp_ruleindex
  22.   {
  23.     if !temp_rule in AND_OR_NOT
  24.     {
  25.       if !temp_rule = NOT
  26.         set !logic_toggle ! !logic_toggle
  27.       else
  28.         set !present_logic_operator !temp_rule
  29.     }
  30.     else
  31.     {
  32.       gosub EvaluateRule !temp_rule !findid !findtype
  33.       gosub CheckLogic
  34.     }
  35.   }
  36.   else
  37.   {
  38.     gosub EvaluateRuleChain ! . !temp_ruleindex !findid !findtype !level
  39.     gosub CheckLogic
  40.   }
  41.   set !chainindex !chainindex + 1
  42.   if !chainindex <= !tempindex
  43.     goto EvaluateRuleChain_loop1
  44.  
  45.   set !loot_match !present_logic
  46.   namespace copy loot_match to local RULES
  47.   set #RESULT !present_logic
  48.   namespace clear
  49.   namespace pop
  50. return #RESULT
  51.  

Note on line 38 where the function is calling itself again, but the last argument is a count of the depth of recursion.
« Last Edit: September 23, 2021, 10:13:53 AM by TrailMyx »
Please read the ScriptUO site RULES
Come play RIFT with me!

Offline lydaanTopic starter

  • Jr. Member
  • **
  • Posts: 70
  • Activity:
    0%
  • Reputation Power: 3
  • lydaan has no influence.
  • Respect: +6
  • Referrals: 0
    • View Profile
+1
I very much appreciate you posting that, as well as sort of translating what Gadarian was sharing. I looked at Gad's post and just thought... "hmmm, interesting. I have no idea what Gad is trying to do but it looks interesting." And I'm not trying to do anything that complex currently.

I was sort of guessing that you would use namespace copy to share relevant values across multiple instances of the same function, and you confirmed that by posting the CLAw recursion engine. This is well beyond what I'm trying to do at this moment, but I appreciate you posting that for reference.

Just for reference, 99% of my coding experience is within EUO. Probably ~2000 hours, the majority of which is fixing designed bugs or correcting for the client behaving unexpectedly. But thanks to this I can generally read any OO language without too much difficulty, after looking up vocabulary.

;----------------------

2 weeks ago, I had never used namespace except for passing a very limited amount of global variables between scripts/clients. This current interest basically started with wanting a sub to call another sub while maintaining the original gosub arguments (%0-n). I was storing the variables with a simple for() declaring %local_variables and then deleting them before returning.

Simplified example:
Code: easyuo
  1. sub clientAction
  2.    for %i 0 %0
  3.       set %local_ca . %i
  4.    ...
  5.    for %i 0 %local_ca0
  6.       deletevar %local_ca . %i
  7. return
*note: this specific case of deletevar does not work. you can concatenate within the deletevar parameter, but only under unique conditions.

I still have to do that, as the only other option I can think of is creating a passVar handler sub with n-if statements and subsequent gosubs with n-arguments, where n is the count/maximum number of possible gosub arguments in a script, and I don't want to write ~80 (or unknown) if statements (Sub MultiClientAction, a handler sub stores n clientAction gosub calls for specific situations), nor do I think this would be a beneficial solution.

Originally, I was looking at namespace for use of CLEAR, but quickly realized I can handle a lot of functionality by setting new namespaces within a sub as well as allowing for a sub to call itself without overwriting stored %variables by utilizing namespace-local !variables.

Sub ClientAction is really just a two state directory function with a single multi-state checkVar, that calls another directly callable sub to check for server/client-connection, and if lost, calls another directly callable login sub, ultimately retaining EUO cursor focus so that the script flow picks up at the last client action and script flow is maintained or easily regained. The goal is to funnel 99% of client interaction into a single checkVar/connection check, as connection to the server is an issue for me, and I'm trying to write as close to 24/7 (theoretical maximum) uninterrupted bot scripts.

Certain functions, like #property management for example, require the variable I'm checking against to be in a specific state, known or unknown, and I must set/confirm that state before checking for the intended resolution. I was originally handling this with a simple counter and cycling through the internal functionality with gotos, but this felt clunky.

Now, thanks to the discussion on this thread, I can implement a more elegant solution of having the sub call itself to set/confirm a checkVar state before checking the original argument.

For this specific case I only need access to the basic functionality of the sub while maintaining local variable integrity of the original call, and not the state of variables within recursive instances of the function. But now, if I need that as well, I have that option (or at least the groundwork) due to this discussion.

Your last post set my brain ablaze, TM. I've understood the concept of recursion for a long while, but never experienced a necessary use case. The last few hours have been a fun learning/understanding experience. I'd like to thank both you and Gad again for sharing your incites with me. I'm mostly done with questions regarding this topic for now, but if I need to tackle full EUO-style recursion, I'm sure I'll have more.
« Last Edit: September 24, 2021, 03:38:31 AM by lydaan »

Offline Gaderian

  • Elite
  • *
  • *
  • Posts: 486
  • Activity:
    0%
  • Reputation Power: 10
  • Gaderian barely matters.Gaderian barely matters.
  • Respect: +50
  • Referrals: 3
    • View Profile
You have to consider that some variables are EUO (the script engine) variables, then there are your script's variables.

You mentioned you want to preserve the %# variables (%0, %1, %2, ... %n), and do this with namespaces.

The prefix for namespace variables is ! (not %). So those sub parameters will not be preserved via namespaces.

Regardless of what you decide to do to preserve those parameter values, it will involve copying those 1 at a time. You could have a loop to copy those into another set of variables, but most of the time, preserving those is only valid at the start of a subroutine into variables you want to reference before the next 'gosub' or 'call' statement - when the values are replaced.

I can think of at least 1 way you could have a generic routine that would bring those into the current namespace. Here is the essence of what I am thinking:
Code: easyuo
  1. sub mytest
  2.  namespace push
  3.  namespace local _Mytest_
  4.  if %0 >= 0
  5.   {
  6.   for %ParameterIndex 0 %0
  7.    {
  8.    set ! . %ParameterIndex % . %ParameterIndex
  9.    }
  10.   }
  11.  
  12.  ; here do your subroutine logic ...
  13.  
  14.  namespace pop
  15. return
  16.  

I do not use deletevar because the documentation declares it deprecated, however, have you tested:
Code: easyuo
  1. deletevar % . local_ca . %i

"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 lydaanTopic starter

  • Jr. Member
  • **
  • Posts: 70
  • Activity:
    0%
  • Reputation Power: 3
  • lydaan has no influence.
  • Respect: +6
  • Referrals: 0
    • View Profile
0
Quote
You mentioned you want to preserve the %# variables (%0, %1, %2, ... %n), and do this with namespaces.

The prefix for namespace variables is ! (not %). So those sub parameters will not be preserved via namespaces.

I've already done this (as I explained in the same post). I was just showing what I was doing before, for anyone else who might find this thread at a later time. I often scroll through threads from years ago to see if a previous discussion involves something I'm working on.

Quote
I do not use deletevar because the documentation declares it deprecated, however, have you tested:
Code: easyuo
  1. deletevar % . local_ca . %i

yep. I've tried just about everything I can think of. the only thing I haven't tried yet is a %deletevar . %i as a string reference of the variable name, but I don't really care at this moment as it is no longer relevant. I'll do a full test later and do a write-up once I'm satisfied I've exhausted all options.

The wiki says "considered deprecated," not exactly deprecated and I would assume the spotty concatenation issue is due to it not being updated once "set %variable   ," was implemented.

The main reason why I prefer to use deletevar is because it supposedly deletes the address, or at least when you reference the address it returns "N/A," mimicking an undefined address. Conversely you could set %variable N/A, and I do this for persistent variables like #result, but my goal is to not populate anything that doesn't need to be. But that's me.

"set %variable  ," returns a value of " ," and if want to check against that you have to set another check variable, like %null to the same value to check against it.

Example:
Code: easyuo
  1. set %variable
  2. if %variable =    ;how do I check for this????
  3.  
  4. ;you must set a checkVar to the same value
  5. set %null
  6. if %variable = %null ;now you can check against %null

like in most situations there are many ways to solve this, but it comes down to personal preference.
« Last Edit: September 23, 2021, 10:37:40 PM by lydaan »

Tags: