Re: Convert C-Builder program to Delphi?

M

Maarten Wiltink

[...]
A_RecordPtr: ^SomeRecordType;
i: uint32;
j: uint32;
pAuthDB: ^SomeOtherRecordType;
if (A_RecordPtr.SomeBoolFunc (TransposeByteOrder
(*(uint32*)&pAuthDB[j].DBID
)
)
)

How can I handle this without getting the dreaded
"Array Type Required" error?


By using enough temporary variables, mostly. You should by now have
seen all the errors before and know how to solve any of them. All
that can go wrong now is that you don't spot what exactly is wrong;
the solution to that is to split up the code until you can only make
once mistake at a time.

Groetjes,
Maarten Wiltink
 
W

W. D.

Thanks Maarten and Moz for your help!!!

This is what I wrote last time:

-o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-
I am still struggling with pointers and indexing them. The
current code I am trying to convert is contained in
some nested FOR loops:

===============================================================
A_RecordPtr: ^SomeRecordType;
i: uint32;
j: uint32;
pAuthDB: ^SomeOtherRecordType;


if
(A_RecordPtr.SomeBoolFunc(TransposeByteOrder(*(uint32*)&pAuthDB[j].DBID)))
===============================================================

How can I handle this without getting the dreaded
"Array Type Required" error?
-o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-

However, it's not just a RECORD that I am trying to
operate on. Rather, there's a CLASS too. I should have
written:

-o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-
I am still struggling with pointers to classes and records
(and how to index them). The current code I am trying to
convert is contained in some nested FOR loops:

===============================================================
A_ClassPtr: ^SomeClassType;
i: uint32;
j: uint32;
pAuthDB: ^SomeRecordType;


if
(A_ClassPtr.SomeBoolFunc(TransposeByteOrder(*(uint32*)&pAuthDB[j].DBID)))
===============================================================

How can I handle this without getting the dreaded
"Array Type Required" error?
-o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o--o-

Maarten said:
By using enough temporary variables, mostly. You should by now have
seen all the errors before and know how to solve any of them.

I wish. With all the pointers, records, classes & indexes, the
levels of abstraction are almost too much for my brain to handle!

All
that can go wrong now is that you don't spot what exactly is wrong;
the solution to that is to split up the code until you can only make
one mistake at a time.

This makes perfect sense. I just wish I could get a handle on
all the indexing pointers to records/classes. Then I could
split off the other stuff into temporary variables, etc.
Groetjes,
Maarten Wiltink

By declaring a type foo:array of SomeRecordType, and assigning the
start of the array to it.

Which 'it'? Would that mean something like:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Type
SomeRecTypeAry: Array of SomeRecordType;

@SomeRecTypeAry := pAuthDB;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C treats pointers and arrays as identical,
but Pascal doesn't (it's more strongly typed as well as less case
sensitive).

Moz

Thanks again guys for your valuable advice. If you would
be so kind, please *point* me in the right direction
once more!
 
M

Maarten Wiltink

[...]
I wish. With all the pointers, records, classes & indexes, the
levels of abstraction are almost too much for my brain to handle!

So you are in over your head. That's okay, happens to all of us.
Just deal with it in the right way. Trying to understand two levels
at once isn't. Look at the trees first. When you grok the trees,
continue to the forest.

This makes perfect sense. I just wish I could get a handle on
all the indexing pointers to records/classes. Then I could
split off the other stuff into temporary variables, etc.

No, you can do that *now*, and it should give you a handle on the
hard parts, because you then have only one hard part per statement.

Start with lifting out the innermost expressions. It's a lexical
operation, no understanding required. Repeat until you start to see
what happens.

Groetjes,
Maarten Wiltink
 
W

W. D.

Maarten said:
[...]
I wish. With all the pointers, records, classes & indexes, the
levels of abstraction are almost too much for my brain to handle!

