That is the case due to the way types like
ShortString,
AnsiString or dynamic arrays are handled as result types. They are passed as a hidden var parameter, so in fact your function declaration internally looks like this:
procedure StringToShortString(const S: String; var Result: ShortString);
Now depending on the code you have it can be that what the compiler passes in as
Result contains valid data, thus while you might set the length correctly you might still have “garbage” in there (in your case you set each character, so that doesn't matter here).
For example:
program tresult;
{$mode objfpc}
function Test1: ShortString;
begin
Result := 'Test';
end;
function Test2: ShortString;
begin
Writeln(Result);
end;
procedure Test;
var
ss: ShortString;
begin
ss := Test1;
ss := Test2;
end;
begin
Test;
end.
This will print “Test”. So safest in those cases is to do a
Result := ''; before changing the length.
And before you ask: no, this won't be changed and yes, that can happen in Delphi as well.