Nexus:TJI Scope of variables
Contents
Scope of Variables
Introduction to variables
A variable is an expression in a programming language that allows you to store information. Different languages have different methods and implementations for this (some don't even have them).
In nexus, variables are weakly typed. What does that mean, you may ask yourself? Well, it means that variables can store anything. The "how" is unknown to us, it could be dynamically typed like python or just not typed at all, like smalltak where they're just pointers. But that's not what's important. What is important, though, is that one variable can store anything, like numbers, objects, lists, etc.
So a variable you were using for, let's say, store a ship object
ship := GetSceneObj("My Ship");
can be then used to store something else, like a string. (although that's a horrible style of coding)
ship := "Hello World";
If you have had experience in other languages, you'll notice than in Black Ruler you don't have to declare the variables anywhere, you just invoke them. The name of the variable can be anything and it won't matter, except for the scope of said variable.
Scope of Variables
The "scope" of a variable means from where in the script that variable can be accessed.
"e." variables
These variables are vital to any code, and you'll probrably be using them a lot, so pay attention. They mark the lowest scope of all, and can only be reached from within the block they were first invoked, and when that block's finished executing they will disappear.
Examples:
a)
rule event DoSomething :action e.string:="Hello World"; Debug(e.string); LocalEvent(DoSomethingElse); :end END Rule event DoSomethingElse :action debug(e.string); :end END
in this case, in the debug screen it'll appear written "Hello World" and below it "0", as the two "e.string" variables are not the same.
b)
Rule event DoSomething :action e.string:="Hello World"; Delay(0,1, Debug(e.string); ,0); :end END
What would it appear on the debug screen? The answer is "0". We don't exactly know how, but the delay command generates a new block where all the variables present in that block are independant from the block they where called from.
c)
rule event DoSomething :action e.string:="Hello World"; Debug(e.string); LocalEvent(DoSomethingElse, e.string:="Hello again"); :end END Rule event DoSomethingElse :action debug(e.string); :end END
In this case, however, the debug screen will show "Hello world" and below it "Hello again". Why? because the string "Hello again" was passed as an argument to the DoSomethingElse rule and stored in that rule's "e.string" variable.
"p." variables
Those variables access the variables stored in the previous event. This always means the directly previous valid E. variables. It's used mainly, if not always, to pass parametres from one event to an other or from an event to a delay function.
Example: a) Going back to the variables of the rule the delay function is called
Rule event DoSomething :action e.string:="Hello World"; Delay(0,1, Debug(e.string); ,e.string:=p.string); :end END
This time in the debug screen it'll appear"Hello World", because the delay's "e.string" variable was declared with the content of the "DoSomething" rule's "e.string" variable (note that the name doesn't have to be the same, but it's good practice to keep it that way).
b)
rule event DoSomething :action e.string:="Hello World"; Debug(e.string); LocalEvent(DoSomethingElse, e.string:=p.string); :end END Rule event DoSomethingElse :action debug(e.string); :end END
Same as above. The "DoSomethingElse" Rule's e.string variable was declared with the "DoSomething" rule "e.string"'s content. Note that ALWAYS when passing arguments with functions like "LocalEvent", "MEvent", "ChangeState", "Delay", etc, you have to use the p prefix to access the variables of the rule this functions were called from, and that p prefix is only used to access the ones with the E prefix.
variables withouth a prefix
Those variables are what we could call "semi-global". Their scope extends within the machine they were first declared, so the contents of that variable can be accessed and changed from any rule in any state of that machine, and it can, of course, be passed as an argument to an other state in an other machine (in the form of a E. variable or any other). You're probably feeling excited about this type of variables, as you don't have to deal with passing parametres and e. or p. variables and all that. Well, don't. Global or semi-global variables are a bad deal in any programming language, and you must avoid them whenever it's possible, because they can break your code if you're not cautius or at least make it unreadable by someone on the outside, as keeping track of those variables in a complex code is a pain.
"M." variables
In all sense and purpose, these are global variables. Their scope extends towards the entire mission, meaning that any rule being executed in your mission can access it and change it. Same recommendation as before: Be careful with it. My recommendation is that use them only for declaring mission "constants" (like ships) or in the worst case some very specific boolean flag, nothing more.
"S." variables
These variables only make sense inside a selection, like the Execlist or SelectEx command. They only live through one iteration of said commands, so declaring them out of the blue doesn't make a lot of sense.
What's important about them, though, is that in those selections the selected object can accessed via the "s.this" variable you all head about. And as any s. variable it will change at the end of the cicle's iteration.