Pass and return by-value for structures

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Pass and return by-value for structures

Post by Mistrel »

Passing structures to functions is already possible through pointers. This is fine except in the case where we actually want a copy:

Code: Select all

Procedure FuncA(*arg.Struct)
  Protected localArg.Struct
  CopyStructure(*a,@localArg,SizeOf(Struct))
  
  ...
EndProcedure
We can already make copies ourselves through CopyStructure() but this is tedious and requires resource tracking of the pointer passed into the function to guarantee its lifetime

Passing pointers is optimal for performance but adds a level of optimization which which is dangerous and often unnecessary. Note that resources will need to be tracked or copied in the event that data is passed on to threads or leaves scope which often makes this optimization redundant.

Pass-by-value is much simpler for these scenarios and the intent is clear. You are asking for and will receive a copy with a known lifetime as it will exist on the stack. (Note that collections contained therein are references on the heap but this requires its own consideration):

Code: Select all

Procedure FuncA(arg.Struct)
  ...
EndProcedure
Notice that we can already copy structures through assignment. If only we could get that result from a function:

Code: Select all

Structure Struct
  value.i
EndStructure

a.Struct
a\value=123

b.Struct
b=a

Debug b\value
Returning a structure is much more tedious. We must either pass it in as an argument:

Code: Select all

Structure Struct
  value.i
EndStructure

Procedure FuncA(*a.Struct)
  *a\value=123
EndProcedure

a.Struct
FuncA(@a)

Debug a\value
Or return it as memory on the heap which is both slower and requires resource management:

Code: Select all

Structure Struct
  value.i
EndStructure

Procedure.i FuncA()
  Protected *a.Struct
  
  *a=AllocateStructure(Struct)
  *a\value=123
  
  ProcedureReturn *a
EndProcedure

*a.Struct=FuncA()

Debug *a\value

FreeStructure(*a)
All of this can be avoided by returning by value:

Code: Select all

Structure Struct
  value.i
EndStructure

Procedure.Struct FuncA()
  Protected a.Struct
  
  a\value=123
  
  ProcedureReturn a
EndProcedure

Debug FuncA()\value
Possibly even from another function:

Code: Select all

Procedure.Struct FuncA()
  ProcedureReturn FuncB(1, 2, 3)
EndProcedure
Clearly there are performance penalties to these copy operations, especially when the lifetime is fleeting. But the advantages are real by simplifying resource management for those who are new to programming and providing another useful tool in the toolbox for those more experienced.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Pass and return by-value for structures

Post by Trond »

You do not need to use CopyStructure. PB can copy by assignment, and this can be done on pointers with a little trick:

Code: Select all

Structure Point
  x.d
  y.d
EndStructure

Structure PointByVal
  P.Point
EndStructure

Procedure ModifyLocalPoint(*P.PointByVal)
  Protected LocalPoint.Point = *P\P
  Debug LocalPoint\x
  Debug LocalPoint\y
  LocalPoint\x = 12345
  LocalPoint\y = 12345
  Debug LocalPoint\x
  Debug LocalPoint\y
EndProcedure

MyPt.Point
MyPt\x = 9999
MyPt\y = 9999
ModifyLocalPoint(MyPt)
Debug MyPt\x
Debug MyPt\y
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Pass and return by-value for structures

Post by wilbert »

Mistrel wrote:Pass-by-value is much simpler for these scenarios and the intent is clear. You are asking for and will receive a copy with a known lifetime as it will exist on the stack.
Passing and returning structures by value is simple for the user but not so easy for the compiler. It's not simply placing everything on the stack.
There are different calling conventions for 32 / 64 bit and they are not the same for each OS PureBasic supports.
MacOS and Linux 64 bit for example will pass some structures through cpu registers instead of stack.
Trond wrote:You do not need to use CopyStructure. PB can copy by assignment, and this can be done on pointers with a little trick:
Very nice. :)
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
IceSoft
Addict
Addict
Posts: 1616
Joined: Thu Jun 24, 2004 8:51 am
Location: Germany

Re: Pass and return by-value for structures

Post by IceSoft »

And it's little bit faster as CopyStructure() (of course ;-) )

Code: Select all

Structure Point3D
  x.w
  y.d
  z.d
  color.i
  *_next.Point3D
EndStructure

Structure Point3Dwrapper
  p.Point3D
EndStructure

Point3Dwrapper.Point3Dwrapper
Point3D.Point3D



StartTime.q = ElapsedMilliseconds() 
For n = 1 To 9999999
  CopyStructure(Point3D, Point3Dwrapper\p, Point3D)
Next n
Time1.q = ElapsedMilliseconds() - StartTime

StartTime = ElapsedMilliseconds() 
For n = 1 To 9999999
  Point3Dwrapper\P= Point3D
Next n
Time2.q = ElapsedMilliseconds() - StartTime


OpenConsole()
PrintN( StrF(time1))
PrintN( StrF(time2))
Repeat
      KeyPressed$ = Inkey()
Until KeyPressed$ = Chr(27)
CloseConsole()
Belive!
<Wrapper>4PB, PB<game>, =QONK=, PetriDish, Movie2Image, PictureManager,...
#NULL
Addict
Addict
Posts: 1440
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Pass and return by-value for structures

Post by #NULL »

In general, don't measure like this. The second case may have a cache advantage, or a disadvantage due to heat. If you swap the testcases the results are more or less identical. But your statement seems to hold, if you put both test loops in one additional loop for example.
User avatar
NicTheQuick
Addict
Addict
Posts: 1227
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Pass and return by-value for structures

Post by NicTheQuick »

If you copy a structure in a procedure it automatically isn't threadsafe because the content of the pointer could be changed after the procedure was called and before the copying was even executed. Keep that in mind.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: Pass and return by-value for structures

Post by Mistrel »

NicTheQuick wrote:If you copy a structure in a procedure it automatically isn't threadsafe because the content of the pointer could be changed after the procedure was called and before the copying was even executed. Keep that in mind.
This shouldn't happen as long as the copy is made in the current thread before it gets passed. The new copy to be passed along has its own pointer.
Post Reply