I stumbled across this post today that discusses FB's for NEW (Placement) syntax. It appears to be essentially PB's DIM AT.
http://freebasic.net/forum/viewtopic.php?f=3&t=25429#p229070
I didn't think FB had an equivalent to DIM AT.... looks like I was wrong. I used DIM AT a fair bit on some programs so this is a welcomed find.
Paul--
DIM AT is easy to duplicate with a simple call to the low API RtlMoveMemory or RtlCopyMemory.
...
How about using a simple pointer...
Pierre
Type SomeType
dw As DWORD
w As WORD
d As Double
End Type
Dim SomeTypeArray(0 TO 49) As SomeType
SomeTypeArray(33).w = 123
Dim As SomeType Pointer pSomeTypeArray = VarPtr(SomeTypeArray(0))
Print pSomeTypeArray[33].w 'Will show 123
Hey,
Here is a "maybe" more explicit example of what I mean.
If you feel like it, Paul and Patrice, could you give a short code example that demonstrate what you are referring to.
Pierre
#define CompilerExe "<D:\Free\64\fbc.exe>"
#define CompilerCmd "<-s console "D:\Free\bas\~~Default.rc">"
#Lang "fb"
#Define Unicode
#Include Once "Windows.bi"
Dim As String sDoubleWord = MKL(123) & MKL(234) & MKL(345) & MKL(456) & MKL(567) & MKL(789) & MKL(0)
Dim AS DWord Pointer pDoubleWord = Cast(Any Pointer, StrPtr(sDoubleWord))
Print "pDoubleWord[2] = " & pDoubleWord[2] 'Will show 345
Print : Print "Press a key or click to end"
Dim buttons As Long : Do : GetMouse(0, 0, 0, Buttons) : IF buttons Or Len(InKey) Then Exit Do : End If : Sleep 50 : Loop
hmmm.... now that I've played with it for a bit, I can see that FB's ability to use dynamic arrays within TYPE structures is pretty powerful. The use of NEW basically simulates the dynamic array functionality only just in a slightly different way. Both call the newly allocated TYPE's constructors and destructors which is pretty powerful.
''
''
type EMPLOYEE
EmpName as string
EmpAddress as STRING
EmpSalary as double
declare constructor
declare destructor
END TYPE
constructor EMPLOYEE
print "Initialize EMPLOYEE type"
end constructor
DEStructor EMPLOYEE
print "Destroy EMPLOYEE type"
end DEStructor
''
''
type APPLICATION
pEmp as EMPLOYEE ptr
declare constructor
declare destructor
end type
constructor APPLICATION
print "Initialize APPLICATION type"
this.pEmp = new EMPLOYEE[10]
with this.pEmp[1]
.EmpName = "Paul"
.EmpAddress = "Canada"
.EmpSalary = 1000.00
end with
end constructor
DEStructor APPLICATION
print "Destroy APPLICATION type"
delete[] this.pEmp
end DEStructor
''
'' MAIN
dim shared gApp as APPLICATION
for i as long = 0 to 9
print i, gApp.pEmp[i].EmpName, gApp.pEmp[i].EmpAddress, gApp.pEmp[i].EmpSalary
NEXT
print "Done. Press any key."
sleep
' gApp's destructor will be called here as the global goes out of scope
Just using a plain CALLOCATE with a typed pointer results in the constructors and destructors NOT being called.
''
''
type EMPLOYEE
EmpName as string
EmpAddress as STRING
EmpSalary as double
declare constructor
declare destructor
END TYPE
constructor EMPLOYEE
print "Initialize EMPLOYEE type"
end constructor
DEStructor EMPLOYEE
print "Destroy EMPLOYEE type"
end DEStructor
''
'' MAIN
dim pEmp as EMPLOYEE Ptr = CALLOCATE(10, len(EMPLOYEE))
with pEmp[1]
.EmpName = "Paul"
.EmpAddress = "Canada"
.EmpSalary = 1000.00
end with
for i as long = 0 to 9
print i, pEmp[i].EmpName, pEmp[i].EmpAddress, pEmp[i].EmpSalary
NEXT
DEALLOCATE pEmp
print "Done. Press any key."
sleep
...and lastly, here is the straight forward dynamic ARRAY version. As you can see, constructors and destructors do get called.
''
''
type EMPLOYEE
EmpName as string
EmpAddress as STRING
EmpSalary as double
declare constructor
declare destructor
END TYPE
constructor EMPLOYEE
print "Initialize EMPLOYEE type"
end constructor
DEStructor EMPLOYEE
print "Destroy EMPLOYEE type"
end DEStructor
''
''
type APPLICATION
arrEmp(any) as EMPLOYEE
declare constructor
declare destructor
end type
constructor APPLICATION
print "Initialize APPLICATION type"
REDIM this.arrEmp(10)
with this.arrEmp(1)
.EmpName = "Paul"
.EmpAddress = "Canada"
.EmpSalary = 1000.00
end with
end constructor
DEStructor APPLICATION
print "Destroy APPLICATION type"
end DEStructor
''
'' MAIN
dim shared gApp as APPLICATION
for i as long = 0 to 9
print i, gApp.arrEmp(i).EmpName, gApp.arrEmp(i).EmpAddress, gApp.arrEmp(i).EmpSalary
NEXT
print "Done. Press any key."
sleep
' gApp's destructor will be called here as the global goes out of scope
This is probably closer to DIM AT. Pretty simple really given FB's ability to use ANY PTR and then convert it to a typed pointer.
I use array indexing in my code because I find it easier to visualize then incrementing memory addresses.
''
''
type EMPLOYEE
EmpName as string
EmpAddress as STRING
EmpSalary as double
END TYPE
''
'' MAIN
dim pMem as any ptr = CALLOCATE(1024)
dim pEmp as EMPLOYEE Ptr = CPtr(EMPLOYEE Ptr, pMem)
with pEmp[1]
.EmpName = "Paul"
.EmpAddress = "Canada"
.EmpSalary = 1000.00
end with
for i as long = 0 to 9
print i, pEmp[i].EmpName, pEmp[i].EmpAddress, pEmp[i].EmpSalary
NEXT
DEALLOCATE pMem
print "Done. Press any key."
sleep
Agreed, looks pretty powerful...
Good stuff to read and learn.
Many thanks for those examples Paul.
Pierre
They borrowed this direct from C++ :)
They borrowed A LOT from C++ :)
Also what I think, they borrowed a lot from C++, and did a great job at it, I like... :-)
As long as they don't borrow the semi-colons and curly braces... :)
Well, I totally got the DIM AT syntax a little wrong. Here is how it relates most closely to the PB DIM AT functionality.
The New (placement) operator allows to construct object(s) (no allocate memory) at an existing memory location:
New(address) datatype[ count ]
TYPE EMPLOYEE
empName AS STRING
empAddress AS STRING
empSalary AS DOUBLE
END TYPE
' Create a generic block of memory
dim pMem as any ptr = CALLOCATE( 1024)
' Here is the DIM AT syntax. Notice the NEW(pMem) part.
' Basically 10 new employee TYPE's are overlaid on the
' existing pMem area.
DIM pEmp AS EMPLOYEE Ptr = NEW(pMem) EMPLOYEE[10]
' Assign data to our employee
pEmp->empName = "Paul"
pEmp->empAddress = "Canada"
pEmp->empSalary = 1000.00
' Deallocate our memory
DEALLOCATE(pMem)
I got to read about this "New" (placement) operator...
I the mean time, what advantage do you see over the following...
#Include Once "string.bi" 'For format
TYPE Employee
FirstName AS STRING
Country AS STRING
Salary AS DOUBLE
END TYPE
Dim pEmployeeArray As Employee Pointer = cAllocate(2048) 'Allocate memory
pEmployeeArray[0].FirstName = "Paul"
pEmployeeArray[0].Country = "Canada"
pEmployeeArray[0].Salary = 10000.00
pEmployeeArray[1].FirstName = "Jos" & CHR(130)
pEmployeeArray[1].Country = "Spain"
pEmployeeArray[1].Salary = 10000.00
Print "> " & pEmployeeArray[0].FirstName
Print "> " & pEmployeeArray[0].Country
Print "> " & Format(pEmployeeArray[0].Salary, "0,")
Print
Print "> " & pEmployeeArray[1].FirstName
Print "> " & pEmployeeArray[1].Country
Print "> " & Format(pEmployeeArray[1].Salary, "0,")
Deallocate(pEmployeeArray) 'Deallocate memory
Sleep
I think that the only advantage would be that the Constructors and Destructors for the TYPE might be called using the NEW method whereas in your example they are not?