Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't Delphi 7 allow a TList of Extended type

I've created several simple lists (and integer list and color list) yet when I try to make an "extended" list it says invalid typecast even though I've used similar typecasting for the prior 2 lists (it throws the error wherever I use the Extended() typecast).

Type
  TAExtList = Class(TObject)
  Private
    FList: TList;
    Procedure SetExt(Index: Integer; Value: Extended);
    Function GetCnt: Integer;
    Function GetExt(Index: Integer): Extended;
  Public
    Constructor Create;
    Destructor Destroy; Override;
    Function Add(Value: Extended): Integer;
    Function Insert(Index: Integer; Value: Extended): Integer;
    Procedure Delete(Index: Integer);
    Procedure Clear;
    Function IndexOf(Value: Extended): Integer;
    Property Count: Integer Read GetCnt;
    Property Extendeds[Index: Integer]: Extended Read GetExt Write SetExt; Default;
  End;

Function TAExtList.Add(Value: Extended): Integer;
Begin
  Result := FList.Add(Pointer(Value));
End;
like image 335
Skutch Avatar asked Jan 01 '26 10:01

Skutch


2 Answers

Both Integer and TColor have the same size (4 bytes) as Pointer in Delphi 7, that is why explicit casting is possible.

docWiki:

Variable Typecasts
You can cast any variable to any type, provided their sizes are the same and you do not mix integers with reals.

But Extended is real, its size is 10 bytes and you cannot cast it to Pointer. Moreover, there is no enough place for it.

P.S. Note that fresh Delphi versions contain rather convenient instrument - generics - just define and create TList<Extended>.

like image 54
MBo Avatar answered Jan 05 '26 05:01

MBo


There are several reasons. First, as MBo already wrote in his answer, an Extended is 10 bytes in size, so it doesn't fit in the 32 bits (4 bytes) of a Pointer.

Another reason is that in Delphi, direct hard casts to floating point types are not allowed, because too many C programmers expected the cast to do a conversion, instead of just a reinterpretation of the bytes of the Extended (or other floating point type). Although the sizes would match, casting to Single is not allowed either. Very early versions of Delphi did actually allow these casts, if I remember correctly (or was that Turbo Pascal?).

But you can still create your TExtendedList, if you use pointers to Extended (after all, a TList stores pointers):

type
  PExtended = ^Extended;

function TExtendedList.Add(const E: Extended): Integer;
var
  P: PExtended;
begin
  New(P);       // allocate an Extended on the heap and "return" a pointer to it
  P^ := E;      // store the parameter on the heap
  inherited Add(P); // add the pointer to the list
end;

But this means that your TList now contains pointers to Extendeds that are allocated on the heap. So removing or changing requires you to use

Dispose(P);

at the appropriate places (e.g. in Delete(), Remove(), Extract(), Clear, etc. and the destructor). Each of the allocated Extendeds must be disposed of at the right time.

Retrieving is similar:

function TExtendedList.GetExt(Index: Integer): Extended;
var
  P: PExtended;
begin
  P := inherited Items[Index]; 
  Result := P^;
  // or short form: Result := PExtended(inherited Items[Index])^;
end;

procedure TExtendedList.SetExt(Index: Integer; Value: Extended);
var
  P: PExtended;
begin
  P := inherited Items[Index];
  P^ := Value;
  // or short form: PExtended(inherited Items[Index])^ := Value;
end;

procedure TExtendedList.Delete(Index: Integer);
begin
  Dispose(PExtended(inherited Items[Index]));
  inherited Delete(Index);
end;

procedure TExtendedList.Clear;
var
  I: Integer;
begin
  for I := 0 to Count - 1 do
    Dispose(PExtended(inherited Items[I]));
  inherited Clear;
end;    

Etc., etc. ...

Update

As @kobik said, you could use the virtual Notify function to delete the items that are removed, instead of in each method:

procedure TExtendedList.Notify(Ptr: Pointer; Action: TListNotification); // declare as override;
begin
  inherited;
  if Action = lnDeleted then
    Dispose(PExtended(Ptr));
end;
like image 39
Rudy Velthuis Avatar answered Jan 05 '26 07:01

Rudy Velthuis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!