Generics object and assignment overloading
Generics object and assignment overloading
type
TMyObject = class
property Value: T;
end;
TIntObject = TMyObject;
var
obj: TIntObject;
int: integer;
begin
obj := TIntObject.Create;
obj := 4; // assigns 4 to obj.value
int := obj; // resulting in Int being 4
end;
Is it possible to do operator overloads which allows the assignments as outlined above? I know this is not housebroken code - but it would help immensely for code simplicity in the specific context that I want to use it in. If possible, what are the pitfalls? (instances will not be persistent or streamed).
type
TMyObject
property Value: T;
end;
TIntObject = TMyObject
var
obj: TIntObject;
int: integer;
begin
obj := TIntObject.Create;
obj := 4; // assigns 4 to obj.value
int := obj; // resulting in Int being 4
end;
Is it possible to do operator overloads which allows the assignments as outlined above? I know this is not housebroken code - but it would help immensely for code simplicity in the specific context that I want to use it in. If possible, what are the pitfalls? (instances will not be persistent or streamed).
You cannot overload assignment. The closest you can get is to overload the implicit cast operator with operator overloading. Which leads you to this:
ReplyDelete{$APPTYPE CONSOLE}
type
TMyRec = record
FValue: T;
class operator Implicit(const Value: T): TMyRec;
class operator Implicit(const Value: TMyRec): T;
end;
class operator TMyRec.Implicit(const Value: T): TMyRec;
begin
Result.FValue := Value;
end;
class operator TMyRec.Implicit(const Value: TMyRec): T;
begin
Result := Value.FValue;
end;
var
value: TMyRec;
int: integer;
begin
value := 666;
int := value;
Writeln(int);
end.
If only you'd asked this on Stack Overflow, others could have benefited in the future, rather than this being lost.
As David Heffernan said, not with objects, only records. If you can use interfaces, you can have your cake and eat it too.
ReplyDeleteclass, not record.
ReplyDeleteIn other words - not possible?
Good point on the SO thing. I'll do that for the future.
ReplyDeleteYou can use class if you have ARC. Anyway, it's really not going to hurt you to expose the value as a property, is it!
ReplyDeleteAsbjørn Heid I require inheritance from the TMyObject class - is that doable with interfaces?
ReplyDeleteDavid Heffernan It would be a nicety, not a necessicty. It wouldn't hurt to get rid of the numerous .Value assignment references.
ReplyDeleteMyClass.ThisField.Value := ref.ThisField; //int
MyClass.ThatField.Value := ref.ThatField; //string
contra
MyClass.ThisField := ref.ThisField; //int
MyClass.ThatField := ref.ThatField; // string
There can be a lot of them.
Javier Hernández I did, I think...
ReplyDeleteSee also: http://www.thedelphigeek.com/2015/01/implementing-record-assignment-operator.html, http://www.thedelphigeek.com/2015/01/implementing-record-assignment-operator_9.html
ReplyDeleteAren't you just looking for Observable? See https://bitbucket.org/sglienke/knockoff CC Stefan Glienke
ReplyDeleteLars Fosdal Ah then it gets tricky quickly, since you don't know which one to instantiate on the implicit conversion operator from T to TRec.
ReplyDeletePrimož Gabrijelčič That doesn't look pertinent to the issue here
ReplyDeleteLars Fosdal Wait, if you want this to be able to copy field values like that, why not just descend from TPersistent and use Assign?
ReplyDeleteedit: sorry, silly friday suggestion. Brain is totally in weekend mode.
These are editor wrappers that I am tinkering with - i.e. lots of once-off declarations. No point in creating assigns for the umpteen variations of classes and editor combos. All I want to do is to minimize the code - and implicit would have done the job - had it been allowed for classes.
ReplyDeleteCode extract
TSupplierEdit = class(TEditorGrid)
type
TRepStatusEdit = TEditorGrid.TEnumComboListEditor;
TBool = TEditorGrid.TEnumComboListEditor;
private
procedure SetSupplier(const Value: TPSDSupplier);
protected
SupplierId: TIntegerEdit;
SupplierNo: TStringEdit;
SupplierName: TStringEdit;
SupplierGS1No: TStringEdit;
SupplierGLN: TStringEdit;
OtherList: TRepStatusEdit;
Bool: TBool;
public
constructor Create(const aGrid: TAdvStringGrid); override;
property Supplier: TPSDSupplier;
end;
constructor TSupplierEdit.Create;
begin
inherited;
SupplierId := Add('Id');
SupplierId.ReadOnly := True;
SupplierNo := Add('SupplierNo');
SupplierName := Add('Name');
SupplierGS1No := Add('GS1 No');
SupplierGLN := Add('GLN');
Status := AddComboList('Status');
Status.Value := ersNew;
Bool := AddComboList('Can do?');
Bool.OnElementToString :=
function(value:Boolean):String
begin
case Value of
False: Result := 'Nope';
else Result := 'Yup';
end;
end;
end;
...
This is where I'd love to get rid of the .value ref.
procedure TSupplierEdit.SetSupplier(const Value: TPSDSupplier);
begin
FSupplier := Value;
SupplierEdit.SupplierId.Value := Supplier.Id;
SupplierEdit.SupplierNo.Value := Supplier.SupplierNo;
SupplierEdit.SupplierName.Value := Supplier.SupplierName;
SupplierEdit.SupplierGS1No.Value := Supplier.SuppliersGS1No;
SupplierEdit.SupplierGLN.Value := Supplier.SuppliersGLN;
SupplierEdit.OtherList.Value := ersRetry;
SupplierEdit.Bool.Value := True;
SupplierEdit.PopulateGrid;
end;
No, I don't want to use RTTI - as that only would work it for some of the use cases - unless I could somehow pass a class.property by reference and extract the property type from it as well as capturing getter and setter.
I am full of wishful thinking, it seems.
Any approach using a record will not work (or requires some nasty workarounds) or is just not worth it so save 6 characters of optimal code.
ReplyDeleteWhat you are trying here is some kind of operator lifting for the assign operator depending on the right side of the assignment. Delphi does not support that - the closest approach I can think of is really what I did with the observable in knockoff (I also blogged about it) - but it will not be suitable for you because due to the nature of anonymous method types you cannot access any other members on such a type. But that type is not to save 6 characters anyway.
it'd possible if property could be marked as "default" like we do with indexed [] properties, but then, how do you set the obj itself?
ReplyDeleteLooking your code, I think Supplier needs some assign method to do SupplierEdit.Assign(Supplier). At least, all .Value:= get isolated, hidden out of view.