Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining records in Delphi - (Record as type vs Record as variable) - Differences, cons and pros..?

I've been doing some research over records in Delphi, and in most cases I see them used as Type, and then declared a new variable of it, such as:

type
  TMyRecord = record
    data1: sometype;
    data2: sometype;
  end;

var
  OnesRecord: TMyRecord;

For arrays, it's also used as:

type
  TMyRecord = record
    data1: sometype;
    data2: sometype;
  end;

var
  OnesRecord: array of TMyRecord;

My questions are the following:

Why one shouldn't use the first approach for arrays, in a way as:

type
  TMyRecord = array of record
    data1: sometype;
    data2: sometype;
  end;

var
  OnesRecord: TMyRecord;

Also, what would be the difference if one would use records defined directly as variables, such as:

var
  OnesRecord: record
    data1: sometype;
    data2: sometype;
  end;

or

var
  OnesRecord: array of record
    data1: sometype;
    data2: sometype;
  end;

?

One final thing; if one would merge the second and third approach, and have type of array, and variable of array of that type, would it be any different than having array of array?

So, is this:

type
  TMyRecord = array of record
    data1: sometype;
    data2: sometype;
  end;

var
  OnesRecord: array of TMyRecord;

any different than this:

type
  TMyRecord = record
    data1: sometype;
    data2: sometype;
  end;

var
  OnesRecord: array of array of TMyRecord;
like image 207
That Marc Avatar asked Nov 26 '14 02:11

That Marc


2 Answers

It is quite a simple issue. When written like this

type
  TPoints = array of record
    X, Y: Double;
  end;

you are unable to declare variables or parameters that operate on a single element of the array. If you never need to operate on a single item then the above declaration can be reasonable.

Every other aspect of your question is logically the same. Be it arrays of arrays, records containing records, anonymous record and arrays as variable types. The issues and design considerations are just the same.


This question is perhaps a little subjective. In my experience, using an inline or anonymous type as shown above, very often turns out to be a bad choice. Often, at some point of future development, it becomes clear that the anonymous type needs to be named.

So myself, I never use compound types composed from anonymous types. And this way I'm always able to refactor code to use small methods operating on on individual elements. There's never a false constraint pushing me towards large methods operating on the compound type that cannot be decomposed.

So I'd declare that type above as:

type
  TPoint = record
    X, Y: Double;
  end;
  TPoints = array of TPoint;

Although in modern Delphi it is much better for type compatibility reasons to omit TPoints and use TArray<TPoint> instead.

like image 95
David Heffernan Avatar answered Oct 13 '22 03:10

David Heffernan


There's nothing wrong doing what you're doing, just like there's nothing keeping you from overloading the Add() operator to do multiplication.

Your questions are entirely theoretical, and so it's hard to say anything one way or another. Yes, the constructs are "legal". So what?

It's like asking about walking on your hands vs. walking on your feet after you've discovered that you CAN walk on your hands.

The question in all cases is the same ... why would you want to do it?

Rather than asking about coding approaches that are "legal" but nobody uses, why don't you try showing an example where such uses would prove to be an advantage?

From a theoretical standpoint, you're trying to mash-up two different data aggregation mechanisms.

Arrays are a way of collecting items of the same type. Records and classes are a way of collecting related items of different types. They're both containers of sorts, but they have distinct qualities.

You usually declare an array as "array of " not "array of record ... end".

By convention, you define the record as a TYPE so you can "re-use" that type.

You obviously haven't got much experience with this, because you can't actually USE these constructs outside of a very narrow setting.

Let's say you want to define something like "array of integer"; you can define it as a specific type:

type
 TIntArray = array of integer;

Why would you do this? Because at times you'll discover that declaring two different things both as "array of integer" makes them not type-compatible, which is counter-intuitive.

But if they're each declared as TIntArray, the compiler accepts that.

I don't know if this is the correct terminology or not, but as far as the compiler is concerned, there IS a difference between "myvar : " and "myvar : ". In this case, would be "TIntArray", and would be "array of integer".

var
  myvar1 : array of integer;
  myvar2 : TIntArray;

These two are NOT type compatible in all cases. Furthermore,

procedure myproc( AVar : array of integer )

will not accept myproc(myvar2) because myvar2 is not of type "array of integer". Really! It's of type TIntArray. See the difference?

Now replace that declaration with any sort of "record ... end", or even your "array of record ... end" thingie and you start to see the limitations of what you're asking. Yes, the compiler digests it just fine. It just won't let you pass anything in as an argument that matches that type! Even if they "look" exactly the same, believe it or not.

So, to answer your own question, I challenge you to construct a non-trivial example where the things you propose actually make sense and the compiler accepts them. Because while the compiler might accept the isolated examples you've created above, they're not likely to work very well in practice (if at all).

But you get an 'A' for Audacity in asking an insightful question!

like image 42
David Schwartz Avatar answered Oct 13 '22 05:10

David Schwartz