Procedures that return pointers to structures

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Procedures that return pointers to structures

Post by PolyVector »

It would be nice if you wanted to return a structure if it was treated as a pointer to the struct....
This would be far more realistic than having the function return a copy of the struct (why do people even want that?)

Code: Select all

Structure Player
  Name$
EndStructure

Global GoodGuy.Player
Global BadGuy.Player

GoodGuy\Name$="PolyVector"
BadGuy\Name$="Robotnik"

Procedure.Player RandomPlayer()
  If Random(100)>50
    ProcedureReturn GoodGuy
  Else
    ProcedureReturn BadGuy
  EndIf
EndProcedure

Debug RandomPlayer()\Name$
RandomPlayer()\Name$="RandomGuy"
Codemonger
Enthusiast
Enthusiast
Posts: 384
Joined: Sat May 24, 2003 8:02 pm
Location: Canada
Contact:

Post by Codemonger »

couldn't you pass the address of the structure using the '@' ... or are you saying it should be more like .net, where every object is implicitly considered to be used or passed by reference or memeory address and not by value. Anyway not sure i understand ... funny code though
<br>"I deliver Justice, not Mercy"

    - Codemonger, 2004 A.D.
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

This way of doing things is pretty standard in C++ with the & (reference) symbol...
It can make for very dynamic code if used correctly... Anyways, it was only a suggestion....

Code: Select all

int x;

int &MyX()
{
  return x;
}

void main()
{
  MyX()=10;
  cout << MyX();
  return;
}
Maybe *Procedure would be a better way to declare it?
Oh well...
User avatar
GedB
Addict
Addict
Posts: 1313
Joined: Fri May 16, 2003 3:47 pm
Location: England
Contact:

Post by GedB »

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.
PolyVector
Enthusiast
Enthusiast
Posts: 499
Joined: Wed Sep 17, 2003 9:17 pm
Location: Southern California
Contact:

Post by PolyVector »

@GedB
I impliment pointers in insanely complex ways in my skin engine, FreeStyle... From my experience, this syntax would make my life a lot easier... I was suggesting this as merely a level of transparency/shortcut....

It would mean that this:

Code: Select all

Procedure.l GetPlayer()
    ProcedureReturn PointerToSomePlayer
EndProcedure

*GoodGuy.Player
*GoodGuy=GetPlayer()
Debug *GoodGuy\Name$
...could be written like this:

Code: Select all

Procedure.Player GetPlayer()
    ProcedureReturn PointerToSomePlayer
EndProcedure

Debug GetPlayer()\Name$
I wouldn't consider this to be 'cryptic syntax'... To me it is far more readable :D
If it clearifies things to use the *Pointer symbol... Then I would suggest This:

Code: Select all

Procedure.Player *GetPlayer()
    ProcedureReturn PointerToSomePlayer
EndProcedure

Debug *GetPlayer()\Name$
User avatar
GedB
Addict
Addict
Posts: 1313
Joined: Fri May 16, 2003 3:47 pm
Location: England
Contact:

Post by GedB »

Anything that encourages or assists the insanely complex use of pointers must be resisted. :twisted:
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

..

Post by NoahPhense »

GedB wrote:Anything that encourages or assists the insanely complex use of pointers must be resisted. :twisted:
lol

@pv
If Random(100)>50

Keep in mind that 0 is a factor of rnd(100)

If Random(102)>50 ; 0-50 = 51 & 51-102 = 51 ;)


*It's *good @to *see @people talking, @*about Pointers.

PS - anyone care to explain this one..

The @* <-- in the code below .. ive never seen it used before, but
apparently its working for the guy..

Code: Select all

*iError.w = 0 
GetState.w = 0 
Toggle.w =0 

; there is also AttachProcess() DetachProcess() 
; ..for your future adventures 

ProcedureDLL AttachThread(Instance) 
  OpenLibrary (0,"vcmain32.dll") 
EndProcedure 

ProcedureDLL HidePoints() 
  CallFunction (0,"VCSetPointDisplay",@*iError,0)  
EndProcedure 

ProcedureDLL ShowPoints() 
  CallFunction (0,"VCSetPointDisplay",@*iError,1) 
EndProcedure 

ProcedureDLL TogglePoints() 
  GetState.w = CallFunction (0,"VCGetPointDisplay", @iError) 
  Toggle.w = 1 - GetState.w 
  CallFunction (0,"VCSetPointDisplay",@*iError,Toggle.w) 
EndProcedure 

ProcedureDLL DetachThread(Instance) 
  CloseLibrary(0) 
EndProcedure
- np
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

It' to get the address of the pointer. The pointer is a long variable (.l) so you can get its address as any other variable.
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

..

Post by NoahPhense »

Fred wrote:It' to get the address of the pointer. The pointer is a long variable (.l) so you can get its address as any other variable.
Nifty, thanks Fred.

- np
Post Reply