microsoft / AL

Home of the Dynamics 365 Business Central AL Language extension for Visual Studio Code. Used to track issues regarding the latest version of the AL compiler and developer tools available in the Visual Studio Code Marketplace or as part of the AL Developer Preview builds for Dynamics 365 Business Central.
MIT License
744 stars 245 forks source link

Warning on using fields not set by SetLoadFields/ AddLoadFields #6203

Closed fvet closed 3 years ago

fvet commented 4 years ago

Title Please provide a CodeCop warning if record fields are used after a record is fetched - where the record fetch is preceded by SetLoadFields/ AddLoadFields. Developers will definitly forget to add the new fields to the SetLoadFields/ AddLoadFields. (especially in parts of code where the function spans multiple pages) and it seems more logic including these already in the SetLoadFields/ AddLoadFields then to force a JIT loading.

Description Following the sample code on https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-partial-records, I decided to add one more field to the function ComputeArithmeticMean.

procedure ComputeArithmeticMean(): Decimal;
    var
        Item: Record Item;
        SumTotal: Decimal;
        Counter: Integer;
    begin
        Item.SetLoadFields(Item."Standard Cost");
        if Item.FindSet() then begin
            repeat
                SumTotal += Item."Standard Cost";
                SumTotal += Item."Unit Cost"; ///// ADDED FIELD
                Counter += 1;
            until Item.Next() = 0;
            exit(SumTotal / Counter);
        end;
    end;

If I understand the documentation correctly, only the 'Standard Cost' (added via SetLoadFields) will be fetched and any other fields (Unit Cost) will only be loading JIT. I would expect the compiler to warn me in case of a record.field usage in combination with a record.SetLoadFields/ record.AddLoadFields where the field has not been included, so we can avoid the JIT loading.

Reason for the rule If fields are used after data is fetched - where the data fetch is conditioned by SetLoadFields/ AddLoadFields - developers will definitly forget to add the new fields to the SetLoadFields/ AddLoadFields (especially in parts of code where the function spans multiple pages), resulting in additional JIT loading.

Bad code sample Example of what bad code the rule should catch:

procedure ComputeArithmeticMean(): Decimal;
    var
        Item: Record Item;
        SumTotal: Decimal;
        Counter: Integer;
    begin
        Item.SetLoadFields(Item."Standard Cost");
        if Item.FindSet() then begin
            repeat
                SumTotal += Item."Standard Cost";
                SumTotal += Item."Unit Cost"; ///// ADDED FIELD
                Counter += 1;
            until Item.Next() = 0;
            exit(SumTotal / Counter);
        end;
    end;

Good code sample Example of what code should look like:

procedure ComputeArithmeticMean(): Decimal;
    var
        Item: Record Item;
        SumTotal: Decimal;
        Counter: Integer;
    begin
        Item.SetLoadFields(Item."Standard Cost", Item."Unit Cost");
        if Item.FindSet() then begin
            repeat
                SumTotal += Item."Standard Cost";
                SumTotal += Item."Unit Cost"; ///// ADDED FIELD
                Counter += 1;
            until Item.Next() = 0;
            exit(SumTotal / Counter);
        end;
    end;
kalberes commented 4 years ago

I think it makes sense, at least to me.

PhDuck commented 4 years ago

@fvet this sounds like a good suggestion, will talk with someone who has more experience writing CodeCop, they could help estimate how hard it would be.

Regarding this particular example I would like to point out a smart optimization that I wrote while implementing Partial Records. When you are looping over rows, like in the above example, an incorrect estimate will only cause a single JIT load, when you call NEXT we will correct the SQL query to also fetch the field that caused a JIT load, so after first iteration the "Unit Cost" field will also by eager loaded, not triggering JIT loads.

PhDuck commented 3 years ago

I'm working on this and have a prototype that we will try to merge into a future version of the AL extension.

PhDuck commented 3 years ago

@qutreson we can close this issue since this was implemented ages ago in rule 0242.