Operator = vs. <=> - When using which?

You can talk about ManiaScript for ManiaPlanet here

Moderator: English Moderator

Post Reply
User avatar
m4rcel
Posts: 653
Joined: 15 Jun 2010, 11:12
Contact:

Operator = vs. <=> - When using which?

Post by m4rcel »

I have a question to the basic ManiaScript syntax: I am still not sure, when I have to use a simple = as assignment, and when to use <=>.

Of course, = must be always used when operating with native types like Integer, or Text, or arrays of these. On the other hand, the <=> is only used with objects, or at least the debugger only claims to use <=> instead of = when I assign an object to a variable.

So when exactly do I have to use the <=> operator?
Do I always have to use <=> when assigning an object? What happens (internal), when I still use = instead (except that the warning is raised by the Debugger)?

(I know this question is on an very expert level, but when there is a Debugger warning, there must be a significant difference between = and <=> ^^)
ImageImage
Image
User avatar
Gugli
Nadeo
Nadeo
Posts: 536
Joined: 14 Jun 2010, 17:35
Location: Mon PC est à Paris, mais mon coeur rode dans les forêts de Lozère

Re: Operator = vs. <=> - When using which?

Post by Gugli »

Ok, tough question. This is probably the most complicated thing in the script syntax.
But we've not (yet) managed to get rid of it.

Rule #1
In ManiaScript, class values are always stored as "aliases". Whatever the symbol you use when setting them. The warning is just here to remind you that <=> should be used.

First case

Here's an example :
There's a array of players, sorted by descending score, called Players.

Important note : we're talking here about an API array, one that's pre declared as a system variable.

One can write :

Code: Select all

declare BestPlayer <=> Players[0];  
   // Alice is the best player, so BestPlayer "points" to Alice
You would expect that :

Code: Select all

declare BestPlayer <=> Players[0];  
   // Alice is the best player, so BestPlayer "points" to Alice
{
    ... // Some code doing stuff
}
log(BestPlayer.Login); 
   // Will log Alice, right ???
In ManiaScript, BestPlayer is an alias. So BestPlayer means "The player in first position in the array Players". That's why, if scores have been changed, maybe it does not mean Alice anymore.

Code: Select all

declare BestPlayer <=> Players[0];  
   // Alice is the best player, so BestPlayer "points" to Alice
Players[1].Score += 1000; 
   // Give 1000 points to the 2nd best player, which is Bob

   // those 2 line are completely equivalent : 
   //    they Will log Bob, because he has an higher score right now.
log(BestPlayer.Login);
log(Players[0].Login);
In such cases, it become more clear that Class objects does not behave as Integer or Text values.
That's why we thought it would be better to use another symbol when setting variables : to remind that's not a plain affectation.

Now what if you want to keep Alice in a variable ?

The following code will work "as expected".

Code: Select all

declare BestPlayerId = Players[0].Id;  
    // BestPlayerId is an Ident : will never change
Players[1].Score += 1000; 
   // Give 1000 points to the 2nd best player, which is Bob
log(Players[BestPlayerId].Login); 
   // Will log Alice 
ProTip : Note that the "log" will be a bit more time-consuming than the previous way : we have to find Alice in the array of players, from the Ident.

ProTip #2 : Yes, this can also be written

Code: Select all

declare BestPlayer <=> Players[Players[0].Id];  
   // will be an alias to Players[AliceId] and not Players[0]. Huge difference !
Players[1].Score += 1000; 
   // Give 1000 points to the 2nd best player, which is Bob
log(BestPlayer.Login); 
   // Will log Alice. Will also costs more CPU, for the alias has to be resolved.  

Ok, I can do both ways. But is the alias system always used ?

Unfortunately, there are some edge cases where the aliases become a bit tricky....
What happens if you declare yourself an array of Classes.

Code: Select all

// Players[0] => Alice
// Players[1] => Bob
declare MyArray = [Players[0], Players[1]]; 
declare MyVal <=> MyArray[0];
MyArray = [Players[1], Players[0]];

log(MyVal.Login); // It will log "Alice", not what you may expect
If fact, when you write "MyVal <=> MyArray[0]", it means "take the alias that is stored in MyArray[0] and copy it in MyVal". So MyVal is an alias to Player[0], and not MyArray[0];
This is because the value stored in MyArray is already an alias, so we copy the alias directly, instead of making an alias to the alias. There are technical reasons : we can not easily do alias to aliases T_T'

