FR: allow variant part to be specified not in the very end of the advanced record definition
Not a crucial thing. At all. I just wanted to put it into words somewhere in the appropriate place.
This usage of variant fields compiles and works perfectly, and is a convenient way to work with mathematical primitives in particular:
type
Vec3 = record
// ... methods ...
case uint32 of
0: (v: array[0 .. 2] of single);
0: (x, y, z: single);
end;
Quaternion = record
// ... methods ...
case uint32 of
0: (v: array[0 .. 3] of single);
0: (x, y, z, w: single);
0: (v3: Vec3);
end;
Plane = record
// ... methods ...
case uint32 of
0: (coefs: array[0 .. 3] of single);
0: (a, b, c, d: single);
0: (abc: Vec3);
end;
But sometimes you'll want properties that access variant fields. Say, to have read-only Plane.normal
for use in contexts where the fact that the normal is the same thing as the vector of (A, B, C) coefficients isn't important and only adds extra cognitive load.
type
Plane = record
case uint32 of
0: (coefs: array[0 .. 3] of single);
0: (a, b, c, d: single);
0: (abc: Vec3);
public
property normal: Vec3 read abc;
end;
This will not compile: no sections can follow variant part, even if they don't add fields.
There is an easy way to get around this:
type
Plane = record
data: record
case uint32 of
0: (coefs: array[0 .. 3] of single);
0: (a, b, c, d: single);
0: (abc: Vec3);
end;
public
property a: single read data.a write data.a;
// ...
property normal: Vec3 read data.abc;
end;
But this makes things slightly less convenient, as you (for a good reason) cannot pass properties as non-const
reference parameters, nor assign array/record elements through the properties that reference array/record as a whole:
{$mode objfpc} {$modeswitch advancedrecords}
type
Matrix3 = record
type
MatrixData = array[0 .. 2, 0 .. 2] of single;
LinearData = array[0 .. 8] of single;
var
data: record
case uint32 of
0: (m: MatrixData);
1: (l: LinearData);
end;
public
property m: MatrixData read data.m write data.m;
property l: LinearData read data.l write data.l;
end;
var
m: Matrix3;
begin
// will not compile
// m.m[1, 2] := 3;
// works, but becomes wordy when assigning many elements
m.data.m[1, 2] := 3;
end.
So, can we have non-terminal variant parts? ;__;
Or, even better, have multiple of them: there are occasional C libraries that abuse anonymous unions and their bindings would benefit from it.