Generics, records and typecasts = F2084 Internal Error: AV0DBFFBE9-R0000000C-0

Generics, records and typecasts = F2084 Internal Error: AV0DBFFBE9-R0000000C-0

// redux - not actual code
type
TKey = record
Index: Integer;
end;

TSomeClass = class abstract
procedure CopyTo(var Key: TKey); virtual; abstract;
procedure CopyFrom(var Key: TKey); virtual; abstract;
end;

TKeyValue = record
Key: TKey;
Value: T;
end;

TIndexList = TArray;
TKeyValueList = TArray>;

TSomeClass = class(TSomeClass)
public type
TValueList = TArray;
private var
ValueList: TValueList;
procedure CopyTo(var Key: TKey); override;
procedure CopyFrom(var Key: TKey); override;
end;

procedure TSomeClass .CopyTo(var Key: TKey);
begin
TKeyValue(Key).Value := ValueList[Key.Index]; // OK
end;

procedure TSomeClass .CopyFrom(var Key: TKey);
begin
ValueList[Key.Index] := TKeyValue(Key).Value; // F2084 Internal Error: AV0DBFFBE9-R0000000C-0
end;

CopyTo/From called with a list of TKeyValue params.

I guess I was asking for it. Rewrote to use regular class objects.

Comments

  1. you're really pushing it with generics, aren't you? (;

    ReplyDelete
  2. Dorin Duminica It is amazing how much scaffolding code clutter you can remove with it. Working on a wrapper for grids that allows me to completely forget about configuring the grid settings. All data typesafe, populated from a class list, or from an SQL query.

    We have a LOT of grids, all with similar event handlers, refresh needs, sorting, grouping, sizing and scaling, look and feel, copy to clipboard, etc. I now define a non-visual grid with the right types, and hook up with a visualizer that I hook up to a grid component.

    It removes hundreds of lines of grid handling per grid in a form, and replaces it with a few dozen lines of declaration and a few lines of implementation.
    http://pastebin.com/q2Gkq5Pn
    Visual result (right side grid)
    https://drive.google.com/open?id=0B1MyXorVzay9UGVRQWpwdWRvOEk

    ReplyDelete
  3. that looks really good!!

    I once wrote a lib < 1.5KLOC that handled everything from generating database to advanced queries in Delphi with basic generics and attributes; whenever I tried something smart with generics, I'd get some cryptic errors just like you, so, I gave up on anything generic that seemed that no one would write test case for, shame really...

    ReplyDelete
  4. My own use of generics has so far been light, but I wrote some very useful generic array code, and as you say, Lars, it helped me remove a good deal of clutter from mainline code. But it also let me condition array access to avoid range error issue, among other things.

    Since I am working in both D2007 and XE7, I am limited in what I can do, but as we shift more and more to XE7, I expect that generics will play an increasing role.

    ReplyDelete
  5. No problem here on Seattle with some minor changes

    unit Unit1;

    interface

    type
    TKey = record
    Index: Integer;
    end;

    TSomeClass = class abstract
    procedure CopyTo( var Key: TKey ); virtual; abstract;
    procedure CopyFrom( var Key: TKey ); virtual; abstract;
    end;

    TKeyValue = record
    Key: TKey;
    Value: T;
    class operator explicit( const Key: TKey ): TKeyValue;
    end;

    TIndexList = TArray;
    // TKeyValueList = TArray>;

    TSomeClass = class( TSomeClass )
    public type
    TValueList = TArray;
    private
    var
    ValueList: TValueList;
    procedure CopyTo( var Key: TKey ); override;
    procedure CopyFrom( var Key: TKey ); override;
    end;

    implementation

    procedure TSomeClass.CopyTo( var Key: TKey );
    var
    lval : TKeyValue;
    begin
    lVal := TKeyValue(Key);
    lVal.Value := ValueList[ Key.Index ]; // OK
    end;

    procedure TSomeClass.CopyFrom( var Key: TKey );
    begin
    ValueList[ Key.Index ] := TKeyValue( Key ).Value;
    end;

    { TKeyValue }

    class operator TKeyValue.explicit( const Key: TKey ): TKeyValue;
    begin
    Result.Key := Key;
    Result.Value := default ( T );
    end;

    end.

    ReplyDelete
  6. But how will you get any value from TKey (there is no value only index) or store any value into TKey (there is no value only index)?

    ReplyDelete
  7. Oliver Münzberg  The external methods don't need the Value. They only work with the Index. Interesting trick with the explicit operator!

    Anyways - the regular object code became much cleaner and shorter than the record overloaded version.

    Developing new classes is interesting. You sometimes have to go a few iterations before their final form appear.

    Usually, you know you are on the right track when you start deleting code that is no longer needed.

    ReplyDelete
  8. FYI, the actual code lifts the following from the grid
    Top Row
    Current Row
    Selected Rows
    Checked Rows
    before an update, and then tries to restore the values to the grid after the update, checking if the value:T at the index still matches, and if not - searches out the row that matches.

    ReplyDelete
  9. Lars Fosdal It sounds very cool, would be glad if you could share it when you get it done. Setting up the grids takes more time than the actual code for the whole form.

    ReplyDelete
  10. Attila Kovacs It is still not at a maturity where it is ready for others to use. Also - I need to get permission from my employer.

    If I eventually make it available, you will find out in this forum.

    ReplyDelete
  11. The casts between TKey and TKeyValue has "I want to be a bug" written all over them.

    ReplyDelete

Post a Comment