(By now, every sane person should be confused... so don't worry if you are...)

Other hidden tricky cases ?

Actually there are : Functions returning Class objects. As with arrays, we have to make a difference between API functions and functions declared in script.

When you call an API function, the result will be a "simplified" alias. Those are unambiguous aliases referring to the object's Id, inside of an API-defined array.

Code: Select all

declare MyLabel <=> GetFirstChild("Label"); 
   // MyLabel is an alias to Page.MainFrame.Controls[IdOfTheFirstChildFound]
Is behaving exactly like

Code: Select all

declare MyLabel <=> Page.MainFrame.Controls[GetFirstChild("Label").Id];
So if there was an API function GetBestPlayer, the code

Code: Select all

declare BestPlayer <=> GetBestPlayer();  
   // Alice is the best player, so BestPlayer is an alias for Players[AliceId]
Players[1].Score += 1000; 
   // Give 1000 points to the 2nd best player, which is Bob

log(BestPlayer.Login); // Will log Alice
When dealing with script-defined functions, the aliases are directly copied (the same way it does when using script-defined arrays).

In both cases, the using a class value you obtained from a function call will never call the function again.

Are there some solutions to clean that mess up ?

- 1st solution : let it the way it is now. If people manage to understand this post, I guess it means that this syntax is not that awful.

- 2nd solution : always force the use of "simplified" aliases.

Code: Select all

declare BestPlayer <=> Players[0];  
// should behave exactly as
declare BestPlayer <=>  Players[ Players[0].Id ];
"Simplified" aliases behave roughly as pointers : the alias will always refer to the same player, and unless the players disconnect, it will always be valid. "declare BestPlayer" will always behave the way "declare BestPlayerId" did.
This solution has 1 problem though : it hides the "cost" of fetching players by Id. And in some cases, one may prefer handling the complexity if it allows more speed.

Any opinions on this would be greatly appreciated ^_^
--
(>~_~)> ═╦═ ╔╦╗ <(~_~<)
User avatar
m4rcel
Posts: 653
Joined: 15 Jun 2010, 11:12
Contact:

Re: Operator = vs. <=> - When using which?

Post by m4rcel »

Oha, that's a wall of a post xD

So let's see if I understood this whole thing correctly:
  • To answer my initial question, "When to use the <=> operator?": "Whenever there is a class object on the right side.", although there is no internal difference between = and <=>.
  • When using own arrays and functions, the alias behave the same as known from pointers in other languages, with the difference, that you do not see that it is actual an alias (like you do not see that you operate with pointers in Java). So once obtained, you always "hold" the same object in your variable.
  • The same is for API functions: The alias is simplified, so that you always "hold" the same object in the variable, whatever will happen after obtaining it. (So there is not really a difference between API and own functions?)
  • When using API arrays, the behavoir differs from that one known from other languages: If Alice is at index 0 of the Player-array, Player[0] means "Player object at index 0" and not "object of Alice". So if order changes, Player[0] will keep referring to "Player object at index 0", which must not be Alice anymore.
If everything is corrent, the most confusing point is, of course, the last one: You always have to make a difference between API array and own array. In the first case, the variable may change the object where it refers to (Bob gets better than Alice), in second case, the variable will always refer to the same object.


Personally, I would try to realize solution 2, to get the same behavoir as known from other languages. This will help newcomers leraning ManiaScript: Whenever a variable refers to Alice, it will remain referring to Alice, whatever happens in between. That the referred object can change is likely an unexpected behavior, especially because it only happens on API arrays.
To not loose the efficiency of the current behavior ("one may prefer handling the complexity if it allows more speed"), why not actually make the two operators different? Let's say, the = operator will have the same behavior like in other languages (i.e. simplified aliases), whereas <=> will remain the current behavior, allowing to make the script more efficient? (This means, that in most cases = will be used to assign objects, and only ery advanced scripts will make use of the <=> operator to get the last quantum of speed out of Maniaplanet ^^)
ImageImage
Image
User avatar
Gugli
Nadeo
Nadeo
Posts: 536
Joined: 14 Jun 2010, 17:35
Location: Mon PC est à Paris, mais mon coeur rode dans les forêts de Lozère

Re: Operator = vs. <=> - When using which?

Post by Gugli »

@m4rcel : You're entirely correct. Thanks for your input.

The solution with two different operators is what we plan to do now (explaining it made it so much clearer, the solution became quite obvious ^_^ some people call that rubberducking). It's quite good since it will be compatible with current scripts. As usual, I don't know when I'll do that though.
--
(>~_~)> ═╦═ ╔╦╗ <(~_~<)
User avatar
Gugli
Nadeo
Nadeo
Posts: 536
Joined: 14 Jun 2010, 17:35
Location: Mon PC est à Paris, mais mon coeur rode dans les forêts de Lozère

Re: Operator = vs. <=> - When using which?

Post by Gugli »

Ok. This has been done, and will be shipped in the next update.
--
(>~_~)> ═╦═ ╔╦╗ <(~_~<)
Post Reply

Return to “ManiaScript”

Who is online

Users browsing this forum: No registered users and 1 guest