So you are in over your head. That's okay, happens to all of us.
Just deal with it in the right way. Trying to understand two levels
at once isn't. Look at the trees first. When you grok the trees,
continue to the forest.
This makes perfect sense. I just wish I could get a handle on
all the indexing pointers to records/classes. Then I could
split off the other stuff into temporary variables, etc.

No, you can do that *now*, and it should give you a handle on the
hard parts, because you then have only one hard part per statement.

Start with lifting out the innermost expressions. It's a lexical
operation, no understanding required. Repeat until you start to see
what happens.

Thanks, Maarten for your reply.

The problem is, I don't know how to index the CLASS and RECORD
variables. These are the 'innermost expressions', yes?

A_ClassPtr.SomeBoolFunc
pAuthDB[j].DBID

You say I can index them, but my hands just scratch my head
and don't type anything useful. I've tried all sorts
of variations, but the compiler just comes up with its
corresponding variety of error messages.

I've hunted throughout the 'Net, (Web pages and UseNet).
Here are some of my favorites that haven't helped:

http://tinyurl.com/6teew
http://tinyurl.com/3vpu6
http://tinyurl.com/6swdg
http://tinyurl.com/4v53k

While I know how to index pointers by creating a
kludgy array, I don't know how to index CLASSES or
RECORDS. Those pesky methods don't seem to play
nice with my array technique.

Purty please, with sugar on top, may I have a
hint? ;^)
 
M

Maarten Wiltink

W. D. said:
Maarten Wiltink wrote: [...]
Start with lifting out the innermost expressions. It's a lexical
operation, no understanding required. Repeat until you start to see
what happens.
The problem is, I don't know how to index the CLASS and RECORD
variables. These are the 'innermost expressions', yes?

I'm not talking about indexing at this point, but only about moving
subexpressions into temporary variables.

However, you can't index classtype references or record type
values in Delphi. You must have an array of them. C arrays look
different. Are you sure you don't have an array? Are you sure
you _shouldn't_ have an array?

A_ClassPtr.SomeBoolFunc
pAuthDB[j].DBID

You say I can index them, but my hands just scratch my head
and don't type anything useful. I've tried all sorts
of variations, but the compiler just comes up with its
corresponding variety of error messages.



if (A_ClassPtr.SomeBoolFunc
(TransposeByteOrder
(*(uint32*)&pAuthDB[j].DBID
)
)
)

The former of your expressions is an outermost, but the other one is
spot on. Leaving the DBID member's type unstated, the above transforms
to:

var Data: T;

