Yukiko wrote:Just a bit of advice on the
SendSysMessage and other function calls that have default parameters. I usually specify the values by reference in the function call. Like this:
Code: Select all
SendSysMessage (who, "This message will be in green with a wide font.", font := 2, color := 66);
Using the references for the various options makes it more readable when trying to debug code but more importantly doing it that way you can change the colour or font without affecting the other default values used by that function.
Just a note; What you have done there is called using
Named Arguments/Parameters, by including the name before the value in the parameter list of the function call.
I say that, because the term 'reference' has a completely different meaning for function parameters; A parameter passed by reference is the opposite of passing it by value, and is similar to passing a pointer. It does not have anything to do with naming the parameter when calling the function.
When you pass a parameter by value, you are passing a copy of the value to the function. When you pass a parameter by reference, you pass instead a 'reference' to the memory location of the variable.
The main difference between the two is that when you pass a reference, any changes the function does to that reference affect the original variable. When you pass by value (the default), no changes carry through.
Consider the following simple code:
Code: Select all
use uo;
program test(who)
var victim := target(who);
SendSysMessage(who, victim.name);
GetNewVictim(victim, who);
SendSysMessage(who, victim.name);
endprogram
function GetNewVictim(what, who)
what := target(who);
endfunction
Run this, and target first yourself, and then another mobile. What do you think the results will be? Because GetNewVictim() declares both of its parameters as the default, "by value", no matter what you select with the second target, the second SendSysMessage will repeat the same victim.name as it said the first time.
However, do this one simple change:
Code: Select all
use uo;
program test(who)
var victim := target(who);
SendSysMessage(who, victim.name);
GetNewVictim(victim, who);
SendSysMessage(who, victim.name);
endprogram
function GetNewVictim(byref what, who)
what := target(who);
endfunction
Note the addition of the 'byref' keyword. That signifies that the 'what' parameter is being passed by reference. Instead of it making a separate, local copy of what for use within the function, it uses the same memory location.
When you run this code this time, and target two different things, you will get each of their separate names printed.
Another example:
Code: Select all
use uo;
program test(who)
var one := "1";
SendSysMessage(who, one);
Testing(one);
SendSysMessage(who, one);
endprogram
function Testing(what)
what := "2";
endfunction
Run this, and you will get:
1
1
Do the same simple change as noted above:
Code: Select all
use uo;
program test(who)
var one := "1";
SendSysMessage(who, one);
Testing(one);
SendSysMessage(who, one);
endprogram
function Testing(byref what)
what := "2";
endfunction
And this time, you get:
1
2
The default, by value, makes a 'copy' of the variable, which will not affect the original variable. Marking a parameter as 'byref' or by reference, means that the ADDRESS of the variable is passed, and so any assignments you do to the variable WILL carry through back in the original caller, if the original caller uses that variable again.
There's one place where this is very important: In Packet Hook scripts. You may have noticed packet hook functions are declared like so:
Code: Select all
function HandleB9(who, byref packet)
....
endfunction
The reason for this is simple; If you leave off the 'byref', then the 'caller' of the packet hook will not be given the changes you made to the packet, because 'byval' makes a separate copy.
Generally speaking, byref parameters aren't really needed all that often, particularly with parameters that are object references. Now, this might get confusing, but object references can themselves be passed by reference, or by value.
That is, you have to keep in mind that an 'object reference' or 'object variable' is itself a memory location that merely points to an instance of an object. That might sound confusing, but you actually already know this fact intuitively, because you know what this code does:
Code: Select all
program DotCommand(who)
who := target(who);
endprogram
When you run this, and target something other than yourself, you know that this code does not 'morph' your character into whatever you just targetted; it merely changes the 'who' reference to point to that object, instead of to you. So really, you already know what a 'reference' is. On the other hand, you also know what a 'value' is:
Code: Select all
program DotCommand(who)
who.color := 100;
endprogram
You know that who.color is a value - not a reference. (the fact that .color is a member of who is merely incidental to this discussion, and not actually central. I use it only because a simple variable would not cause an actual change in the world that you could see: your skin color changing). When you set who.color to a different number, you are actually changing the value of something - not just pointing a reference to a different object.
eScript variables are completely flexible - they can hold a reference one moment, and a value the next. Like so:
Code: Select all
program DotCommand(who)
who := 1;
endprogram
Running that code won't delete your character and turn it into a number 1; It will simply replace the 'who' reference with a value of 1.
=========================
So, we have variables that can be values and references. We also have function parameters that can be passed by value or by reference. What's the relation here? Does one type of variable demand a certain type of function parameter? No, it doesn't. You can pass either type of variable in either way: You can pass a reference variable byref or byval, and you can pass a value variable byref or byval (I'm not sure if there is a literal 'byval' keyword, but it's not needed; remember: the default, if you don't specify, is byval.)
Though it may have been subtle, my first two examples showed passing references byval and byref. I alternated between how to pass 'what', but in both cases, 'who' (the reference to the dot-command-user) was always byval. However, we know that 'who' refers to an object - your PC. That's perfectly valid.
What this means is when I pass 'who' to that function, a local copy of the value of 'who' is created on the stack for the function. The 'value' of that variable happens to be a reference. Confused yet? Yes.. a reference is, itself, a value.
If you pass that reference BY reference, any changes you do to that reference also 'pass back' to the caller, just as you saw with the 'what' parameter when we had the 'byref'. But when you pass the reference by value, no changes you do to the reference will pass back to the caller - the caller's "who" reference will remain safely pointed at you.
Errr... anyway; I know we didn't need all of that just now... but I did think it was important not to confuse the issue of 'reference' parameters/arguments to functions, because there is a specific meaning to that. You were using named arguments and in fact, NOT using reference parameters (because the function you are calling does not define its parameters as references, but instead as values.)