AL icon indicating copy to clipboard operation
AL copied to clipboard

Ternary operator values implicit conversion issues

Open RadoArvay opened this issue 1 year ago • 10 comments

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

RadoArvay avatar Dec 18 '24 13:12 RadoArvay

@BazookaMusic This is related to #7926 - but this time, both return parts are string, so this is another issue.

NKarolak avatar Dec 18 '24 14:12 NKarolak

Yes, I saw that issue and I wanted to continue there, but it is already closed and, as you wrote, there are different types.

RadoArvay avatar Dec 18 '24 14:12 RadoArvay

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 avatar Dec 18 '24 19:12 BazookaMusic

@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.

NKarolak avatar Dec 18 '24 20:12 NKarolak

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.

RadoArvay avatar Dec 18 '24 21:12 RadoArvay

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.

BazookaMusic avatar Dec 18 '24 21:12 BazookaMusic

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).

RadoArvay avatar Dec 19 '24 04:12 RadoArvay

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.

bjarkihall avatar Mar 10 '25 03:03 bjarkihall

@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.

NKarolak avatar Mar 10 '25 10:03 NKarolak

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;
}

Image

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..

navdotnetreqs avatar Apr 02 '25 03:04 navdotnetreqs