Byval myType PTR vs. myType as function parameter?

New to FreeBASIC? Post your questions here.
cbruce
Posts: 104
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Byval myType PTR vs. myType as function parameter?

Postby cbruce » Jun 12, 2018 17:36

.
I see cases where people have passed TYPEs as function parameters in one of two different ways. I am wondering why?

Code: Select all

TYPE type__t
    DIM x as INTEGER
END TYPE

DIM mytype as type__t

SUB somesub( BYVAL zzz as type__t PTR)
    ' PTR dereference
    zzz->x = 42
END SUB

SUB somesub2( zzz as type__t)
    ' DOT dereference
    zzz.x = 42
END SUB

somesub( @mytype)
somesub2( mytype)


Are there use cases where one method works and the other does not?
.
fxm
Posts: 8167
Joined: Apr 22, 2009 12:46
Location: Paris suburb, FRANCE

Re: Byval myType PTR vs. myType as function parameter?

Postby fxm » Jun 12, 2018 18:17

Pass a variable "byref" or pass its pointer "byval" to a procedure is fonctionally equivalent under the hood:
Because when you pass a variable "byref", the compiler passes the address of the variable (a pointer) "byval", and it adds some code for dereferencing the passed pointer when you use the reference in the procedure body.

By cons, passing "byval as any ptr" allows to pass variables of different types to a same procedure, but in order to use these variables, the "any ptr" pointer must be converted to the right type before dereference it in the procedure body.
sancho3
Posts: 263
Joined: Sep 30, 2017 3:22

Re: Byval myType PTR vs. myType as function parameter?

Postby sancho3 » Jun 12, 2018 21:28

Expanding on what FXM said:
In the code you showed you are:
- in the first case passing the address of variable 'mytype' to the procedure.
- in the second case FB defaults to ByRef for UDT's, so again you are passing the address of 'mytype' to the procedure.

Code: Select all

TYPE type__t
    DIM x as INTEGER
END TYPE

DIM mytype as type__t

SUB somesub( BYVAL zzz as type__t PTR)
    ' PTR dereference
    zzz->x = 42
   ? "Inside somesub()"
   ? "the address of the pointer 'zzz': "; @zzz
   ? "the address of the pointed data: "; @(*zzz)
   ? "testing the data pointed to:  "; *(zzz).x  ' note the dot operator
   ?
   
END SUB

SUB somesub2(/'this parameter defaults To byref '/ zzz as type__t)
    ' DOT dereference
    zzz.x = 42
   ? "Inside somesub2()"
   ? "the address of the pointer 'zzz': "; @zzz
   ? "made into a pointer:  "; (@zzz)->x  ' note the -> operator
   
   ' This next line is an error because zzz is not a pointer
   ' and cannot be dereferenced with '*'
   '? "not valid: "; @(*zzz)
   ?
END SUB

somesub( @mytype)
somesub2( mytype)
? "address of original variable 'mytype': "; @mytype
?


Sleep


Except for arrays, its a good idea to always specify ByRef/ByVal.
EDIT:
Check out the ugly inline comment I used here!
MrSwiss
Posts: 2679
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Byval myType PTR vs. myType as function parameter?

Postby MrSwiss » Jun 12, 2018 21:45

sancho3 wrote:SUB somesub2(/'this parameter defaults To byref '/ zzz as type__t)

