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 <=> ^^)
Operator = vs. <=> - When using which?
Moderator: English Moderator
- Gugli
- 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?
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 :
You would expect that :
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.
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".
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
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.
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.
Is behaving exactly like
So if there was an API function GetBestPlayer, the code
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.
"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 ^_^
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
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 ???
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);
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 #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
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]
Code: Select all
declare MyLabel <=> Page.MainFrame.Controls[GetFirstChild("Label").Id];
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
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 ];
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 ^_^
--
(>~_~)> â•â•¦â• ╔╦╗ <(~_~<)
(>~_~)> â•â•¦â• ╔╦╗ <(~_~<)
Re: Operator = vs. <=> - When using which?
Oha, that's a wall of a post xD
So let's see if I understood this whole thing correctly:
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 ^^)
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.
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 ^^)
- Gugli
- 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?
@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.
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.
--
(>~_~)> â•â•¦â• ╔╦╗ <(~_~<)
(>~_~)> â•â•¦â• ╔╦╗ <(~_~<)
- Gugli
- 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?
Ok. This has been done, and will be shipped in the next update.
--
(>~_~)> â•â•¦â• ╔╦╗ <(~_~<)
(>~_~)> â•â•¦â• ╔╦╗ <(~_~<)
Who is online
Users browsing this forum: No registered users and 1 guest