Skip to main content

Notifications

Just.One.Line.Of.Code

dkatson Profile Picture dkatson 2,261

In the upcoming version of Business Central there is one interesting feature for AL developers - Returning complex types

At last, on the customers question "How difficult is that?" you can answer "It's just one line of code"

At the same time when customer will ask "Hey, why so expensive? You told it's just one line of code!" - you can argue "Yes, but it's very difficult line of code

Where does it come from?

I don't know. But I know that in Python language this is used a lot. 

One of the examples you can find in my older blog How to get Insights from your Business Central App Data, using Python Azure Functions

#Get Top 10 Best-Selling Days
top_days = sales.groupby(['date'])['amount'].sum.nlargest(10)
]

AL Example

How about the next scenario?

Let say you want to purchase apartment but you don't know which exactly. You just know the size and the preferred number of bedrooms. If the apartment you found is big enough, the owner agrees to give a discount. After you sign the contract. 

Can all this be implemented in one line of code?

How about this? 

procedure PurchaseAppartment(PurchaseHeader: Record "Purchase Header")
begin
 SetSize(100).SetNoOfBedrooms(2).FindAppartment().CreatePurchaseLine(PurchaseHeader).ApplyDiscountPercent(10).PrepareForPosting().SendToPosting(CODEUNIT::"Purch.-Post");
end;

Oh yes, that's now possible. Let's look at the detailed implementation.

Return the codeunit

We will use the codeunit as a way to store temporary variables - the preferred Size and Number of bedrooms. 

Start with creating the codeunit with a global variables, where we will save our external values. I will use my own Apartment table. 

4061.pastedimage1615795127682v2.png

In a previous versions we would do just...

5482.pastedimage1615798030680v3.png

However if we will try to call SetSize() and set a '.' at the end, we will not see anything.

6735.pastedimage1615798202631v4.png

Now, let's try to return the same codeunit

2816.pastedimage1615798432427v5.png

In this case we will see another picture, by setting the '.' at the end of SetSize()

7888.pastedimage1615798524174v6.png

however if we will try to show saved variable in a second call...

5710.pastedimage1615799470929v7.png

... we will see

4861.pastedimage1615799647945v8.png

The reason is that by returning the codeunit, even the same one as we are calling from, we return another instance of the codeunit. And another instance doesn't "know" anything about previous calls. To solve this we need to turn the codeunit into SingleInstance mode.

0576.pastedimage1615799824453v9.png

In this case we will see

8117.pastedimage1615799878303v10.png

Great, now moving forward. 

Return the Record

0451.pastedimage1615799994417v11.png

Take a look at the FindAppartment() function. When we found the apartment that full-fill our conditions, we return the found record.

What do you think will happen when we put a '.' at the end of FindAppartment() when we call it?

2526.pastedimage1615800267945v12.png

Think you guessed. Right, we will have access to all record fields, methods etc. 

Just by adding the procedure to the Appartment table, and we can extend our one-line-of-code as follow

6507.pastedimage1615800710118v14.png

0486.pastedimage1615800649279v13.png

Btw, if you was too attentive you noticed that 

    procedure FindAppartment(): Record Appartment
    begin
        exit(Appartment.Find());
    end;

will not work. The reason is that standard "Find" returns Boolean, and we need a Record.

1106.pastedimage1615801042567v15.png

In my situation I made an overload to the standard Find function, not with different input variables signature, but with different output signature. Take a look

6712.pastedimage1615801152693v17.png

The reason I used an Apartment variable as the return value is a bug (I guess) in the new functionality. When you try to do something like this

8422.pastedimage1615801430547v18.png

3858.pastedimage1615801488816v19.png

you will get

8306.pastedimage1615801531725v20.png

However if you slightly change this into 

8105.pastedimage1615801591742v21.png

you will get

0458.pastedimage1615801636756v22.png

This is the size of first apartment in the list. 

Nice. We are almost done. We ended with the creation of the Purchase Line. By adding two functions to the Purchase Line table extension we will set the discount and prepare the purchase header for posting.

6242.pastedimage1615802897781v23.png

You see that at the ApplyDiscountPercent() function I apply the same technique as previously, due to the return record bug. 

Now we can call finalise our one-line-code function

3681.pastedimage1615803272167v25.png

And the prove that this works

1663.JBfIn6nqHu.gif

The source code is available here https://github.com/dkatson/Blog.Just.One.Line.Of.Code

Comments

*This post is locked for comments

  • Kishor Mistry Profile Picture Kishor Mistry
    Posted at
    Now if Microsoft had given us a "self" variable within codeunits to return the current instance of the codeunit then the above could be achieved without having to use a single instance codeunit - you would simply call exit(self); at the end of each function. It would also allow for multiple concurrent codeunits (which is not possible when you have a single instance codeunit) Nice post BTW
  • Manjusree S Profile Picture Manjusree S 10
    Posted at
    Nice post!!!. I have US Business Central 18.0 (Platform 18.0.22913.0 + Application 18.0.22967.0) online sandbox installed in docker. But I am unable to test any of the new features like complex return types or report extension. Any idea what am I missing?. Thank you in advance