Dynamics 365 Business Central: obsoleting the WITH statement

As you ever used the WITH clause in C/AL or AL language? There are lovers of this clause and there are developers that hate using this clause (I’m in this second category), but despite every personal opinion the WITH clause is widely used in code and also in the Microsof’s Base Application.

As announced at the Dynamics 365 Business Central Virtual Event, Microsoft is continuously evolving the platform and their apps (today and in the future) and they need to be able to upgrade tenants smoothly while trying to not break our extensions.

The WITH clause can help you on writing a more readable code in certain situations (I don’t think so but that was the goal) but it creates a lot of un-efficiency related to code compilation. For avoiding this, Microsoft is planning to making the WITH clause obsolete and you should start forgot it (please don’t use it anymore!) and start fixing your apps accordingly.

When using WITH, in AL (or C/AL too) there are two types of usage: explicit WITH and implicit WITH.

Explicit WITH is something like in the following example:

Here I have a codeunit with a ProcessCustomer method that uses WITH to reference the Customer record. The procedure calls a local method called IsReady to determine if the Customer record can be inserted into the database.

What happens now if another extension (or Microsoft itself) will add a new method called IsReady in the Customer table? Something like the following:

The problem here is related to symbols lookup. To resolve symbols, the compiler checks the following scopes (in the following order):

  1. “With” scope: Customer and Customer extension members, Record class members
  2. Method scope: Parameters and variables
  3. Object scope: global variables and methods, fields, base class members
  4. Global scope: enums, built-in methods and classes

In this way, your code here can have an unpredictable result (the IsReady() method declared in the tableextension wins and brokes your code because you can have totally different results than what you want to achieve in your local IsReady() method).

And if (for example) the IsReady() method declared in the tableextension requires a parameter, your code will not compile anymore and your extension is totally broken (you have a compilation error now):

This is the reason while Microsoft in the future AL language extension will signal you a warning in code if you’re using the WITH clause:

and fortunately you will have code actions for fixing these problems:

taht when clicked will transform your code as follows:

While fixing the explicit WITH could be quite easy, the implicit WITH is instead more difficult to catch and it’s something like in the following example. Imagine that I have a codeunit that works on the Customer table:

Here the implicit WITH could be fixed by prefixing Rec. and you can use AL code actions to do that:

If I click on the code action for fixing the implicit WITH, you can see that the code is fixed by appending Rec. to the methods, but the IsReady() method that I want to use here is not prefixed (because it’s declared locally):

And if someone (a third-party extension or Microsoft itself) will add an IsReady() method to the Customer table in the future? For solving this problem, the new code action for resolving the implicit with will add also a pragma declaration for the compiler (#pragma implicitwith disable):

In this way the compiler will not resolve the IsReady() method by going to the previously explained chain and it will always found the local declaration.

The usage of implicit WITH must be fixed also on pages, where you have a field reference. All fields on a page must be fixed with Rec.YourField:

and you will have code actions for fixing this quickly:

You can also disable the Microsoft warnings related to the explicit (AL0606) or implicit (AL0604) WITH usage by using the following directive in your code (.al file):

#pragma warning disable AL0604,AL0606

And you can also disable these warnings globally by adding this declaration in your app.json file:

“suppressWarnings”: [ “AL0604”, “AL0606”]

but personally this is not what I would recommend you to do.

Common questions that you can have about this:

  • Will I receive a warning starting from tomorrow about WITH usage? No, this is planned for the Wave 2 2020 release (5 months later on)
  • Should I start fixing my apps now? I think the answer is yes, start avoiding the WITH usage from today and start fixing the implicit with from today if you can.
  • When the WITH usage will be transformed from a warning to an error? At least one year later, so Wave 2 2021 at least.

Please don’t wait too much and start fixing your apps by avoiding the WITH usage starting from today.

14 Comments

  1. I knew we should have avoided the WITH statements but we followed the advice of that drooling hobbit Gary Stone over on his blog several years ago and now we are wading through years of code to fix it up. Oh well. Lesson learned, follow this blog and don’t listen to anything Gary Stone ever says, or Rick Thorn for that matter.

    Like

  2. Thanks for the headsup Stefano, however I can’t find the quick fix (it shows no quick fixes available, on vsix from container of version 17.0.14454.0). Should I get a later version or how can I enable the quick fixes? Thanks!

    Like

      1. Hi Stefano,
        Thank you for the information.
        But I also couldn’t find the code action like you showed in your blog.

        I’ve just createred a BC Container of Version 17 from bcinsider today.

        Do I miss something?
        Thank you.

        Renee

        Like

  3. Hi Stefano,
    Thank you for the information.
    But I also couldn’t find the code action like you showed in your blog.

    I’ve just created a BC 17 Container from bcinsider today.

    Do I miss something?
    Thank you.

    Renee

    Like

      1. Stefano, thank you for the help!! 🙂
        Yes, I enable code actions setting in VS Code and it works now.

        Like

  4. Hi Stefano,

    I love the WITH as it improve readibility.
    I understand the breakchange challenge.
    But why not have the ‘.’ as an alias for the WITH record

    Example :
    With MyRec do begin
    “No.” := ‘001’;
    “Name” := ‘xxx’
    End;

    Could be replace by :
    With MyRec do begin
    .”No.” := ‘001’;
    .”Name” := ‘xxx’;
    End;

    This way preserve readability and fullfill the breakchange challenge :
    “Thats’ one small dot for Microsoft, one giant leap for developpers” isn’t it?

    Like

    1. Personally I don’t think that WITH helps on redability, I’ve always discouraged to use it. But this is a personal opinion 🙂
      Microsoft wants to remove the method and wants that you declare exactly (explicitly) the object you use.

      Like

  5. I don’t mind that Microsoft is doing this, but why is it OK for their base code (as of 21.6) to still include implicit and explicit withs? I made a report (since you can’t extend them) starting by copying their code, and get a whole bunch of compile warnings. Come on Microsoft, it’s rules for all not some!

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.