Why is a Currency variable treated as a constant with FillChar in Delphi?
Asked Answered
C

2

12

The following code should compile and does compile with many other types.
However, the compiler reports a "Constant object cannot be passed as var parameter" error - despite the variable quite obviously being a variable.

program CurrencyConstant;
{$APPTYPE CONSOLE}
var
  GVar: Currency;
begin
  FillChar(GVar, SizeOf(GVar), 0);
end.

Similarly, the same problem occurs with a local variable in a procedure.

procedure TestCurrency;
var
  LVar: Currency;
begin
  FillChar(LVar, SizeOf(LVar), 0);
end;

I suspect it has something to do with the fact that FillChar is a compiler magic procedure, and that Dest is an untyped var parameter. FillChar is the only routine I've found with this problem.

  • What causes this problem?
  • Are any other types affected?

In response to the inevitable "Why would you do that comments": We have a code generator that uses FillChar to generically initialise record structures & primitive types. It works with everything else, but unexpectedly failed with Currency. We do have workarounds, but it would be nice to understand the root cause, and know whether anything else is likely to cause us trouble.


Edit

From Jeroen's answer it is reasonable to conclude that the issue exists in all vesions of Delphi. Furthermore array's of Currency apparently exhibit a similar problem.

David's answer provides some nice workarounds.

One final workaround to consider is, modifying the generator to deal with Currency as a special case and simply set the Value := 0.

Contradistinguish answered 10/9, 2013 at 11:39 Comment(6)
It still occurs in Delphi XE4. Report No: 118866 Status: Reported Cannot perform FillChar on Currency variables qc.embarcadero.com/wc/qcmain.aspx?d=118866 It is similar to qc.embarcadero.com/wc/qcmain.aspx?d=87168 Workaround for Delphi < 2009: use ZeroMemory from the Windows unit which works just as well as FillChar.Fabriane
@Jeroen Guess how ZeroMemory is implemented?Mb
@JeroenWiertPluimers Thanks. Could you re-post as an answer? Those links deserve more prominence than a mere comment.Contradistinguish
@CraigYoung that report is now marked as fixed. I wonder which version of Delphi the fix will ship in.Fabriane
@CraigYoung it got fixed in Delphi XE5 Update 2; look for 118866: edn.embarcadero.com/article/43522Fabriane
@JeroenWiertPluimers Cool, thanks. I've updated your answer with the info.Contradistinguish
F
2

As requested by Craig Young:

It still occurs in Delphi XE4.
Report No: 118866 Status: Reported
Cannot perform FillChar on Currency variables
https://web.archive.org/web/20150322021442/http://qc.embarcadero.com/wc/qcmain.aspx?d=118866
It is similar to http://qc.embarcadero.com/wc/qcmain.aspx?d=87168 (not archived)

The workaround for this compiler bug for Delphi < 2009: use ZeroMemory or FillMemory from the Windows unit which works just as well as FillChar.

On the Delphi side, ZeroMemory and FillMemory use FillChar underneath which might be inlined as of Delphi 2006.
On the C++ side both use compiler macros.

It might be that this issue only happens with Currency because that is the only numeric compiler type that is scaled.
The issue does not reproduce with ordinal types, regular floating point types, and Comp.


Edit: The issue has been fixed in XE5 Update 2

Fabriane answered 11/9, 2013 at 9:54 Comment(5)
An accepted answer really ought to answer the question. Couldn't you make it so.Mb
The other QC report that you found is not just similar, it is identical. It also passes a Currency variable to FillChar. The variable happens to be part of an array, but vaArray[viSize] is Currency. So your new QC report is a dupe. That said, neither are very good reports. Why didn't you submit an SSCCE? You submitted all that extra fluff instead of the beautiful SSCCE from this question.Mb
@DavidHeffernan I formulated the QC this way because I know how the QC entry gets added to the test suites. Compiler handling of array elements might be different than simple variables, especially for compiler built-in specials. The QC I entered might not be identical to the other QC, the compiler engineers will surely indicate if it is: they are the ones that know for sure. I just searched (and this time found!) what I was after: a related report. This answer was purely as a gesture towards Craig. If you don't like it: vote it down and/or ask Craig to un-accept it.Fabriane
I didn't say I don't like it. I just said that you should answer the question. Just a minor edit to say that it's a compiler bug. As for the QC report, I've heard Allen say that he prefers simple reports. Surely it's for them to work out all the cases that need to be considered in their test suite. Outsiders cannot do so and will only miss things.Mb
Note that QualityCentral has now been shut down, so you can't access qc.embarcadero.com links anymore. If you need access to old QC data, look at QCScraper.Aggappera
M
9

