How to access items inside nested records that contain a variant record (union) in Pascal

1 Answer

0 votes
program NestedVariantRecord;

{$mode objfpc}{$H+}{$J-} // Enable ObjFPC mode and Ansistrings

uses
  SysUtils; // BoolToStr

type
  // 1. Define the tag (discriminator) enum
  TShapeType = (stCircle, stRectangle);

  // 2. Define specific nested sub-records
  TCircle = record
    Radius: Single;
  end;

  TRectangle = record
    Width: Single;
    Height: Single;
  end;

  // 3. Define nested metadata record
  TMetadata = record
    Name: string;
    IsActive: Boolean;
  end;

  // 4. Main record containing nested fields and a variant part (union)
  TShape = record
    ID: Integer;
    Metadata: TMetadata;
    // Variant record (union) — must be the last part of the record
    case ShapeType: TShapeType of
      stCircle: (Circle: TCircle);
      stRectangle: (Rectangle: TRectangle);
  end;

(**
 * Safely accesses and prints items from nested variant records.
 * Uses 'const' to pass by reference efficiently without pointers.
 *)
procedure PrintShapeProperties(const AShape: TShape);
begin
  // Access nested fields using direct dot notation
  WriteLn('Shape ID: ', AShape.ID);
  WriteLn('Shape Name: ', AShape.Metadata.Name);
  WriteLn('Status: ', BoolToStr(AShape.Metadata.IsActive, 'Active', 'Inactive'));

  // Switch on the tag field to safely read the active variant branch
  case AShape.ShapeType of
    stCircle:
      begin
        WriteLn('Type: Circle');
        WriteLn('Radius: ', AShape.Circle.Radius:0:2);
      end;

    stRectangle:
      begin
        WriteLn('Type: Rectangle');
        WriteLn('Width: ', AShape.Rectangle.Width:0:2, 
                ', Height: ', AShape.Rectangle.Height:0:2);
      end;
  end;
  WriteLn('------------------------------------');
end;

var
  MyCircle, MyRectangle: TShape;
begin
  // Initialize Circle
  MyCircle.ID := 101;
  MyCircle.Metadata.Name := 'Unit Circle';
  MyCircle.Metadata.IsActive := True;
  MyCircle.ShapeType := stCircle;
  MyCircle.Circle.Radius := 5.5;

  // Initialize Rectangle
  MyRectangle.ID := 102;
  MyRectangle.Metadata.Name := 'Bounding Box';
  MyRectangle.Metadata.IsActive := False;
  MyRectangle.ShapeType := stRectangle;
  MyRectangle.Rectangle.Width := 10.0;
  MyRectangle.Rectangle.Height := 20.0;

  // Print properties
  PrintShapeProperties(MyCircle);
  PrintShapeProperties(MyRectangle);
end.


{
run:

Shape ID: 101
Shape Name: Unit Circle
Status: Active
Type: Circle
Radius: 5.50
------------------------------------
Shape ID: 102
Shape Name: Bounding Box
Status: Inactive
Type: Rectangle
Width: 10.00, Height: 20.00
------------------------------------

}

 



answered 7 hours ago by avibootz
...