Data:=pAuthDB[j].DBID;
if (A_ClassPtr.SomeBoolFunc(*(uint *)&Data);

where of course *X is written X^ in Pascal, (uint *) is written PCardinal
where PCardinal = ^Cardinal, and &X @X, so the argument to SomeBoolFunc
becomes (PCardinal(@Data))^. (You never have too many brackets.)

Note that if T is smaller than four bytes, the above code is broken
because the adjacent data aren't duplicated and the code depends on them;
this may well be the entire point of that useless-looking cast.

Groetjes,
Maarten Wiltink
 
W

W. D.

Again, thanks a bunch, Maarten!

Maarten said:
W. D. said:
Maarten Wiltink wrote: [...]
Start with lifting out the innermost expressions. It's a lexical
operation, no understanding required. Repeat until you start to see
what happens.
The problem is, I don't know how to index the CLASS and RECORD
variables. These are the 'innermost expressions', yes?

I'm not talking about indexing at this point, but only about moving
subexpressions into temporary variables.

However, you can't index classtype references or record type
values in Delphi. You must have an array of them.

This is the critical information that I needed. Apparently,
in C++, indexing pointer variables (whether they are strings,
records, classes, or whatever) is just a matter of tacking
on an index:

SomeComplicatedRecord.SomeMethod

C arrays look
different. Are you sure you don't have an array? Are you sure
you _shouldn't_ have an array?

I guess I really *SHOULD* have an array in Delphi. Otherwise,
how can I cycle through each member?

This requires converting the type from a pointer to a non-pointer
type. And of course, much of the code that references the
variable will also need to be rewritten.

I've begun to do this but, am wondering how to
deallocate the memory for an Array of Record.
This record, 'Was_a_pointer', is declared in the
'Private' section of a class. In the Destructor,
this is how it was deallocated:

// C++: delete[] Was_a_pointer;


When I try to deallocate this array, I get
all sorts of errors. None of the following
work:

Was_a_pointer := NIL;
FreeMem(Was_a_pointer);
@Was_a_pointer := NIL;
Was_a_pointer.Free;
Dispose(Was_a_pointer);

Is an array that is declared in a class automatically
disposed of when the class is destroyed? If not,
what is the proper way to free memory allocated to
arrays of records?

Thanks soooo much for all your wisdom and insights!
 
M

Maarten Wiltink

W. D. said:
Maarten Wiltink wrote: [...]
However, you can't index classtype references or record type
values in Delphi. You must have an array of them.

This is the critical information that I needed. Apparently,
in C++, indexing pointer variables (whether they are strings,
records, classes, or whatever) is just a matter of tacking
on an index:

SomeComplicatedRecord.SomeMethod


It is. Frankly, I was labouring under the assumption that you had
discovered this long ago.

In C, a is syntactic sugar for *(a+i). Array indexing borrows from
pointer arithmetic and it is defined that addition to a typed pointer
is scaled by the size of the referenced type. Look again at the
expression *(a+i) and you see that indexing a pointer to the base of
an array of, say, uint32's (four bytes in size), works exactly as you
might expect. Unsurprisingly, an array variable is treated as a pointer
to the base of the array. It works nicely for dynamically allocated
arrays, too, but they are explicitly pointers.

In Pascal, this doesn't work. Arrays are a first-class datatype (well,
almost) and not compatible in any way with pointers to anything. The
single exception is PChar, which is allowed to be indexed in this way,
but that's a C compatiblity feature. The usage of PChar instead of real
strings is a C compatibility feature to begin with.


[... I] am wondering how to
deallocate the memory for an Array of Record.
This record, 'Was_a_pointer', is declared in the
'Private' section of a class. In the Destructor,
this is how it was deallocated:

// C++: delete[] Was_a_pointer;


When I try to deallocate this array, I get
all sorts of errors. None of the following
work:

Was_a_pointer := NIL;
FreeMem(Was_a_pointer);
@Was_a_pointer := NIL;
Was_a_pointer.Free;
Dispose(Was_a_pointer);

Is an array that is declared in a class automatically
disposed of when the class is destroyed? If not,
what is the proper way to free memory allocated to
arrays of records?

There are - in Object Pascal - two kinds of arrays. Static arrays
are statically allocated and go away with the containing object.
Dynamic arrays should be SetLength'd to zero elements if you want
to be explicit, but they are also handled by compiler magic if a
containing object is freed.

Setting a dynamic array variable to nil is allowed as a special
case for rather dubious reasons; it is equivalent to SetLength(., 0).
FreeMem should be paired with GetMem. Trying to move the physical
location where a variable lives obviously can't work. Free applies
to objects and dynamic arrays aren't. Dispose should be paired with
New.

All that applies to dynamic arrays. That setting it to nil doesn't
work indicates you had a static array. You don't need to deallocate
those; just let them go out of scope.

Thanks soooo much for all your wisdom and insights!

Here's one you may not like so much: translating well requires knowing
_both_ languages well. Imagine translating a good book full of inside
jokes, wordplay, and cultural references, from a language you only
half understand. You'll miss some of the words, and everything that is
behind the words.

Groetjes,
Maarten Wiltink
 
W

W. D.

Maarten Wiltink wrote:

There are - in Object Pascal - two kinds of arrays. Static arrays
are statically allocated and go away with the containing object.
Dynamic arrays should be SetLength'd to zero elements if you want
to be explicit, but they are also handled by compiler magic if a
containing object is freed.