Sorry, this is incorrect, because "not stated passing method" defaults to: ByVal, except in
cases, where default ByRef is implicit (Array's passing, where "specifiers" are forbidden).
fxm
Posts: 8167
Joined: Apr 22, 2009 12:46
Location: Paris suburb, FRANCE

Re: Byval myType PTR vs. myType as function parameter?

Postby fxm » Jun 12, 2018 22:07

In the -lang fb dialect, ByVal is the default parameter passing convention for all built-in types except String and user-defined Type which are passed ByRef by default.
fxm
Posts: 8167
Joined: Apr 22, 2009 12:46
Location: Paris suburb, FRANCE

Re: Byval myType PTR vs. myType as function parameter?

Postby fxm » Jun 12, 2018 22:15

cbruce
Posts: 104
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Re: Byval myType PTR vs. myType as function parameter?

Postby cbruce » Jun 12, 2018 22:23

.
Ok... so Type structures are not implicitly passed by reference in FB.

EDIT: Nope! wait a minute... I think MrSwiss says BYVAL, but fxm says BYREF ???

And in my OP... somesub() can change the type instance and the caller sees the changes... and in somesub2(), the caller does not see any changes made to that type instance inside the function.
.
sancho3
Posts: 263
Joined: Sep 30, 2017 3:22

Re: Byval myType PTR vs. myType as function parameter?

Postby sancho3 » Jun 12, 2018 22:32

@cbruce:
I am correct about the default being pass ByRef. See below.

@Mr. Swiss:
Incorrect. UDT Types are passed ByRef by default.
https://www.freebasic.net/wiki/wikka.php?wakka=KeyPgFunction
String and user-defined Types are passed Byref by default.

If you had run the code it would have been obvious. Please run the code and see for yourself.
In the following code the final print results in 43 not 42. Thus somesub2() has changed the variable contents.

Code: Select all

TYPE type__t
    DIM x as INTEGER
END TYPE

DIM mytype as type__t

SUB somesub( BYVAL zzz as type__t PTR)
    ' PTR dereference
    zzz->x = 42
   ? "Inside somesub()"
   ? "the address of the pointer 'zzz': "; @zzz
   ? "the address of the pointed data: "; @(*zzz)
   ? "testing the data pointed to:  "; *(zzz).x  ' note the dot operator
   ?
   
END SUB

SUB somesub2(/'this parameter defaults To byref '/ zzz as type__t)
    ' DOT dereference
    zzz.x = 43
   ? "Inside somesub2()"
   ? "the address of the pointer 'zzz': "; @zzz
   ? "made into a pointer:  "; (@zzz)->x  ' note the -> operator
   
   ' This next line is an error because the data pointed to is not a pointer
   ' and cannot be dereferenced with '*'
   '? "not valid: "; @(*zzz)
   ?
END SUB

somesub( @mytype)
somesub2( mytype)
? "address of original variable 'mytype': "; @mytype
?
? mytype.x

Sleep


@FXM:
Thanks for the correction.
coderJeff
Site Admin
Posts: 2614
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Byval myType PTR vs. myType as function parameter?

Postby coderJeff » Jun 13, 2018 3:53

For me, I find it typically depends on how I create the object that I am working with:
DIM x as T '' use BYREF as T parameters
DIM x as T PTR = new T '' use BYVAL as T PTR parameters

It's great that fbc supports pointers; it makes many data structures like lists and trees easy to work with. Except that when using pointers, you should also expect to get a NULL (zero) pointer and deal with that.

With dkl's work on BYREF variables, and BYREF function returns, not using pointers is also appealing. I find that using BYREF and . DOT member access tends to make the code a little easier to read and don't have to worry about @, *, -> operators.

Expaning on fxm's comment, I think more correctly:
BYREF as T
is closer to
BYVAL as T CONST PTR.

I always try to give the CONST-ness of parameters consideration when declaring routines; fbc can give catch a number of programming errors if you let it know how you expect a parameter to change (or not).
fxm
Posts: 8167
Joined: Apr 22, 2009 12:46
Location: Paris suburb, FRANCE

Re: Byval myType PTR vs. myType as function parameter?

Postby fxm » Jun 14, 2018 10:54

coderJeff wrote:With dkl's work on BYREF variables, and BYREF function returns, not using pointers is also appealing. I find that using BYREF and . DOT member access tends to make the code a little easier to read and don't have to worry about @, *, -> operators.

I fully agree.
It's why I'm waiting impatiently the continuing of development around references:
- adding the capacity to define arrays (static or dynamic) of references,
- adding the capacity to declare member references (variables and arrays) in UDTs,
so that they can also replace the use of pointers in these cases.

Don't forget the still open bug reports:
- #814 A global reference declaration cannot have an initializer which assigns an element of a global dynamic array
- #822 Compiler aborts when initializing a static byref member UDT with a local instance
- #842 BYREF (variable) does not report some assignment errors detectable on its internal pointer
dodicat
Posts: 5014
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Byval myType PTR vs. myType as function parameter?

Postby dodicat » Jun 15, 2018 13:32

Here is a byref udt pointer.
It doesn't work with -gen gcc.
But unfortunately the error given is not at all clear.

Code: Select all

 

Type points
    Public:
    Declare  Function set(As Ulong=0,As Byte=0,byref as points ptr=new points) Byref As points Ptr   'setter/getter
    Declare  Function box(As long,As long,As long, As long) As points Ptr
    declare  operator cast() as string 'print
    Private:
    As Long x,y             'a position
    as long EndOfPointer
    static as string  message 'a message
End Type

dim as string points.message 'activate static string
 
operator points.cast() as string 'print
return str(x) + " , " + str(y) + " = Centre of " + lcase(message)
end operator

'create an array of points at box corners, return the pointer
Function points.box(x1 As long,y1 As long,x2 As long,y2 As long) As points Ptr
    Dim As long dx=(x2-x1),dy=(y2-y1)
    Swap dx,dy:dx=-dx
    Static p(4) As points
    p(1)=Type(x1-dx/2,y1-dy/2)
    p(2)=Type(x1+dx/2,y1+dy/2)
    p(3)=Type(x2+dx/2,y2+dy/2)
    p(4)=Type(x2-dx/2,y2-dy/2)
    p(0)=Type<points>((x1+x2)\2,(y1+y2)\2) 'p(0) reserved for the the centre
    EndOfPointer=Ubound(p)
    message=__function__
    Return @p(0)
End Function
'getter setter function (instead of property)
Function points.set(c As Ulong,FillFlag As Byte,byref pt as points ptr) Byref As points Ptr
    Static As points Ptr p',pt
   ' pt=new points
    Function= p   'get
    If p Then     'set
        For n as long =1 To  EndOfPointer
            If n=1 Then Pset(p[n].x,p[n].y),c Else line -(p[n].x,p[n].y),c 
            if n= EndOfPointer then line (p[n].x,p[n].y)- (p[1].x,p[1].y),c ' close
        Next
        pt->x=p[0].x 'retrieve and return the centroid
        pt->y=p[0].y
        function=pt  'return the centroid
        If FillFlag Then Paint(p[0].x,p[0].y),c,c
         circle(pt->x,pt->y),3,,,,,f   
    End If
    delete p
    p=0
End Function

dim as long mx,my,btn
Dim As points  z
Screen 19,32
 #define fill 1
do
    getmouse mx,my,,btn

screenlock
cls
 if btn<=0 then mx=100:my=300:locate 4:print " Use left mouse button"
 
locate 2
z.set()=z.box(mx,my,400,300)      'get
print *z.set(Rgb(0,100,255),fill) 'set
screenunlock

sleep 1
loop until len(inkey)
Print "Done"
Sleep 
fxm
Posts: 8167
Joined: Apr 22, 2009 12:46
Location: Paris suburb, FRANCE

Re: Byval myType PTR vs. myType as function parameter?

Postby fxm » Jun 15, 2018 15:05

Seems to work in gas!

1)
Put as initializer 'New UDT' inside the UDT declaration is very daring.
At least put that declaration after the data fields!
Try with:

