Passing datatype ? (Solved)
Passing datatype ? (Solved)
Hi,
is possible in Freebasic to pass a datatype UDT to SUB/Function/etc.. ?
Explanation - I wrote 1 prototype routine for ALL reading of data from random accessed files via 1 PUT command.
Because of reading different datafileformats, I need to pass a datatype for buffer (from group of datatypes) or shared variable of that datatype.
In more words, say, program is like a game.It has 40 similar levels.
Every level reads different datafile with different dataformat.Sum of datatypes for random access read is 10.
So I need somewhere to define this parameter to be easily accessible via e.g.UDT array by index of gamelevel.
Searching in manual for "retype variable & datatype passing" had no success.
One&only interesting thing founded was "Overloading", but all examples are with base datatypes, NOT with UDTs.
Other was too complicated.Pointers etc.
Any help is appreciated, thank you.
is possible in Freebasic to pass a datatype UDT to SUB/Function/etc.. ?
Explanation - I wrote 1 prototype routine for ALL reading of data from random accessed files via 1 PUT command.
Because of reading different datafileformats, I need to pass a datatype for buffer (from group of datatypes) or shared variable of that datatype.
In more words, say, program is like a game.It has 40 similar levels.
Every level reads different datafile with different dataformat.Sum of datatypes for random access read is 10.
So I need somewhere to define this parameter to be easily accessible via e.g.UDT array by index of gamelevel.
Searching in manual for "retype variable & datatype passing" had no success.
One&only interesting thing founded was "Overloading", but all examples are with base datatypes, NOT with UDTs.
Other was too complicated.Pointers etc.
Any help is appreciated, thank you.
Last edited by ppf on May 11, 2019 8:21, edited 1 time in total.
-
- Posts: 789
- Joined: Jul 26, 2018 18:28
Re: Passing datatype ?
ppf wrote:Hi,
is possible in Freebasic to pass a datatype UDT to SUB/Function/etc.. ?
Code: Select all
Sub MyProc(ByRef Value As MyUDT)
End Sub
'or
Sub MyProc(Value As MyUDT Ptr)
End Sub
Re: Passing datatype ?
If the UDT list is predefined at compile time, and if the différent UDTn have a common UDT base-type that extends the Object built-in type, we can use the Run-Time Type Information to recover the right type:
Code: Select all
Type UDT Extends Object
End Type
Type UDT1 Extends UDT
' user fields
End Type
Type UDT2 Extends UDT
' user fields
End Type
Type UDT3 Extends UDT
' user fields
End Type
Sub UDTtest (Byval p As UDT Ptr)
If *p Is UDT1 Then Print "UDT1"
If *p Is UDT2 Then Print "UDT2"
If *p Is UDT3 Then Print "UDT3"
End Sub
Dim u1 As UDT1, u2 As UDT2, u3 As UDT3
Dim As UDT Ptr pUDT(1 To 3) = {@u3, @u1, @u2}
UDTtest(pUDT(1))
UDTtest(pUDT(2))
UDTtest(pUDT(3))
Sleep
Last edited by fxm on May 03, 2019 18:27, edited 1 time in total.
Re: Passing datatype ?
this may be naive, how about overloading your procedure for the differents types?
Re: Passing datatype ?
I assumed that ppf wanted to pass a data-type from a predefined data-type list (for example from a data-type array).
-
- Posts: 2958
- Joined: Jun 02, 2015 16:24
Re: Passing datatype ?
Not sure you meant Byref here. As far as I know, if we pass the address (ptr), then it will be more suitable to do it Byval. And if we pass the object, then Byref. Correct me if wrong of course.fxm wrote:
Sub UDTtest (Byrefp As UDT Ptr)
Re: Passing datatype ?
You are right.
In my draft version, I had passed a base-type reference from a base-type pointer array, by dereferencing the element of array.
I updated my code according to your remark.
In my draft version, I had passed a base-type reference from a base-type pointer array, by dereferencing the element of array.
I updated my code according to your remark.
-
- Posts: 2958
- Joined: Jun 02, 2015 16:24
Re: Passing datatype ?
Even the best do typos ;)
Re: Passing datatype ?
We all need each other.
Re: Passing datatype ?
We can even do without UDT. The Object built-in can directly be the base-type of each UDTn:
Code: Select all
Type UDT1 Extends Object
' user fields
End Type
Type UDT2 Extends Object
' user fields
End Type
Type UDT3 Extends Object
' user fields
End Type
Sub UDTtest (Byval p As Object Ptr)
If *p Is UDT1 Then Print "UDT1"
If *p Is UDT2 Then Print "UDT2"
If *p Is UDT3 Then Print "UDT3"
End Sub
Dim u1 As UDT1, u2 As UDT2, u3 As UDT3
Dim As Object Ptr pUDT(1 To 3) = {@u3, @u1, @u2}
UDTtest(pUDT(1))
UDTtest(pUDT(2))
UDTtest(pUDT(3))
Sleep
Re: Passing datatype ?
Hi,
I am back; was busy due unexpected crashes.Ehh, 3 days lost, program was ok, datafile value typo leads to error messages, never seen before.
Thank you all for tips.
Here is extracted short code from my program - six gamelevels + 4 Random file read/write buffers & UDTs.
to demonstrate the question..
Added fxm's way.Now compiled ok, but testprints gives wrong results.
Why ?
Seems, I am missing something there
old code
New version
I am back; was busy due unexpected crashes.Ehh, 3 days lost, program was ok, datafile value typo leads to error messages, never seen before.
Thank you all for tips.
Here is extracted short code from my program - six gamelevels + 4 Random file read/write buffers & UDTs.
to demonstrate the question..
Added fxm's way.Now compiled ok, but testprints gives wrong results.
Why ?
Seems, I am missing something there
old code
Code: Select all
#include "fbgfx.bi"
screen 19,32
'UDT for (6) game level setup
type gLevelUdt
as integer IDgl 'game level ID
as string*20 nameGL 'game level name
as string*15 dataFileNameGL 'game level data filename for RANDOM read
as string*10 glPathToDataFile 'path to game level data file
rwBuffer1 as any ptr 'buffer parameters here starts
rwBuffer2 as object ptr
buffType as integer
bufferLEN as integer
bufferSize as byte
'etc etc
end type
'just only 4 custom datatype - UDTs for RANDOM file read(write) of user data
'type rwRFileUdtA my way
type rwRFileUdtA Extends Object 'fxm way
as byte a
'etc etc
end type
'type rwRFileUdtB
type rwRFileUdtB Extends Object
as ushort b
as string*3 cs
'etc etc
end type
'type rwRFileUdtC
type rwRFileUdtC Extends Object
as single a
as ubyte c
as integer d
as string*8 fs
'etc etc
end type
'type rwRFileUdtD
type rwRFileUdtD Extends Object
as long dw
as single a
as ubyte c
as integer d
as string*10 ws
'etc etc
end type
'define global buffers for reading files
dim shared rwBuffieA as rwRFileUdtA
dim shared rwBuffieB as rwRFileUdtB
dim shared rwBuffieC as rwRFileUdtC
dim shared rwBuffieD as rwRFileUdtD
'define global variables of game level parameters
dim shared iGL as integer 'level index/counter
dim shared GLid as integer 'level ID
dim shared GLname as string*20 'level name
dim shared GLdataFileName as string*15 'datafilename
dim shared GLpathToDataFile as string*10 'path to datafilename
'etc etc
'initializing values
dim shared gameLevelsSum as integer=6 ' global - how much game levels in game
dim shared gameLevelSetup(1 to gameLevelsSum) as gLevelUdt ' global - array of each gamelevel parameter list
Dim As Object Ptr pUDT(1 To 4) = {@rwBuffieA, @rwBuffieB, @rwBuffieC, @rwBuffieD} 'fxm way
'filling a gamelevel setup array
with gameLevelSetup(1)
.IDgl=101
.nameGL="game Level no.1"
.dataFileNameGL="Level1.dat"
.glPathToDataFile="/levelData/"
'.rwRandomBuffer ??
.rwBuffer1=@rwBuffieA '??
.rwBuffer2=@rwBuffieA '??
.buffType=1
.bufferLEN=LEN(rwBuffieA)
.bufferSize=Sizeof(rwRFileUdtA)
'etc etc
end with
with gameLevelSetup(2)
.IDgl=208
.nameGL="game Level no.2"
.dataFileNameGL="Level2.dat"
.glPathToDataFile="/levelData/"
'.rwRandomBuffer ??
.rwBuffer1=@rwBuffieB '??
.rwBuffer2=@rwBuffieB '??
.buffType=2
.bufferLEN=LEN(rwBuffieB)
.bufferSize=Sizeof(rwRFileUdtB)
'etc etc
end with
'...
'etc
'...
with gameLevelSetup(6)
.IDgl=605
.nameGL="game Level no.6"
.dataFileNameGL="Level6.dat"
.glPathToDataFile="/levelData/"
'.rwRandomBuffer ??
.rwBuffer1=@rwBuffieC '??
.rwBuffer2=@rwBuffieC '??
.buffType=3
.bufferLEN=LEN(rwBuffieC)
.bufferSize=Sizeof(rwRFileUdtC)
'etc etc
end with
'random fileread routine - pass only filenumber by freefile, shared gamelevel ndex iGL and a record number to random read
Sub randomReadRecord(ByVal fileNr As integer,ByVal recN As Integer)
scope
/'
'a - using pointer
dim bufferRW as object ptr
'dim bufferRW as any ptr
'dim bufferRW as rwRFileUdtA ptr
'bufferRW=gameLevelSetup(iGL).rwBuffer2
'bufferRW= CAllocate(gameLevelSetup(iGL).bufferSize)
'bufferRW= CAllocate(1 * SizeOf(gameLevelSetup(iGL).rwBuffer2))
'bufferRW= Allocate(1 * SizeOf(gameLevelSetup(iGL).buffType))
bufferRW= CAllocate(1 * gameLevelSetup(iGL).bufferSize)
'/ /'
'b - using var ??
'var bufferRW= ?? gameLevelSetup(iGL).rwRandomBuffer ??
'var bufferRW=0 '??
'bufferRW=Cast(udt,z) '??
'Get #fileNr,recN,bufferRW
'/
Get #fileNr,recN,*bufferRW,1
'next line is routine to dereferencing buffer to datatype members - os ok to build it for me
'setGLevel(iGL,bufferRW) 'fill shared parameters - select case ONLY HERE
? "gameLevelSetup(iGL).bufferSize =";gameLevelSetup(iGL).bufferSize 'OK results printed
? "next line gives wrong results - why ?"
? " bufferRW= "; bufferRW;" Sizeof(bufferRW)= ";Sizeof(bufferRW);" LEN(bufferRW)= ";LEN(bufferRW) 'wrong results printed
deallocate (bufferRW)
end scope
end sub
? "Sizeof types A-D"
? Sizeof(rwRFileUdtA), Sizeof(rwRFileUdtB), Sizeof(rwRFileUdtC), Sizeof(rwRFileUdtD)
?
? "LEN Sizeof buffies A-D"
? LEN(rwBuffieA),Sizeof(rwBuffieA)
? LEN(rwBuffieB),Sizeof(rwBuffieB)
? LEN(rwBuffieC),Sizeof(rwBuffieC)
? LEN(rwBuffieD),Sizeof(rwBuffieD)
? "gameLevelSetup(1).rwBuffer2"
? gameLevelSetup(1).rwBuffer2
'? *gameLevelSetup(1).rwBuffer2
? "pUDT(1)"
? pUDT(1)
'? *pUDT(1)
'? "Typeof(pUDT) ";Typeof(pUDT)
if *pUDT(1) is rwRFileUdtA then ? "ifff ";Sizeof(rwBuffieA) ' var XNy=rwBuffieB
'? "XNy ";XNy
'here test random read routine
? "randomReadRecord() test.."
iGL=1 'set gamelevel 1
? iGL;" iGL"
randomReadRecord(3,3) 'dummy values to testing buffer variable functionality
?:?
iGL=2 'set gamelevel 2
? iGL;" iGL"
randomReadRecord(4,2)
?:?
iGL=6 'set gamelevel 6
? iGL;" iGL"
randomReadRecord(1,2)
sleep
end
Code: Select all
'here is simplified shorten code from my program - six gamelevels + 3 Random file red/write buffers
#include "fbgfx.bi"
screen 20,32
'UDT for 4 user datafile formats and parameters
type dataFRtype
indexFR as integer
notes as string
bufferType as string
bufferVariable as string
bufferPointer as any Ptr
bufferLEN as byte
bufferSize as byte
end type
'UDT for 6 game level setup
type gLevelUdt
as string dataFileNameGL 'game level data filename for RANDOM read
fileFormatParmsID as integer 'index of filetype parameters
' etc 'the rest of gamelevel parameters
end type
'(A-D) just only 4 custom buffer datatype - UDTs for RANDOM file reading of user data
type rwRFileUdtA
'type rwRFileUdtA Extends Object
as byte a
'etc etc
end type
type rwRFileUdtB
'type rwRFileUdtB Extends Object
as ushort b
as string*3 cs
'etc etc
end type
type rwRFileUdtC
'type rwRFileUdtC Extends Object
as single a
as ubyte c
as integer d
as string*8 fs
'etc etc
end type
type rwRFileUdtD
'type rwRFileUdtD Extends Object
as long dw
as single a
as ubyte c
as integer d
as string*10 ws
'etc etc
end type
'initializing values
const gameLevelsSum as integer=6 ' global - how much game levels in game
dim shared gameLevelSetup(1 to gameLevelsSum) as gLevelUdt ' global - array of each gamelevel parameter list
const bufferTypeSsum=4
dim shared fileReadParm(1 to bufferTypeSsum) as dataFRtype
dim shared ff as integer 'freefile in
'define global buffers for reading files
Static shared rwBuffieA as rwRFileUdtA
Static shared rwBuffieB as rwRFileUdtB
Static shared rwBuffieC as rwRFileUdtC
Static shared rwBuffieD as rwRFileUdtD
'pointers to buffers
Static Shared As rwRFileUdtA Ptr pA=@rwBuffieA
Static Shared As rwRFileUdtB Ptr pB=@rwBuffieB
Static Shared As rwRFileUdtC Ptr pC=@rwBuffieC
Static Shared As rwRFileUdtD Ptr pD=@rwBuffieD
'fill some buffer variable
'A
rwBuffieA.a=26
'B
rwBuffieB.b=12345
rwBuffieB.cs="XYZ"
'C
rwBuffieC.a=999.5
rwBuffieC.c=99
rwBuffieC.d=321000
rwBuffieC.fs="87654321"
'D
rwBuffieD.dw=123000456
rwBuffieD.a=23.4
rwBuffieD.c=101
rwBuffieD.d=23000
rwBuffieD.ws="0123456789"
'array of I/O parameters
'fill values for file format + buffer
with fileReadParm(1)
.indexFR=1 'just info
.notes="byte only" 'short overview
.bufferType="rwRFileUdtA" 'just info
.bufferVariable="rwBuffieA" 'just info
.bufferPointer=pA 'address const
.bufferLEN=LEN(rwBuffieA) 'lenght of variable
.bufferSize=Sizeof(rwRFileUdtA) 'size of type
end with
with fileReadParm(2)
.indexFR=2 'just info
.notes="ushort s" 'short overview
.bufferType="rwRFileUdtB" 'just info
.bufferVariable="rwBuffieB" 'just info
.bufferPointer=pB 'address const
.bufferLEN=LEN(rwBuffieB) 'lenght of variable
.bufferSize=Sizeof(rwRFileUdtB) 'size of type
end with
with fileReadParm(3)
.indexFR=3 'just info
.notes="single uis" 'short overview
.bufferType="rwRFileUdtC" 'just info
.bufferVariable="rwBuffieC" 'just info
.bufferPointer=pC 'address const
.bufferLEN=LEN(rwBuffieC) 'lenght of variable
.bufferSize=Sizeof(rwRFileUdtC) 'size of type
end with
with fileReadParm(4)
.indexFR=4 'just info
.notes="long suis" 'short overview
.bufferType="rwRFileUdtD" 'just info
.bufferVariable="rwBuffieD" 'just info
.bufferPointer=pD 'address const
.bufferLEN=LEN(rwBuffieD) 'lenght of variable
.bufferSize=Sizeof(rwRFileUdtD) 'size of type
end with
'define global variables of game level parameters
dim shared iGL as integer 'level index/counter
'etc
'filling of gamelevel setup array
with gameLevelSetup(1)
.dataFileNameGL="Level1.dat"
.fileFormatParmsID=1 'array index of I/O parameters
'etc etc
end with
with gameLevelSetup(2)
.dataFileNameGL="Level2.dat"
.fileFormatParmsID=2
'etc etc
end with
with gameLevelSetup(3)
.dataFileNameGL="Level3.dat"
.fileFormatParmsID=3 'array index of I/O parameters
'etc etc
end with
with gameLevelSetup(4)
.dataFileNameGL="Level4.dat"
.fileFormatParmsID=4
'etc etc
end with
'etc
'show it - check default data
Sub showReadinParameters(byval i as integer)
? ,"indexFR ";fileReadParm(i).indexFR 'index in array
? ,"bufferType ";fileReadParm(i).bufferType
? ,"bufferVariable ";fileReadParm(i).bufferVariable
? ,"bufferPointer ";fileReadParm(i).bufferPointer
?
end sub
'testin - print buffer members
sub printBufferMembers(byval id as integer)
? "testin - print buffer members ... buffer type id= ";id
var p=fileReadParm(id).bufferPointer
select case id
case 1
? "->a "; cast(Typeof(rwBuffieA) ptr, p)->a
' ? "->a2 "; Cptr(rwRFileUdtA ptr, p) '->a
case 2
? "->b "; cast(Typeof(rwBuffieB) ptr, p)->b
? "->cs "; cast(Typeof(rwBuffieB) ptr, p)->cs
case 3
? "->a "; cast(Typeof(rwBuffieC) ptr, p)->a
? "->c "; cast(Typeof(rwBuffieC) ptr, p)->c
? "->d "; cast(Typeof(rwBuffieC) ptr, p)->d
? "->fs "; cast(Typeof(rwBuffieC) ptr, p)->fs
case 4
? "->dw "; cast(Typeof(rwBuffieD) ptr, p)->dw
? "->a "; cast(Typeof(rwBuffieD) ptr, p)->a
? "->c "; cast(Typeof(rwBuffieD) ptr, p)->c
? "->d "; cast(Typeof(rwBuffieD) ptr, p)->d
? "->fs "; cast(Typeof(rwBuffieD) ptr, p)->ws
' ?
' ? "->a4 "; Cptr(rwRFileUdtD ptr, p) '->a
end select
end sub
'random fileread routine (second version)- pass only numer of record and index of datafileformat array
Sub randomReadRecord2(byval recN As Integer,byval id as integer)
'Sub randomReadRecord2(byval recN As Integer,byval id as integer, pX as any pointer)
? ".. Get" 'testin
showReadinParameters(id) 'testin
var p=fileReadParm(id).bufferPointer
? "bufferPointer= ";p
'var AA= 'here setup buffer done
' get #ff,recN,*cast(Typeof(AA) ptr, p),1
' printBufferMembers(id) 'testin - print buffer members
end sub
? "Sizeof types A-D "; Sizeof(rwRFileUdtA), Sizeof(rwRFileUdtB), Sizeof(rwRFileUdtC), Sizeof(rwRFileUdtD)
?
? "LEN Sizeof buffies A-D pointers pA-D"
? LEN(rwBuffieA),Sizeof(rwBuffieA),pA
? LEN(rwBuffieB),Sizeof(rwBuffieB),pB
? LEN(rwBuffieC),Sizeof(rwBuffieC),pC
? LEN(rwBuffieD),Sizeof(rwBuffieD),pD
'simulation starts here
var aqa=1
var bbq=1
'create files
dim as integer fx(1 to 4) 'freefile
var aqar=10 'dummy
for i as integer=1 to 4
fx(i)=freefile()
aqar=fileReadParm(i).bufferSize
open gameLevelSetup(i).dataFileNameGL for random as #fx(i) Len=aqar
next i
put #fx(1),,rwBuffieA 'create files
put #fx(2),,rwBuffieB
put #fx(3),,rwBuffieC
put #fx(4),,rwBuffieD
close
'simulate flow
'select gamelevel - GUI, manual etc
iGL=1 ' e.g. 1
? "gamelevel ";iGL;" =iGL",
'open needed datafile
ff=freefile()
aqa=fileReadParm(gameLevelSetup(iGL).fileFormatParmsID).bufferSize 'just for shorter notation
bbq=gameLevelSetup(iGL).fileFormatParmsID
open gameLevelSetup(iGL).dataFileNameGL for random as #ff Len=aqa
randomReadRecord2(1,bbq)
close:?
iGL=3 ' set gamelevel 6 e.g.
? "gamelevel ";iGL;" =iGL",
'open needed datafile
ff=freefile()
aqa=fileReadParm(gameLevelSetup(iGL).fileFormatParmsID).bufferSize 'just for shorter notation
bbq=gameLevelSetup(iGL).fileFormatParmsID
open gameLevelSetup(iGL).dataFileNameGL for random as #ff Len=aqa
randomReadRecord2(1,bbq)
close:?
iGL=4 'set gamelevel 3
? "gamelevel ";iGL;" =iGL",
'open needed datafile
ff=freefile()
aqa=fileReadParm(gameLevelSetup(iGL).fileFormatParmsID).bufferSize 'just for shorter notation
bbq=gameLevelSetup(iGL).fileFormatParmsID
open gameLevelSetup(iGL).dataFileNameGL for random as #ff Len=aqa
randomReadRecord2(1,bbq)
close:?
close
? "ended, press key..."
sleep
end
Last edited by ppf on May 11, 2019 8:15, edited 1 time in total.
Re: Passing datatype ?
In your code above, bufferRW is not declared because of the multi-line comment block.
In any cases, bufferRW must be declared as a typed pointer (<> Any Ptr, and <> object Ptr), for example as a pointer to a UDT.
In any cases, bufferRW must be declared as a typed pointer (<> Any Ptr, and <> object Ptr), for example as a pointer to a UDT.
-
- Posts: 2958
- Joined: Jun 02, 2015 16:24
Re: Passing datatype ?
Hi ppf,ppf wrote:Code: Select all
'type rwRFileUdtB type rwRFileUdtB Extends Object as ushort b as string*3 cs 'etc etc end type
As far as I understand what you want to do here, with the part with GET# that requires the buffer size. I'm thinking of this:
Code: Select all
type BASEOBJECT extends OBJECT
declare abstract function MySize() as integer
end type
type UDT1 extends BASEOBJECT
declare function MySize() as integer
as integer _dummy(1 to 1000)
end type
function UDT1.MySize() as integer
#print typeOf(THIS)
return sizeOf(THIS)
end function
dim as UDT1 uu
? sizeOf(BASEOBJECT)
? sizeOf(uu)
? uu.MySize()
Maybe it's not what you want. Anyway you still can force your UDTs to embed certain identical procedures that give information on themselves, even if you don't know anything of the variable. This way you don't have to use an external description like an enum and so on. You just have to know the name of the procedures you know being defined, and call them.
Re: Passing datatype ?
To take advantage of polymorphism (with the 'MySize()' abstract method declared in the 'BASEOBJECT' base-type), you must call 'MySize()' on base-type [ptr] typed variables:
Otherwise, the 'BASEOBJECT' base-type with its abstract method is useless.
Code: Select all
type BASEOBJECT extends OBJECT
declare abstract function MySize() as integer
end type
type UDT1 extends BASEOBJECT
declare function MySize() as integer
as integer _dummy(1 to 1000)
end type
function UDT1.MySize() as integer
#print typeOf(THIS)
return sizeOf(THIS)
end function
dim u1 as UDT1 ' , u2 as UDT2, u3 as UDT3
dim as BASEOBJECT Ptr pu(1 To 3) = {@u1} ' {@u1, @u2, @u3}
? sizeOf(BASEOBJECT)
? sizeOf(u1)
? pu(1)->MySize()
-
- Posts: 2958
- Joined: Jun 02, 2015 16:24
Re: Passing datatype ?
I guess I wanted to do what you show above :)fxm wrote:]Otherwise, the 'BASEOBJECT' base-type with its abstract method is useless.
But not totally useless to just declare the procedure abstract. If you don't implement it, you get a compilation error:
Code: Select all
error 306: UDT has unimplemented abstract methods