You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This improvement would be generally useful, not specific to my code or setup.
Engine area
Delphi language support
Improvement description
Background
This is an undocumented implementation detail of the Delphi compiler.
Class operators are compiled to internal class functions, prefixed with a double-ampersand and internal operator name.
It's possible to manually implement these class functions, circumventing the ordinary rules around class overloads.
If you're feeling particularly clever, this lets you implement operator overloads in places where they're not ordinarily allowed (like record helpers).
Identifying internal names
We can find all of the internal operator names by emitting C++ builder headers for a Delphi record with operator overloads defined.
Given Delphi record TFoo:
type
TFoo = recordprivate
FValue: Integer;
publicconstructor Create(AValue: Integer);
classoperator Implicit(AValue: Integer): TFoo;
classoperator Explicit(AValue: Integer): TFoo;
classoperator Negative(const A: TFoo): TFoo;
classoperator Positive(const A: TFoo): TFoo;
classoperator LogicalNot(const A: TFoo): TFoo;
classoperator Inc(const A: TFoo): TFoo;
classoperator Dec(const A: TFoo): TFoo;
classoperator Trunc(const A: TFoo): TFoo;
classoperator Round(const A: TFoo): TFoo;
classoperatorIn(const A: Integer; const B: TFoo): Boolean;
classoperator Equal(const A, B: TFoo): Boolean;
classoperator NotEqual(const A, B: TFoo): Boolean;
classoperator GreaterThan(const A, B: TFoo): Boolean;
classoperator GreaterThanOrEqual(const A, B: TFoo): Boolean;
classoperator LessThan(const A, B: TFoo): Boolean;
classoperator LessThanOrEqual(const A, B: TFoo): Boolean;
classoperator Add(const A, B: TFoo): TFoo;
classoperator Subtract(const A, B: TFoo): TFoo;
classoperator Multiply(const A, B: TFoo): TFoo;
classoperator Divide(const A, B: TFoo): TFoo;
classoperator IntDivide(const A, B: TFoo): TFoo;
classoperator Modulus(const A, B: TFoo): TFoo;
classoperator LeftShift(const A, B: TFoo): TFoo;
classoperator RightShift(const A, B: TFoo): TFoo;
classoperator LogicalAnd(const A, B: TFoo): TFoo;
classoperator LogicalOr(const A, B: TFoo): TFoo;
classoperator LogicalXor(const A, B: TFoo): TFoo;
classoperator BitwiseAnd(const A, B: TFoo): TFoo;
classoperator BitwiseOr(const A, B: TFoo): TFoo;
classoperator BitwiseXor(const A, B: TFoo): TFoo;
classoperator Assign(var Dest: TFoo; var Src: TFoo);
classoperator Include(const A, B: TFoo): TFoo;
classoperator Exclude(const A, B: TFoo): TFoo;
classoperator True(const Src: TFoo): Boolean;
classoperator False(const Src: TFoo): Boolean;
classoperator OnesComplement(const Src: TFoo): TFoo;
propertyValue: Integer read FValue;
end;
The following C++ type is emitted:
structDECLSPEC_DRECORD TFoo
{
private:int FValue;
public:
__fastcall TFoo(int AValue);
static TFoo __fastcall _op_Implicit(int AValue);
static TFoo __fastcall _op_Explicit(int AValue);
static TFoo __fastcall _op_UnaryNegation(const TFoo A);
static TFoo __fastcall _op_UnaryPlus(const TFoo A);
static TFoo __fastcall _op_LogicalNot(const TFoo A);
static TFoo __fastcall _op_Increment(const TFoo A);
static TFoo __fastcall _op_Decrement(const TFoo A);
static TFoo __fastcall _op_Trunc(const TFoo A);
static TFoo __fastcall _op_Round(const TFoo A);
staticbool __fastcall _op_In(constint A, const TFoo B);
staticbool __fastcall _op_Equality(const TFoo A, const TFoo B);
staticbool __fastcall _op_Inequality(const TFoo A, const TFoo B);
staticbool __fastcall _op_GreaterThan(const TFoo A, const TFoo B);
staticbool __fastcall _op_GreaterThanOrEqual(const TFoo A, const TFoo B);
staticbool __fastcall _op_LessThan(const TFoo A, const TFoo B);
staticbool __fastcall _op_LessThanOrEqual(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Addition(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Subtraction(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Multiply(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Division(const TFoo A, const TFoo B);
static TFoo __fastcall _op_IntDivide(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Modulus(const TFoo A, const TFoo B);
static TFoo __fastcall _op_LeftShift(const TFoo A, const TFoo B);
static TFoo __fastcall _op_RightShift(const TFoo A, const TFoo B);
static TFoo __fastcall _op_LogicalAnd(const TFoo A, const TFoo B);
static TFoo __fastcall _op_LogicalOr(const TFoo A, const TFoo B);
static TFoo __fastcall _op_ExclusiveOr(const TFoo A, const TFoo B);
static TFoo __fastcall _op_BitwiseAnd(const TFoo A, const TFoo B);
static TFoo __fastcall _op_BitwiseOr(const TFoo A, const TFoo B);
static TFoo __fastcall _op_BitwiseXOR(const TFoo A, const TFoo B);
staticvoid __fastcall _op_Assign(TFoo &Dest, TFoo &Src);
static TFoo __fastcall _op_Include(const TFoo A, const TFoo B);
static TFoo __fastcall _op_Exclude(const TFoo A, const TFoo B);
staticbool __fastcall _op_True(const TFoo Src);
staticbool __fastcall _op_False(const TFoo Src);
static TFoo __fastcall _op_OnesComplement(const TFoo Src);
__property int Value = {read=FValue};
TFoo() {}
TFoo& operator =(int AValue) { *this = TFoo::_op_Implicit(AValue); return *this; }
TFoo operator -() { returnTFoo::_op_UnaryNegation(*this); }
TFoo operator +() { returnTFoo::_op_UnaryPlus(*this); }
TFoo operator !() { returnTFoo::_op_LogicalNot(*this); }
TFoo& operator ++() { *this = TFoo::_op_Increment(*this); return *this; }
TFoo operator ++(int) { TFoo tmp = *this; *this = TFoo::_op_Increment(*this); return tmp; }
TFoo& operator --() { *this = TFoo::_op_Decrement(*this); return *this; }
TFoo operator --(int) { TFoo tmp = *this; *this = TFoo::_op_Decrement(*this); return tmp; }
friendbooloperator ==(const TFoo A, const TFoo B) { returnTFoo::_op_Equality(A, B); }
friendbooloperator !=(const TFoo A, const TFoo B) { returnTFoo::_op_Inequality(A, B); }
friendbooloperator >(const TFoo A, const TFoo B) { returnTFoo::_op_GreaterThan(A, B); }
friendbooloperator >=(const TFoo A, const TFoo B) { returnTFoo::_op_GreaterThanOrEqual(A, B); }
friendbooloperator <(const TFoo A, const TFoo B) { returnTFoo::_op_LessThan(A, B); }
friendbooloperator <=(const TFoo A, const TFoo B) { returnTFoo::_op_LessThanOrEqual(A, B); }
friend TFoo operator +(const TFoo A, const TFoo B) { returnTFoo::_op_Addition(A, B); }
friend TFoo operator -(const TFoo A, const TFoo B) { returnTFoo::_op_Subtraction(A, B); }
friend TFoo operator *(const TFoo A, const TFoo B) { returnTFoo::_op_Multiply(A, B); }
friend TFoo operator /(const TFoo A, const TFoo B) { returnTFoo::_op_Division(A, B); }
friend TFoo operator %(const TFoo A, const TFoo B) { returnTFoo::_op_Modulus(A, B); }
friend TFoo operator <<(const TFoo A, const TFoo B) { returnTFoo::_op_LeftShift(A, B); }
friend TFoo operator >>(const TFoo A, const TFoo B) { returnTFoo::_op_RightShift(A, B); }
friend TFoo operator &&(const TFoo A, const TFoo B) { returnTFoo::_op_LogicalAnd(A, B); }
friend TFoo operator ||(const TFoo A, const TFoo B) { returnTFoo::_op_LogicalOr(A, B); }
friend TFoo operator &(const TFoo A, const TFoo B) { returnTFoo::_op_BitwiseAnd(A, B); }
friend TFoo operator |(const TFoo A, const TFoo B) { returnTFoo::_op_BitwiseOr(A, B); }
friend TFoo operator ^(const TFoo A, const TFoo B) { returnTFoo::_op_BitwiseXOR(A, B); }
TFoo operator ~() { returnTFoo::_op_OnesComplement(*this); }
};
Name data
Public operator name
Internal class function name
Implicit
&&op_Implicit
Explicit
&&op_Explicit
Negative
&&op_UnaryNegation
Positive
&&op_UnaryPlus
LogicalNot
&&op_LogicalNot
Inc
&&op_Increment
Dec
&&op_Decrement
Trunc
&&op_Trunc
Round
&&op_Round
In
&&op_In
Equal
&&op_Equality
NotEqual
&&op_Inequality
GreaterThan
&&op_GreaterThan
GreaterThanOrEqual
&&op_GreaterThanOrEqual
LessThan
&&op_LessThan
LessThanOrEqual
&&op_LessThanOrEqual
Add
&&op_Addition
Subtract
&&op_Subtraction
Multiply
&&op_Multiply
Divide
&&op_Division
IntDivide
&&op_IntDivide
Modulus
&&op_Modulus
LeftShift
&&op_LeftShift
RightShift
&&op_RightShift
LogicalAnd
&&op_LogicalAnd
LogicalOr
&&op_LogicalOr
LogicalXor
&&op_ExclusiveOr
BitwiseAnd
&&op_BitwiseAnd
BitwiseOr
&&op_BitwiseOr
BitwiseXor
&&op_BitwiseXOR
Assign
&&op_Assign
Include
&&op_Include
Exclude
&&op_Exclude
True
&&op_True
False
&&op_False
OnesComplement
&&op_OnesComplement
Rationale
Some Delphi libraries actually make use of this undocumented language "feature" to provide operator overloads in record helpers.
Spring4D is the most prominent example, using this approach to polyfill older versions of Delphi:
{$IFNDEF DELPHIXE3_UP}
TMethodHelper = recordhelperfor TMethod
publicclass function &&op_Equality(const left, right: TMethod): Boolean; static; inline;
class function &&op_Inequality(const left, right: TMethod): Boolean; static; inline;
class function &&op_GreaterThan(const left, right: TMethod): Boolean; static; inline;
class function &&op_LessThan(const left, right: TMethod): Boolean; static; inline;
end;
{$ENDIF}
The text was updated successfully, but these errors were encountered:
fourls
changed the title
[Engine Improvement]: Support operator overloads implemented by &&op_* class functions
Support operator overloads implemented by &&op_* class functions
Nov 27, 2023
Prerequisites
Engine area
Delphi language support
Improvement description
Background
This is an undocumented implementation detail of the Delphi compiler.
Class operators are compiled to internal class functions, prefixed with a double-ampersand and internal operator name.
It's possible to manually implement these class functions, circumventing the ordinary rules around class overloads.
If you're feeling particularly clever, this lets you implement operator overloads in places where they're not ordinarily allowed (like record helpers).
Identifying internal names
We can find all of the internal operator names by emitting C++ builder headers for a Delphi record with operator overloads defined.
Given Delphi record
TFoo
:The following C++ type is emitted:
Name data
Implicit
&&op_Implicit
Explicit
&&op_Explicit
Negative
&&op_UnaryNegation
Positive
&&op_UnaryPlus
LogicalNot
&&op_LogicalNot
Inc
&&op_Increment
Dec
&&op_Decrement
Trunc
&&op_Trunc
Round
&&op_Round
In
&&op_In
Equal
&&op_Equality
NotEqual
&&op_Inequality
GreaterThan
&&op_GreaterThan
GreaterThanOrEqual
&&op_GreaterThanOrEqual
LessThan
&&op_LessThan
LessThanOrEqual
&&op_LessThanOrEqual
Add
&&op_Addition
Subtract
&&op_Subtraction
Multiply
&&op_Multiply
Divide
&&op_Division
IntDivide
&&op_IntDivide
Modulus
&&op_Modulus
LeftShift
&&op_LeftShift
RightShift
&&op_RightShift
LogicalAnd
&&op_LogicalAnd
LogicalOr
&&op_LogicalOr
LogicalXor
&&op_ExclusiveOr
BitwiseAnd
&&op_BitwiseAnd
BitwiseOr
&&op_BitwiseOr
BitwiseXor
&&op_BitwiseXOR
Assign
&&op_Assign
Include
&&op_Include
Exclude
&&op_Exclude
True
&&op_True
False
&&op_False
OnesComplement
&&op_OnesComplement
Rationale
Some Delphi libraries actually make use of this undocumented language "feature" to provide operator overloads in record helpers.
Spring4D is the most prominent example, using this approach to polyfill older versions of Delphi:
The text was updated successfully, but these errors were encountered: