Inherited records lazarus / 64-FPC development ---------------------------------------------------------------------- SonnyBoyXXl · 2018-01-13 21:22 Hello together, so my last silly question for today Is it possible to derive records in FPC (maybe trunk version) like in C++? For example to translate this Quotestruct CD3DX12_PACKED_MIP_INFO : public D3D12_PACKED_MIP_INFO{}; to something like this Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  type    TD3DX12_PACKED_MIP_INFO = record(TD3D12_PACKED_MIP_INFO)    end;  Thx SonnyBoy ---------------------------------------------------------------------- taazz · 2018-01-13 21:25 the old object construct can be used instead of records for the same purpose. ---------------------------------------------------------------------- SonnyBoyXXl · 2018-01-13 21:42 When you have your own record definition (with no external requirements) : yes. But I'm using header definitions from Microsoft. And struct definied in the C++ .h headers are records in Pascal. When I'm using external functions in a DLL which have an struct as input parameter this should be a "record", not a "class". Is a class definied in FPC the "same"  as a struct in C++? ---------------------------------------------------------------------- marcov · 2018-01-13 21:43 Afaik object is fairly struct like till you use virtual methods. ---------------------------------------------------------------------- Zoran · 2018-01-13 21:48 Yes, unlike classes (whose instances are always created on the heap, meaning they are implicit pointers), objects can be created on the stack, so they are very similar to C++ structs (classes). See: https://www.freepascal.org/docs-html/current/ref/refch5.html Yes, you can simply use an object instead of record and derive from it -- see this example of inheritance, but add just fields, not methods, and you will get what you asked for. Edit: important note -- just to clarify -- the word object has two unrelated meanings in Pascal -- The word object is often use with meaning "instance of a class", but this is not what we are talking about here. The objects and classes are two distinct concepts of OOP which Object Pascal has -- see here: http://wiki.freepascal.org/Programming_Using_Objects ---------------------------------------------------------------------- marcov · 2018-01-13 22:23 Only virtual methods, as demonstrated by : Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Type   DrawingObject = Object      x, y : single;      height, width : single;      procedure Draw;   end;    DrawingObject2 = Object      x, y : single;      height, width : single;      procedure Draw; virtual;   end; procedure DrawingObject.Draw; begin end;procedure DrawingObject2.Draw; begin end;  begin     writeln(sizeof(drawingobject));                // 16, 4 singles;  writeln(sizeof(drawingobject2));               // 20 in 32-bit. 4*single + 1 x vmt pointer due to virtualend. ---------------------------------------------------------------------- Thaddy · 2018-01-14 06:43 @SonnyBoy: Your example shows just an empty record. If it is just a case of naming the C++ record try this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type    TD3DX12_PACKED_MIP_INFO =  TD3D12_PACKED_MIP_INFO;// or strongly typed:type    TD3DX12_PACKED_MIP_INFO = type TD3D12_PACKED_MIP_INFO; Usually such C(++) records are opaque to Pascal code. Therefor in recent trunk a special record and pointer type were added to the system unit: TOpaqueData and OpaquePointer that are for use in just such cases. You can declare these in the same manner as I described above and the compiler will provide type checking.  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type    PD3D12_PACKED_MIP_INFO = OpaquePointer;  // pointer to TOpaqueData    TD3D12_PACKED_MIP_INFO  = TOpaqueData;  // declared as an empty "opaque" record    PD3DX12_PACKED_MIP_INFO = ^TD3DX12_PACKED_MIP_INFO    TD3DX12_PACKED_MIP_INFO =  TD3D12_PACKED_MIP_INFO;// or strongly typed:type    TD3DX12_PACKED_MIP_INFO = type TD3D12_PACKED_MIP_INFO; This works because we usually need the pointers and not the structure itself and these are now  typed pointers in the same fashion as C++ expects. You need a very recent trunk for this. 3.1.1-r37942 ---------------------------------------------------------------------- SonnyBoyXXl · 2018-01-14 09:10 Hello Thaddy, you are right, this was a very simple example. @marcov and Zoran: objects can't handle unions and class operators (?) So let me give a more complex example: Quote//--------------------------------------------------------------- --------------- // 2D Vector; 32 bit floating point components struct XMFLOAT2 {     float x;     float y;     XMFLOAT2() XM_CTOR_DEFAULT     XM_CONSTEXPR XMFLOAT2(float _x, float _y) : x(_x), y(_y) {}     explicit XMFLOAT2(_In_reads_(2) const float *pArray) : x(pArray[0]), y(pArray[1]) {}     XMFLOAT2& operator= (const XMFLOAT2& Float2) { x = Float2.x; y = Float2.y; return *this; } }; // 2D Vector; 32 bit floating point components aligned on a 16 byte boundary __declspec(align(16)) struct XMFLOAT2A : public XMFLOAT2 {     XMFLOAT2A() XM_CTOR_DEFAULT     XM_CONSTEXPR XMFLOAT2A(float _x, float _y) : XMFLOAT2(_x, _y) {}     explicit XMFLOAT2A(_In_reads_(2) const float *pArray) : XMFLOAT2(pArray) {}     XMFLOAT2A& operator= (const XMFLOAT2A& Float2) { x = Float2.x; y = Float2.y; return *this; } }; //------ So this is my example (maybe not perfect) to convert this to pascal when inherited records are possible: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i type    TTwoSingleArray = array [0..1] of single;     // 2D Vector; 32 bit floating point components     { TXMFLOAT2 }     TXMFLOAT2 = record      class operator Initialize(var AFloat2:TXMFLOAT2);        constructor Create(_x, _y: single);        class operator Explicit(a: TTwoSingleArray): TXMFLOAT2;        case integer of            0: (x: single;                y: single);            1: (f: TTwoSingleArray);    end;     // 2D Vector; 32 bit floating point components aligned on a 16 byte boundary{$PACKRECORD 16}     { TXMFLOAT2A }     TXMFLOAT2A = record (TXMFLOAT2)        class operator Initialize (var AFloat2A:TXMFLOAT2A);        constructor Create(_x, _y: single);        class operator Explicit(a: TTwoSingleArray): TXMFLOAT2A;    end;  implementation { TXMFLOAT2A } class operator TXMFLOAT2A.Initialize(var AFloat2A: TXMFLOAT2A);begin    ZeroMemory(AFloat2A,SizeOf(TXMFLOAT2A));end; constructor TXMFLOAT2A.Create(_x, _y: single);begin    inherited;end; class operator TXMFLOAT2A.Explicit(a: TTwoSingleArray): TXMFLOAT2A;begin    inherited;end;  { TXMFLOAT2 } class operator TXMFLOAT2.Initialize(var AFloat2: TXMFLOAT2);begin    ZeroMemory(AFloat2,SizeOf(TXMFLOAT2));end; constructor TXMFLOAT2.Create(_x, _y: single);begin    x:=_x;    y:=_y;end; class operator TXMFLOAT2.Explicit(a: TTwoSingleArray): TXMFLOAT2;begin    Result.f:=a;end; struct - public sequences are rare in the MS API as I checked yesterday. But if you have a definition like this Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  TDWRITE_FONT_METRICS = record        designUnitsPerEm: UINT16;      ascent: UINT16;        descent: UINT16;        lineGap: INT16;        capHeight: UINT16;        xHeight: UINT16;        underlinePosition: INT16;        underlineThickness: UINT16;        strikethroughPosition: INT16;        strikethroughThickness: UINT16;  end; TDWRITE_FONT_METRICS1 = record        {TDWRITE_FONT_METRICS}      designUnitsPerEm: UINT16;        ascent: UINT16;        descent: UINT16;        lineGap: INT16;        capHeight: UINT16;        xHeight: UINT16;        underlinePosition: INT16;        underlineThickness: UINT16;        strikethroughPosition: INT16;      strikethroughThickness: UINT16;      { New }        glyphBoxLeft: INT16;         glyphBoxTop: INT16;         glyphBoxRight: INT16;      glyphBoxBottom: INT16;        subscriptPositionX: INT16;        subscriptPositionY: INT16;        subscriptSizeX: INT16;        subscriptSizeY: INT16;        superscriptPositionX: INT16;        superscriptPositionY: INT16;        superscriptSizeX: INT16;        superscriptSizeY: INT16;        hasTypographicMetrics: longbool;    end;  inherited records can save code Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TDWRITE_FONT_METRICS1 = record (TDWRITE_FONT_METRICS)      { New }      glyphBoxLeft: INT16;         glyphBoxTop: INT16;         glyphBoxRight: INT16;        glyphBoxBottom: INT16;        subscriptPositionX: INT16;        subscriptPositionY: INT16;        subscriptSizeX: INT16;        subscriptSizeY: INT16;        superscriptPositionX: INT16;        superscriptPositionY: INT16;      superscriptSizeX: INT16;        superscriptSizeY: INT16;        hasTypographicMetrics: longbool;    end; ---------------------------------------------------------------------- dicepd · 2018-01-15 19:12 I can think of another case where inheritance in adv records would be really useful. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TGLZVector4f =  record  {lots of methods here}   class operator -(constref A: TGLZVector4f): TGLZVector4f; overload;    case Byte of    0: (V: TGLZVector4fType);      1: (X, Y, Z, W: Single);      2: (Red, Green, Blue, Alpha: Single);      3: (AsVector3f : TGLZVector3f);         4: (ST,UV : TGLZVector2f);      5: (Left, Top, Right, Bottom: Single);      6: (TopLeft,BottomRight : TGLZVector2f);       end;  For most of the 'types' in the accessors negate works fine, the negative of each of the members. However when it comes to using as a homogenous vector it all falls down and needs some way of overriding negate to only negate X,Y,Z. Currently means whole new record for homogenous or ugly HmgNegate method. ---------------------------------------------------------------------- dicepd · 2018-01-15 20:38 The other way around the above would be to allow operators in record helpers. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TGLZHmgVector4f = TGLZVector4f; TGLZVectorHelper = record helper for TGLZVector4f  public   class operator -(constref A: TGLZHmgVector4f): TGLZVector4f; overload;end; ---------------------------------------------------------------------- Thaddy · 2018-01-16 06:45 Note you should always add the methods *after* the fields, so fields first, then the methods, albeit only to reflect it is still a record. ---------------------------------------------------------------------- dicepd · 2018-01-16 08:23 Quote from: Thaddy on January 16, 2018, 07:45:39 amNote you should always add the methods *after* the fields, so fields first, then the methods, albeit only to reflect it is still a record. The compiler does not give a hoot about the order, just your convention? ---------------------------------------------------------------------- Thaddy · 2018-01-16 08:27 Depends. e.g.  field re-ordering. You can not rely on that. Now it is OK, but that is implementation detail. Better to keep it in record order as intended. See all official examples.