Skip to content

X++ Syntactic Sugar – Method Chaining and Fluent Interfaces

As you work with D365 F&O and X++, you will likely pick up some design patterns and techniques from the standard application. One of the recently added features to D365 F&O has been the SysDa framework. When you work with SysDa, you will likely notice how the query blocks are structured in a way that makes them look like natural written language (Also known as a fluid interface).

In this post, we will examine method chaining, a part of the design pattern used by the SysDa framework.

What is Method Chaining and Fluent Interfaces?

Method chaining is a pattern in which multiple methods are called on the same object sequentially. Each method returns itself, allowing the developer to chain additional methods directly onto the previous call, which can lead to more readable code.


Let’s look at the following piece of code:

internal final class FTBXExchangeRateProviderCBODK implements IExchangeRateProvider
{
    ******

    private void addExchangeRatesStatbank(
        ExchangeRateResponse    _response,
        str                     _apiEndpoint,
        str                     _exchangeRateType,
        FromDate                _fromDate,
        ToDate                  _toDate)
    {    
        var httpRequestMessage  = new HttpRequestMessage(new HttpMethod('post'), _apiEndpoint);

        ******

        var statBankRequest = new FTBXExchangeRateProviderCBODKStatbankRequestContract();
        statbankRequest.parmLang(statBankLanguage);
        statbankRequest.parmTable(statBankTable);
        statbankRequest.parmFormat(statBankFormat);
        statbankRequest.parmTimeOrder(statBankOrder);

        var currencyVariable = new FTBXExchangeRateProviderCBODKStatbankVariableContract();
        
        currencyVariable.parmCode(statBankVariableCurrency);
        currencyVariable.parmValues().addEnd('*');
        statbankRequest.parmVariables().addEnd(currencyVariable);

        var exchangeRateTypeVariable = new FTBXExchangeRateProviderCBODKStatbankVariableContract();
        exchangeRateTypeVariable.parmCode(statBankVariableType);
        exchangeRateTypeVariable.parmValues().addEnd(_exchangeRateType);
        statbankRequest.parmVariables().addEnd(exchangeRateTypeVariable);

        var exchangeRateDatesVariable = new FTBXExchangeRateProviderCBODKStatbankVariableContract();
        exchangeRateDatesVariable.parmCode(statBankVariableTime);

        ******

        httpRequestMessage.Content = new StringContent(
            FormJsonSerializer::serializeClass(statbankRequest),
            System.Text.Encoding::UTF8, 
            'application/json');
            
        *******
    }
}

Link to original code: FTBXExchangeRateProviderCBODK

It’s just an ordinary method. However, one issue with this piece of code is that keeping track of variable names can be a bit of a burden. This is where the Method Chaining pattern can be applied.

If you take the method chaining pattern and apply it to the example code, it will look something like this:

internal final class FTBXExchangeRateProviderCBODK implements IExchangeRateProvider
{
    ******

    private void addExchangeRatesStatbank(
        ExchangeRateResponse    _response,
        str                     _apiEndpoint,
        str                     _exchangeRateType,
        FromDate                _fromDate,
        ToDate                  _toDate)
    {    
        var httpRequestMessage  = new HttpRequestMessage(new HttpMethod('post'), _apiEndpoint);

        httpRequestMessage.Content = new StringContent(
            FormJsonSerializer::serializeClass(
                new FTBXExchangeRateProviderCBODKStatbankRequestContract()
                    .setLang(statBankLanguage)
                    .setTable(statBankTable)
                    .setFormat(statBankFormat)
                    .setTimeOrder(statBankOrder)
                    .addVariable(new FTBXExchangeRateProviderCBODKStatbankVariableContract()
                        .setCode(statBankVariableCurrency)
                        .addValue('*'))
                    .addVariable(new FTBXExchangeRateProviderCBODKStatbankVariableContract()
                        .setCode(statBankVariableType)
                        .addValue(_exchangeRateType))
                    .addVariable(new FTBXExchangeRateProviderCBODKStatbankVariableContract()
                        .setCode(statBankVariableTime)
                        .addDateRange(_fromDate, _toDate))),
            System.Text.Encoding::UTF8, 
            'application/json');
            
        *******
    }
}

Link to original code: FTBXExchangeRateProviderCBODK

Why Use Method Chaining?

As the example shows, there are multiple benefits of using method chaining in your code.

  • Improved readability: By chaining parm methods together, it’s possible to reduce the number of number of lines of X++ code, making the logic easier to follow
  • Cleaner code: The pattern helps avoid intermediate variables and keeps related operations together
  • Fluent interfaces: It creates a more fluent interface, making your code look more like natural language.

Implementing Method Chaining

To implement method chaining for data contract, crate a “setter” method for each parameter you have, approximately in this format.

    [DataMemberAttribute('Lang')]
    public str parmLang(str _lang = lang)
    {
        lang = _lang;
        return lang;
    }
    
    public FTBXExchangeRateProviderCBODKStatbankRequestContract setLang(Str _lang)
    {
        lang = _lang;
        return this;
    }

Link to original code: FTBXExchangeRateProviderCBODKStatbankRequestContract

In this example, I have created a set method in addition to the parm method ‘parmLang’.

Best Practices

There are still a few best practices that I have gathered while trying to apply this pattern.

  • Keep track of the chain length: Don’t make the chains way to long, since they can make debugging difficult.
  • Clarity: Each method should have a clear and specific purpose. Don’t overcomplicate things beyond measure.
  • Error handling: Make sure to keep error handling in check. While I haven’t seen any issues using this pattern, I can imagine error handling in long chains can cause headaches.

Conclusion

Method chaining is a valuable pattern in your tool belt when you feel it’s difficult to create readable and concise code. Using this pattern will make your code look cleaner and more intuitive; it has, for me, at least.

https://en.wikipedia.org/wiki/Method_chaining
https://en.wikipedia.org/wiki/Syntactic_sugar

https://en.wikipedia.org/wiki/Fluent_interface

Leave a Reply

Your email address will not be published. Required fields are marked *