Setting a dynamic array variable to nil is allowed as a special
case for rather dubious reasons; it is equivalent to SetLength(., 0).
FreeMem should be paired with GetMem. Trying to move the physical
location where a variable lives obviously can't work. Free applies
to objects and dynamic arrays aren't. Dispose should be paired with
New.

All that applies to dynamic arrays. That setting it to nil doesn't
work indicates you had a static array. You don't need to deallocate
those; just let them go out of scope.

So, my Array of Records will be automatically
deallocated when the class that uses it is destroyed?


Here's one you may not like so much: translating well requires knowing
_both_ languages well. Imagine translating a good book full of inside
jokes, wordplay, and cultural references, from a language you only
half understand. You'll miss some of the words, and everything that is
behind the words.

No wonder I am having so much trouble. ;^)
 
M

Maarten Wiltink

W. D. said:
Maarten Wiltink wrote:
[...]
So, my Array of Records will be automatically
deallocated when the class that uses it is destroyed?

Yes. But be precise. The syntax "array of record" can appear in
program code, and declares a dynamic array variable. The above
bit is about static arrays, which have an ordinal type appearing
in square brackets between "array" and "of". That doesn't change
the fact of its automatic deallocation when a containing
*object* - again, be precise - is freed, but this sort of
confusion is setting yourself up for problems. Compilers are
unforgiving.

Groetjes,
Maarten Wiltink
 
W

W. D.

Maarten said:
W. D. said:
Maarten Wiltink wrote:
[...]
So, my Array of Records will be automatically
deallocated when the class that uses it is destroyed?

Yes. But be precise. The syntax "array of record" can appear in
program code, and declares a dynamic array variable. The above
bit is about static arrays, which have an ordinal type appearing
in square brackets between "array" and "of". That doesn't change
the fact of its automatic deallocation when a containing
*object* - again, be precise - is freed, but this sort of
confusion is setting yourself up for problems. Compilers are
unforgiving.

OK. To be precise and clear, would the following
be correct?

Array Type Example Dealloc by:
1. Static Array (in Class) A1: Array[0..7] of ARecType Destroy Class
2. Static Array (!in Class) A2: Array[0..7] of ARecType Close of
Program
3. Dynm Array (in Class) A3: Array of ARecType SetLength(A3,
0);
4. Dynm Array (!in Class) A4: Array of ARecType SetLength(A4,
0);
 
M

Maarten Wiltink

W. D. said:
Maarten Wiltink wrote:

OK. To be precise and clear, would the following
be correct?

Array Type Example Dealloc by:
1. Static Array (in Class) A1: Array[0..7] of ARecType Destroy Class
2. Static Array (!in Class) A2: Array[0..7] of ARecType Close of
Program
3. Dynm Array (in Class) A3: Array of ARecType SetLength(A3,
0);
4. Dynm Array (!in Class) A4: Array of ARecType SetLength(A4,
0);

Apart from using the word "class" where you mean "object", and me using
"object" where a Borland Greater Pedant would use "class type instance"
or something to differentiate old-style from new-style objects, yes.

It's not complete, though - A3 is also freed when its containing object
is, and that will probably happen more often. In my experience, it's
rare to re-allocate dynamic arrays.

As a final note which I encourage everybody not to read, you can set a
dynamic array reference to nil for the same effect as SetLength'ing it
to zero elements. But that is an ugly hack misguidedly prompted by
implementation issues.

Groetjes,
Maarten Wiltink
 
W

W. D.

Maarten said:
W. D. said:
Maarten Wiltink wrote:

OK. To be precise and clear, would the following
be correct?

Array Type Example Dealloc by:
1. Static Array (in Class) A1: Array[0..7] of ARecType Destroy Class
2. Static Array (!in Class) A2: Array[0..7] of ARecType Close of
Program
3. Dynm Array (in Class) A3: Array of ARecType SetLength(A3,
0);
4. Dynm Array (!in Class) A4: Array of ARecType SetLength(A4,
0);