What causes the problem?

A compiler bug. Please submit a QC report.

Are any other types affected?

Maybe. Try some to find out.


As for a work around I would write it like this:

FillChar(Pointer(@LVar)^, SizeOf(LVar), 0);

or perhaps like this:

ZeroMemory(@LVar, SizeOf(LVar));

or even like this:

LVar := Default(Currency);

Personally I regard ZeroMemory as being more descriptive than FillChar.

Mb answered 10/9, 2013 at 11:59 Comment(4)
Note that the Pointer cast above is needed if you are compile with typed address operatorMb
Or you can use a double type cast FillChar(double(GVar), SizeOf(GVar), 0). This is relative safe because you get an error message if SizeOf(GVar)<>SizeOf(double) in future versions.Chivaree
@DavidHeffernan Thanks David, we were going to use the Pointer cast as a workaround - I hadn't thought of ZeroMemory. However, the latter is clearly better. As for Default(), its not available on D2007. I confirmed it is available in D2009, but cannot find any documentation for it. (It's not even mentioned in XE4 online docs of System.) Are you aware of any?Contradistinguish
@CraigYoung It should appear here: docwiki.embarcadero.com/RADStudio/en/Delphi_Intrinsic_Routines but I can only find it here: docwiki.embarcadero.com/RADStudio/en/… For your code gen then ZeroMemory is a good option. It will be inlined into a call to FillChar in the end!Mb
F
2

As requested by Craig Young:

It still occurs in Delphi XE4.
Report No: 118866 Status: Reported
Cannot perform FillChar on Currency variables
https://web.archive.org/web/20150322021442/http://qc.embarcadero.com/wc/qcmain.aspx?d=118866
It is similar to http://qc.embarcadero.com/wc/qcmain.aspx?d=87168 (not archived)

The workaround for this compiler bug for Delphi < 2009: use ZeroMemory or FillMemory from the Windows unit which works just as well as FillChar.

On the Delphi side, ZeroMemory and FillMemory use FillChar underneath which might be inlined as of Delphi 2006.
On the C++ side both use compiler macros.

It might be that this issue only happens with Currency because that is the only numeric compiler type that is scaled.
The issue does not reproduce with ordinal types, regular floating point types, and Comp.


Edit: The issue has been fixed in XE5 Update 2

Fabriane answered 11/9, 2013 at 9:54 Comment(5)
An accepted answer really ought to answer the question. Couldn't you make it so.Mb
The other QC report that you found is not just similar, it is identical. It also passes a Currency variable to FillChar. The variable happens to be part of an array, but vaArray[viSize] is Currency. So your new QC report is a dupe. That said, neither are very good reports. Why didn't you submit an SSCCE? You submitted all that extra fluff instead of the beautiful SSCCE from this question.Mb
@DavidHeffernan I formulated the QC this way because I know how the QC entry gets added to the test suites. Compiler handling of array elements might be different than simple variables, especially for compiler built-in specials. The QC I entered might not be identical to the other QC, the compiler engineers will surely indicate if it is: they are the ones that know for sure. I just searched (and this time found!) what I was after: a related report. This answer was purely as a gesture towards Craig. If you don't like it: vote it down and/or ask Craig to un-accept it.Fabriane
I didn't say I don't like it. I just said that you should answer the question. Just a minor edit to say that it's a compiler bug. As for the QC report, I've heard Allen say that he prefers simple reports. Surely it's for them to work out all the cases that need to be considered in their test suite. Outsiders cannot do so and will only miss things.Mb
Note that QualityCentral has now been shut down, so you can't access qc.embarcadero.com links anymore. If you need access to old QC data, look at QCScraper.Aggappera

© 2022 - 2024 — McMap. All rights reserved.