Code: Select all

Type points
    Private:
    As Long x,y             'a position
    as long EndOfPointer
    static as string  message 'a message
    Public:
    Declare  Function set(As Ulong=0,As Byte=0,byref as points ptr=new points) Byref As points Ptr   'setter/getter
    Declare  Function box(As long,As long,As long, As long) As points Ptr
    declare  operator cast() as string 'print
End Type
Compile in gcc:
- seems to work in gcc 32-bit,
- does not work in gcc 64-bit.

2)
Apart from that, your code in 'points.set()' is very unsafe.
'New' without 'Delete' => memory leak in the loop => used memory increasing indefinitely.

3)
With:

Code: Select all

Function points.set(c As Ulong,FillFlag As Byte,byref pt as points ptr) Byref As points Ptr
    Static As points Ptr p',pt
   ' pt=new points
    Function= p   'get
    If p Then     'set
        For n as long =1 To  EndOfPointer
            If n=1 Then Pset(p[n].x,p[n].y),c Else line -(p[n].x,p[n].y),c
            if n= EndOfPointer then line (p[n].x,p[n].y)- (p[1].x,p[1].y),c ' close
        Next
        pt->x=p[0].x 'retrieve and return the centroid
        pt->y=p[0].y
        function=pt  'return the centroid
        If FillFlag Then Paint(p[0].x,p[0].y),c,c
         circle(pt->x,pt->y),3,,,,,f   
    End If
'    delete p
'    p=0
End Function
works also in gcc 64bits, but always memory leaks.
dodicat
Posts: 5014
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Byval myType PTR vs. myType as function parameter?

Postby dodicat » Jun 15, 2018 16:38

It wasn't so much to fix anything, but to show the compile errors.
I don't use -gen gcc much, so I am surprised to see the (non freebasic) compile log/errors.
(Fbide)
In essence, you would have to get the c code, read the errors in the compiler log, and try and figure out where these errors are in the basic code.
fxm
Posts: 8167
Joined: Apr 22, 2009 12:46
Location: Paris suburb, FRANCE

Re: Byval myType PTR vs. myType as function parameter?

Postby fxm » Jun 15, 2018 16:54

With the full parameter declaration both in procedure declaration and definition, a warning message appears a little more clear:

Code: Select all

Type UDT
  Declare Sub s (Byval pu As UDT Ptr = New UDT)
  Dim As Integer I
End Type

Sub UDT.S (Byval pu As UDT Ptr = New UDT)
End Sub
FBIDETEMP.bas(6) warning 36(0): Mismatching parameter initializer, at parameter 1 (pu) of S()

By swapping the lines of the two member fields, the warning disappears.

Return to “Beginners”

Who is online

Users browsing this forum: No registered users and 2 guests