Apart from using the word "class" where you mean "object", and me using
"object" where a Borland Greater Pedant would use "class type instance"
or something to differentiate old-style from new-style objects, yes.

It's not complete, though - A3 is also freed when its containing object
is, and that will probably happen more often. In my experience, it's

^^^destroyed?

Does 'destroyed' go here?
rare to re-allocate dynamic arrays.

As a final note which I encourage everybody not to read, you can set a
dynamic array reference to nil for the same effect as SetLength'ing it
to zero elements. But that is an ugly hack misguidedly prompted by
implementation issues.

What would be the case if this were necessary?


Now, I am having a problem with making a copy of a dynamic
array:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Var
Array1: Array of Char;
Array2: Array of Char;

Begin

....

Array2 := Copy(Array1, 1, 256);

End;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When I try to do this, I get an 'Incompatible types' error.
Why is this? The array types are exactly the same.
What is the proper way to copy dynamic arrays?
 
M

Maarten Wiltink

W. D. said:
Maarten Wiltink wrote:
[...] A3 is also freed when its containing object is, ...
^^^destroyed?

Does 'destroyed' go here?

Yes. A style figure known as ellipsis, IIANM. Selective omission of
repetetive elements.

[...] you can set a dynamic array reference to nil for the same
effect as SetLength'ing it to zero elements. But that is an ugly
hack misguidedly prompted by implementation issues.

What would be the case if this were necessary?

Dogs and cats would be living together, and fire would be raining
from the sky. It _isn't_ necessary. Use SetLength.

Now, I am having a problem with making a copy of a dynamic
array:
Var
Array1: Array of Char;
Array2: Array of Char;
Array2 := Copy(Array1, 1, 256);
When I try to do this, I get an 'Incompatible types' error.
Why is this? The array types are exactly the same.
What is the proper way to copy dynamic arrays?

As was explained here once (quite a long time ago), the type
_constructors_ are exactly the same. The resulting types aren't.
Use a named type or declare both variables at the same time.

If that's not it, perhaps Copy is wrong and you need to use
something else or write your own.

Groetjes,
Maarten Wiltink
 
J

Jamie

So, my Array of Records will be automatically
deallocated when the class that uses it is destroyed?

Let me try.

if you create a class, variables that are already
specified in the class with fixed heap sized fields (not dynamic),
get their space needed as soon as the constructor of the
class is call which in turn creates enough memory to allow
all heap type info for that class to exists.
the heap for these local variables work much the same way as
the local varibles work when calling functions! local storage is
created for you to allow occupation of these variables automaticly
from the stack which gets cleaned up when the function exits.
in classes, the memory that got allocated simply gets returned back
to the Run Time Lib to be re'used when the class free's it self.

now, dynamic variables are pointers just as the class code are
also pointers.
if you have local variables that are pointer types, only the pointers
them selfs will get created ( 4 bytes)( 32 bit Dword) how ever, any
items that these pointers look at is up to you at the construction time
to declare except for like RTL types (strings) and (Dynamic Arrays).
in anycase, with strings you simply treat them as you do any where.
with the RTL arrays how ever, you need to use the SetLength to
actually initiate them but no clean up should be needed because it is a
RTL type just like the string..
now here comes the tricky part. in any case!, when ever you create a
Class instant or pointer of any type with in a class constructor, you
need to free them in the destructor!
simply put, what memory you hog up, you release ..
Examples.

Var
MyArray:Array of Pointer;

that is a RTL type.
using the SetLength(MyArray, NumberofPointersWanted) is like using
SetLength(SomeString, ?);
space is created but managed like the strings are, you shouldn't
have to do anything in the constructor.

Now do something like this after you have initiated the MyArray.

GetMem(MyArray[0], NumberofBytes);

now this becomes a problem.
you need to free the memory that MyArray[0] is looking at before
exiting the Destructor.
ect////
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,142
Latest member
arinsharma
Top