6 ms·
Yes, but this example of matrix multiplication does weird stuff: {$MODE DELPHI} {$modeswitch advancedrecords} type TMatrix<T, R, C> = record
by dannymi 3y ago
Yes, but this example of matrix multiplication does weird stuff:
{$MODE DELPHI}
{$modeswitch advancedrecords}
type
TMatrix<T, R, C> = record
fCoordinates: array[R, C] of Double;
end;
function mul<T, R, X, C>(A: TMatrix<T, R, X>; B: TMatrix<T, X, C>): TMatrix<T, R, C>;
var
i: R;
j: X;
k: C;
begin
Writeln('yep');
Writeln(High(R)); // 3
Writeln(High(X)); // 4
Writeln(High(C)); // 3
for i := Low(R) to High(R) do
for k := Low(C) to High(C) do begin
Result.fCoordinates[i, k] := 0;
for j := Low(X) to High(X) do
Result.fCoordinates[i, k] += A.fCoordinates[i, j] * B.fCoordinates[j, k]
end
end;
type
R1 = 1..3;
R2 = 1..4;
var
A: TMatrix<Double, R1, R2>;
B: TMatrix<Double, R1, R1>;
C: TMatrix<Double, R2, R1>;
begin
mul<Double, R1, R2, R1>(A,B); // should fail because B would have to have as many rows as A has columns--and it doesn't.
mul(A,C) // does not work even with a right-size C--even though it should
end.
- badsectoracula 3y agoThe second bit is because you lack the explicit specialization - you must always tell the compiler how to specialize a generic. Personally i prefer to use generics in objfpc mode as you are more explicit that way. However FPC trunk can allow implicit function specialization if you request it with {$modeswitch implicitfunctionspecialization}. Your code compiles with that. The first bit is an interesting case and i wonder why it happens. It seems the root cause is that it considers the two type specializations equivalent as even ignoring the generic functions something like "A:=B" is allowed. I trimmed the code down to this: {$MODE DELPHI} type TMatrix<R, C> = record X: array[R, C] of Double; end; type R1 = 1..3; R2 = 1..4; var A: TMatrix<R1, R2>; B: TMatrix<R1, R1>; begin A:=B; end. This is clearly a bug and not intentional behavior as doing the specialization by hand shows an error as expected. Also it seems related to multidimensional arrays as with a single element it also shows an error. Note that the other way (B:=A) doesn't work, so my guess is that at some point the type compatibility comparison only checks if assigning one array would fit memory-wise into the other. I'll check against latest trunk later and if it happens i'll file a bug report.
- dannymi 3y agoThank you! I also tried {$R+} type R1 = 1..3; R2 = 1..4; var a: R1; b: R2; begin b := 4; a := b; Writeln(a) end. ... and that only gives me a runtime error. So maybe those types count as equal anyway?
- badsectoracula 3y agoThe types themselves count as assignable since the values can be compatible and unless the compiler can tell statically a value is out of range it wont complain at compile time (but will at runtime if range checking is enabled). However using the ranges for arrays is not compatible, if you have a A: array [R1] of Double and a B: array [R2] of Double you can't assign one to the other.