Keep in mind that a class is a reference. The CONST part governs assignment to the reference, not the instance that the reference points too.
Bit more detailed.
1) Calling the method indeed takes a pointer to the record.
The record is declared const (though for the meaning of that, see "2" below).
(self is (like) a var param in case of an advanced record)
TContainer = record
Items: array of Integer;
procedure Resize(Count: SizeInt);
end;
PContainer = ^TContainer;
procedure TContainer.Resize(Count: SizeInt);
begin
SetLength(Items, Count);
end;
procedure Foo(const Container: TContainer);
begin
//SetLength(Container.Items, 1); // fails
SetLength(PContainer(@Container)^.Items, 1); // compiles / but is wrong code (see "2")
Container.Resize(100); // Completely fine (unless `Resize` is inlined)
end;
The compiler does not know that the pointer is to the const var. Well, it could in this case, but you can always make it arbitrary complex.
2) "const param"
Check the docs.
It says something along the lines "const" means the programmer promises to the compiler, that the code (written by the programmer) will not modify the value.
- "const param" are not an instruction to the compiler to check that (even though it will check the easy cases).
- "const param" are a promise to the compiler (checked by the user) to allow the compiler to perform various optimizations.
therefore, if you make that promise and break it, then your wrote invalid code. And such code may have undefined behaviour (wrong results, crashes, anything).
There are examples demonstrating this with ansistrings, if you search the forum.
It may be, that improved versions of the compiler will in the future detect this case (even if not inlining / but according to the doc, they don't have to).