What your code is really doing is returning a pointer to the variable. I don't like the way that it does this, because it is hidden behind some cryptic syntax.
Memory management is a nightmare, because the pointer can remain after the original value has been deleted.
In purebasic if you want to return a pointer, then you return a pointer: a long value that is exactly what it says it is. This helps you stay aware of how things really are.
Given your example code, if you call RandomPlayer() 100 times you still only have 2 instances of Player.
Take, for example, this code (valid pb, you can run it)
Code: Select all
Structure Player
Name$
EndStructure
Global GoodGuy.Player
Global BadGuy.Player
GoodGuy\Name$="PolyVector"
BadGuy\Name$="Robotnik"
Procedure.l RandomPlayer()
If Random(100)>50
ProcedureReturn @GoodGuy
Else
ProcedureReturn @BadGuy
EndIf
EndProcedure
DefType.Player *Player1, *Player2, *player3, *player4
*Player1 = RandomPlayer()
*Player2 = RandomPlayer()
*player3 = RandomPlayer()
*player4 = RandomPlayer()
Debug "Player1: " + *Player1\Name$
Debug "Player2: " + *Player2\Name$
Debug "Player3: " + *player3\Name$
Debug "Player4: " + *player4\Name$
*Player1\Name$="RandomGuy1"
*Player2\Name$="RandomGuy2"
*player3\Name$="RandomGuy3"
*player4\Name$="RandomGuy4"
Debug "Player1: " + *Player1\Name$
Debug "Player2: " + *Player2\Name$
Debug "Player3: " + *player3\Name$
Debug "Player4: " + *player4\Name$
Run it a couple of times and see how the result differ?
Is this the results you expected? I can't see them being worth much.
Tracing the problem is easier with PB. We are reminded that we are dealing with a pointer by the need to prefix the variable with an asterix and the functions declaration shows that it is returning a long, not a Player. We the C++ style all of this is hidden from us, an experienced programmer has to step away from the code an figure out what is really going on.
Quickly change the code so that it creates a copy of GoodGuy or BadGuy and returns that. Does this fix the problem? It creates new problems. How are you going to keep track of the memory used by each player? When will you free it? If you're writing a game that throws countless players at the user you could be creating thousands of players which only last a few seconds before being shot by the player. When will you reclaim their memory?
You can make this work, by dealing with this and dealing with that and the conclusion is inevitable: Objects. For objects to work properly you need garbage collection. Your code just got slower and your executable bigger.
You can add feature after feature to the language to help manage all of this, and you end up with an impenetrably complex language like C++.
PB takes a different path, it stays honest with the programmer and doesn't pretend to make difficult things simple. This is how it earns our respect.
There are a couple of solutions for this problem, and you choose which one based on your own needs keeping full control over all of it. I would favour:
Code: Select all
Structure Player
Name$
EndStructure
Procedure RandomPlayer(*Player.Player)
If Random(100)>50
*Player\Name$ = "PolyVector"
Else
*Player\Name$ = "Robotnik"
EndIf
EndProcedure
DefType.Player Player1, Player2, player3, player4
RandomPlayer(Player1)
RandomPlayer(Player2)
RandomPlayer(player3)
RandomPlayer(player4)
Debug "Player1: " + Player1\Name$
Debug "Player2: " + Player2\Name$
Debug "Player3: " + player3\Name$
Debug "Player4: " + player4\Name$
Player1\Name$="RandomGuy1"
Player2\Name$="RandomGuy2"
player3\Name$="RandomGuy3"
player4\Name$="RandomGuy4"
Debug "Player1: " + Player1\Name$
Debug "Player2: " + Player2\Name$
Debug "Player3: " + player3\Name$
Debug "Player4: " + player4\Name$
There are other methods, depending upon you needs. The good thing is it is easy to understand the tradeoffs you are making because everything is kept simple and out in the open.