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.
// 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
Key: TKey;
Value: T;
end;
TIndexList = TArray
TKeyValueList
TSomeClass
public type
TValueList = TArray
private var
ValueList: TValueList;
procedure CopyTo(var Key: TKey); override;
procedure CopyFrom(var Key: TKey); override;
end;
procedure TSomeClass
begin
TKeyValue
end;
procedure TSomeClass
begin
ValueList[Key.Index] := TKeyValue
end;
CopyTo/From called with a list of TKeyValue
I guess I was asking for it. Rewrote to use regular class objects.
you're really pushing it with generics, aren't you? (;
ReplyDeleteDorin 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.
ReplyDeleteWe 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
that looks really good!!
ReplyDeleteI 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...
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.
ReplyDeleteSince 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.
No problem here on Seattle with some minor changes
ReplyDeleteunit 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.
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)?
ReplyDeleteOliver Münzberg The external methods don't need the Value. They only work with the Index. Interesting trick with the explicit operator!
ReplyDeleteAnyways - 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.
FYI, the actual code lifts the following from the grid
ReplyDeleteTop 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.
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.
ReplyDeleteAttila 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.
ReplyDeleteIf I eventually make it available, you will find out in this forum.
The casts between TKey and TKeyValue has "I want to be a bug" written all over them.
ReplyDelete