8

Why does this code:

  w: word;
  s: String;
begin
  str(w, s);

generate this warning in XE7:

[dcc32 Warning] Unit1.pas(76): W1057 Implicit string cast from 'ShortString' to 'string'

Tom

Danilo Casa
  • 506
  • 1
  • 9
  • 18
Tom
  • 565
  • 1
  • 5
  • 21
  • One of the many compiler warnings I've been dealing with since upgrading from XE2 to XE7. – Jerry Dodge Jan 30 '15 at 22:13
  • Compiler actually generates a call to _StrLong which returns a shortstring. This is not an answer of course. – Sertac Akyuz Jan 30 '15 at 22:15
  • @Jerry - This is the same for XE2. – Sertac Akyuz Jan 30 '15 at 22:19
  • @Sertac Well the warning itself, not the exact scenario. – Jerry Dodge Jan 30 '15 at 22:28
  • @Jerry It's exactly the same. Nothing new here – David Heffernan Jan 30 '15 at 22:37
  • I believe that the problem is that str() does not have an overload that takes String (which is really UnicodeString), and only has an overload that takes shortstring. str() is an ancient DOS/TurboPascal era way to convert to string, and a more modern idiom would be `w.ToString()` or `IntToStr(w)` – Warren P Jan 30 '15 at 22:41
  • @David I didn't mean it's a new warning - same misunderstanding as last time we had this conversation :-) I mean changes to Delphi and libraries in other areas caused this compiler warning (and many others) to arise which otherwise didn't happen in XE2, but `Str` had nothing to do with them. Obviously use of `Str` would have raised the same warning in many prior versions, given its nature. – Jerry Dodge Jan 31 '15 at 00:20
  • @Jerry If XE2 -> XE7 upgrade leads to new W1057 warnings then I think you've got a real problem. At the very least you need to gain a clear understanding of why this happens. – David Heffernan Jan 31 '15 at 08:21

1 Answers1

5

System.Str is an intrinsic function that dates from a byegone era. The documentation says this:

procedure Str(const X [: Width [:Decimals]]; var S: String);

....

Notes: However, on using this procedure, the compiler may issue a warning: W1057 Implicit string cast from '%s' to '%s' (Delphi).

If a string with a predefined minimum length is not needed, try using the IntToStr function instead.

Since this is an intrinsic, there is likely something extra going on. Behind the scenes, the intrinsic function is implemented by a call to an RTL support function that yields a ShortString. Compiler magic then turns that into a string. And warns you of the implicit conversion. The compiler magic transforms

Str(w, s);

into

s := _Str0Long(w);

Where _Str0Long is:

function _Str0Long(val: Longint): _ShortStr;
begin
  Result := _StrLong(val, 0);
end;

Since _Str0Long returns a ShortString then the compiler has to generate code to perform the implicit converstion from ShortString to string when it assigns to your variable s. And of course it's then natural that you see W1057.

The bottom line is that Str only exists to retain compatibility with legacy Pascal ShortString code. New code should not be calling Str. You should do what the documentation says and call IntToStr:

s := IntToStr(w);

Or perhaps:

s := w.ToString;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Assigning System.Str to ShortString is one way of converting an integer to text without hitting heap memory allocation. – LU RD Jan 30 '15 at 23:03
  • @LURD True dat. I'd opine that there are better ways. In any case, here we assign to `string`. But for those edge cases where perf is critical then a case can be made for heap avoidance with `Str`. – David Heffernan Jan 30 '15 at 23:07
  • David: you showed me great restraint by not including "RTFM" in your post. Thanks for your usual thorough answer. Since we're migrating more than a million lines of code, I'm taking the "change as little as possible" route on this first phase by using $WARNINGS OFF on the few lines of code that invoke this. (They're actually Str(w:3:1, S), so there's a bit more going on than the simple example I provided... – Tom Jan 31 '15 at 01:12
  • @Tom In the short term a global disabling of W1057 would not hurt. Longer term you may end up with `w.ToString.PadLeft(3)` – David Heffernan Jan 31 '15 at 08:26