Just.One.Line.Of.Code
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.
In a previous versions we would do just...
However if we will try to call SetSize() and set a '.' at the end, we will not see anything.
Now, let's try to return the same codeunit
In this case we will see another picture, by setting the '.' at the end of SetSize()
however if we will try to show saved variable in a second call...
... we will see
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.
In this case we will see
Great, now moving forward.
Return the Record
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?
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
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.
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
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
you will get
However if you slightly change this into
you will get
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.
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
And the prove that this works
The source code is available here https://github.com/dkatson/Blog.Just.One.Line.Of.Code
Comments
-
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
-
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
*This post is locked for comments