Ternary operator values implicit conversion issues
Is it fully by design or sort of a bug?
1. Describe the bug
When I use the ternary operator with one-character text constants as values, I get conversion errors (compiler or runtime) between Text and Character types.
2. To Reproduce
Standard is TextElement from XmlPort, but it does not matter, it can be any Text variable.
Example 1:
Standard := OptionValue = DummyVATReportHeader."VAT Report Type"::Standard ? '1' : ''; (empty text)
Cannot implicitly convert type 'Text' to 'Char' AL0122
It is the compiler error in VSCode. Ok, two different types of values are used, but couldn't it be more looser?
"Negative" definition is OK in VSC, but I did not try to publish and run it:
Standard := OptionValue <> DummyVATReportHeader."VAT Report Type"::Standard ? '' : '1';
Example 2:
Standard := OptionValue = DummyVATReportHeader."VAT Report Type"::Standard ? '1' : ' '; (one-space-constant) or
Standard := OptionValue = DummyVATReportHeader."VAT Report Type"::Standard ? '1' : '0';
AL compiler in VSC does not complain. BusinessCentral will crash when run that code - and it is not debuggable. But in debug mode, VSC shows the conversion error:
Error: C# compilation has failed for the application object XmlPort_nnn.
The failing c# file name is 5F513583CF61537DB8A2B84F5170D2575517F854DED61E60FD0ECD0091A256A3.cs. You can find this file with the associated AL file saved in the C:\ProgramData\Microsoft\Microsoft Dynamics NAV\252\Server\MicrosoftDynamicsNavServer$BC\apps\compilationerrors folder.
Detailed compilation error: C:\ProgramData\Microsoft\Microsoft Dynamics NAV\252\Server\MicrosoftDynamicsNavServer$BC\apps\metadata\3\5F\5F513583CF61537DB8A2B84F5170D2575517F854DED61E60FD0ECD0091A256A3.cs(1242,60): error CS1503: Argument 1: cannot convert from 'target-typed conditional expression' to 'string'
3. Expected behavior
4. Actual behavior
5. Versions:
- AL Language: 14.2.1249978 (I did not test the insider 15.0)
- Business Central: 25.2.27733.28023
- Operating System:
- [X] Windows
- [ ] Linux
- [ ] MacOS
Internal work item: AB#561007
@BazookaMusic This is related to #7926 - but this time, both return parts are string, so this is another issue.
Yes, I saw that issue and I wanted to continue there, but it is already closed and, as you wrote, there are different types.
Accepting because C# compilation errors is a bug. If it compiles it should run.
However, the conversion errors are because these are the conversion rules for AL. Since the type of the expression is decided by the "true" side, you need to adjust the code so that there is a conversion from the "false" side to the "true" side.
Maybe it makes sense to adjust these conversion rules, so you can add an idea in BCIdeas with some annoying examples.
@BazookaMusic
Since the type of the expression is decided by the "true" side, you need to adjust the code so that there is a conversion from the "false" side to the "true" side.
I don't get this. Did you mean that we should adjust the AL code? Why and how - all of the true and false parts above return a string.
No Natalie, it is as the compiler says in Example 1: true part returns Char type ('1') - unfortunately (because it is only one character). false part in my examples is either Text (empty string ''), or Char (one-spaced string ' '). It is very strict implicit conversion. I would be glad if it has been more looser conversion between these two types, but ok, I get it.
They were very special examples. I did not try it, but if I used Labels or Text variables, it would run correctly, I believe.
One trick that we sometimes use in C# is to do '1'.ToString(), so you can use the Format function on the left side to make sure it's a text.
However, I have to say that the fact that 1 character strings are chars is a pain point.
As you write, ToString() or Format() should help and I considered that but I chose other solution eventually. Problem is that all of "string helpers" lower readability and simplicity of code - and that is what the ternary operator is meant for (I think).
Shorter way of casting is wrapping a string-concatenation inside parenthesis: Message(true ? ('' + 'a') : '')
Too bad we need workarounds like these since 1-letter string-literals are reserved for Chars.
@BazookaMusic
the type of the expression is decided by the "true" side
Suggestion: This data type determination "by true side" should be done only when assigning the result to a Variant (like here). In all other cases, we assign to a variable/parameter of an explicit data type. And we cannot use ternary operators without using the result value. In the example of the Message method taking in a string, the AL compiler should check both return values of the ternary expression to be Text, and not the other way round.
Here's a super simple example to demonstrate this bug:
pageextension 50100 "Customer List Test" extends "Customer List"
{
trigger OnOpenPage()
var
Boo: Boolean;
Quantity: Decimal;
OrigQty: Decimal;
begin
OrigQty := 0.25;
Boo := false;
Quantity := Boo ? 1 : OrigQty;
end;
}
So as you can see, the implicit conversion effects integer/decimal values as well. This is not great. If the type determination cannot be fixed and must be done by one var or the other, at least give a compilation error if the types don't match. And if not even that, make it a CodeCop rule..