Recent

Author Topic: SetLength and compiler hints  (Read 3528 times)

Grahame Grieve

  • Sr. Member
  • ****
  • Posts: 365
SetLength and compiler hints
« on: October 25, 2021, 08:56:14 am »
I've just been caught out by an uninitialised variable. I didn't get any hint for it - I'll get to that later. So I've turned all uninitialised variable hints back on, and this code generates a hint:

function StringToShortString(const S: String) : ShortString;
var
  i : integer;
begin
  SetLength(result, min(s.Length, 255));
  for i := 1 to length(result) do
    result := AnsiChar(s);
end; 

I have 1000s of these things - pretty much whereever I use SetLength, I'm going to get a warning. But why? I am initialising the variable...

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: SetLength and compiler hints
« Reply #1 on: October 25, 2021, 09:25:00 am »
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:

Code: Pascal  [Select][+][-]
  1. 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:

Code: Pascal  [Select][+][-]
  1. program tresult;
  2.  
  3. {$mode objfpc}
  4.  
  5. function Test1: ShortString;
  6. begin
  7.   Result := 'Test';
  8. end;
  9.  
  10. function Test2: ShortString;
  11. begin
  12.   Writeln(Result);
  13. end;
  14.  
  15. procedure Test;
  16. var
  17.   ss: ShortString;
  18. begin
  19.   ss := Test1;
  20.   ss := Test2;
  21. end;
  22.  
  23. begin
  24.   Test;
  25. 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.

creaothceann

  • Full Member
  • ***
  • Posts: 117
Re: SetLength and compiler hints
« Reply #2 on: October 25, 2021, 12:38:31 pm »
If you're sure that it'll always be a ShortString then you can also set the length via Result[0].

Code: Pascal  [Select][+][-]
  1. function StringToShortstring(const s : string) : Shortstring;
  2. var
  3.         i : integer;
  4. begin
  5.         i := min(s.Length, 255);
  6.         Result[0] := AnsiChar(i);
  7.         for i := 1 to i do  Result[i] := AnsiChar(s[i]);
  8.         // alternative: Result := Copy(s, 1, min(s.Length, 255));
  9. end;
  10.  

Grahame Grieve

  • Sr. Member
  • ****
  • Posts: 365
Re: SetLength and compiler hints
« Reply #3 on: October 25, 2021, 10:06:41 pm »
what about for dynamic arrays, where the same issue arises - I can't set them to ''

Bart

  • Hero Member
  • *****
  • Posts: 5275
    • Bart en Mariska's Webstek
Re: SetLength and compiler hints
« Reply #4 on: October 25, 2021, 10:28:31 pm »
Set them to nil.

Bart

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: SetLength and compiler hints
« Reply #5 on: October 27, 2021, 10:13:28 am »
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:

Code: Pascal  [Select][+][-]
  1. procedure StringToShortString(const S: String; var Result: ShortString);

Why is that not an out parameter, which I think would avoid this specific problem?

Quote
And before you ask: no, this won't be changed and yes, that can happen in Delphi as well.

Having a useful hint in the compiler which in practice has to be disabled is an abomination every bit as bad as the laxity of C.

Speaking as somebody who has promoted "the Pascal way" for the last 40+ years, I am disappointed that the major language implementations have degenerated to the point where they prefer to introduce "computer science crap" like generics instead of fixing this sort of fundamental problem.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: SetLength and compiler hints
« Reply #6 on: October 28, 2021, 09:18:43 am »
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:

Code: Pascal  [Select][+][-]
  1. procedure StringToShortString(const S: String; var Result: ShortString);

Why is that not an out parameter, which I think would avoid this specific problem?

Because that's how Delphi does it as well, so it's possible that there is code out there that relies on this behaviour. And the RTL itself is actively using this implementation detail.

 

TinyPortal © 2005-2018