4 minute read time

AMC Tech Tips: Improving .NET COBOL application responsiveness with new syntax for .NET

by   in Application Modernization & Connectivity

Micro Focus COBOL under .NET (and JVM)

For the last twenty years Micro Focus has invested to COBOL running under .NET to match the equivalent capabilities with other languages that run in that environment (often called "managed code") such as Java, C#, and VB.NET, in terms of features and constructs.

Today Micro Focus Visual COBOL (and its mainframe-application sibling Enterprise Developer) can compile COBOL code directly to JVM bytecode and to CIL (for .NET framework and .NET core). Interacting with other JVM or .NET libraries has never been easier thanks to new managed syntax that can be used directly in COBOL programs.

In this blog I will demonstrate writing asynchronous code using the new async / await syntax for COBOL running under .NET (hereafter called .NET COBOL) which is available in the latest release of Visual COBOL and Enterprise Developer.

Synchronous

Synchronous code is where each line of a program is executed one at a time. The next line is only executed when the previous line has completed no matter how long that might be. For example if a program first needed to download a file and then read it, it would only read that file as soon as the download had completed.

Let's take a look at the following snippet of code.

method-id GetEmployeeDetails (id as binary-long)
                             returning employee as type EmployeeDetails.
    declare account = GetUserAccount()
    set employee to QueryEmployee(id)
    if not account::HasAccessRights(employee)
        raise new AccessDeniedException()
    end-if
end method.

method-id btnGetEmployee_Click (sender as object, e as type EventArgs).
    try
        declare employee = await GetEmployeeDetails(binary-long::Parse(txtId::Text))
        invoke ShowEmployeeDetails(employee)
    catch ex as type Exception
        set lblStatus::Text to ex::Message
    end-try
end method.

Notice how GetEmployeeDetails must first fetch the user account and then after that has completed, query the employee. Both could take several seconds to complete particularly if they require downloading data over a network, but couldn't we save time by running them both simultaneously? Not only that, the user interface (UI) becomes unresponsive as all this code is being executed on the UI thread, this means the user has no way of cancelling the operation and no status is displayed to show what the application is actually doing.

Asynchronous

Asynchronous code is where a program will continue execution even before a particular operation has finished. When that operation does finish, specific code will be executed. This can be achieved by using event handlers or perhaps a loop that checks to see if the operation has finished, if it has, execute the handler code, if not then refresh the screen or handle user input. With the new async / await syntax programs can not only be asynchronous, but can be written just like it would be if it was synchronous. This makes the code much easier to follow depsite being more complicated behind the scenes.

Let's take a look at an asynchronous implementation of the example above.

method-id GetEmployeeDetailsAsync (id as binary-long)
                                  yielding employee as type EmployeeDetails async.
    declare account as type UserAccount
    invoke await type Task::WhenAll(
        delegate
            set account to GetUserAccount()
        end-delegate,
        delegate
            set employee to QueryEmployee(id)
        end-delegate)
    if not account::HasAccessRights(employee)
        raise new AccessDeniedException()
    end-if
end method.

method-id btnGetEmployee_Click (sender as object, e as type EventArgs) async-void.
    set lblStatus::Text to "Fetching employee"
    set btnGetEmployee::Enabled to false
    try
        declare employee = await GetEmployeeDetailsAsync(binary-long::Parse(txtId::Text))
        invoke ShowEmployeeDetails(employee)
    catch ex as type Exception
        set lblStatus::Text to ex::Message
    finally
        set lblStatus::Text to ""
        set btnGetEmployee::Enabled to true
    end-try
end method.

The Task Parallel Library (TPL) is an API from the .NET framework which can be used to write asynchronous code. In the snippet above, TPL calls are generated by the COBOL compiler when invoking GetEmployeeDetailsAsync. This is achieved by awaiting GetEmployeeDetailsAsync from an async-void method. When the await is hit, GetEmployeeDetailsAsync is executed up until the first await call within that method. At that point, GetUserAccount and QueryEmployee are run simultaneously on separate threads using one of the TPL utility methods: Task::WhenAll, while the UI thread returns back to the application loop. When both the employee details and the user account have been fetched, the execution of GetEmployeeDetailsAsync continues (by default on the UI thread).

In order to achieve this behaviour in previous versions of Visual COBOL, a callback (delegate) would be required, but thanks to the new async syntax the method can still be written like a synchronous method, yet behind the scenes it is compiled to be asynchronous. This is known as a coroutine, another example being iterator methods.

The Task asynchronous programming model in C# Microsoft documentation covers .NET asynchronous programming in more depth.

Afterword

The new async / await syntax now makes it easy to create asynchronous APIs for COBOL applications or C# applications to consume thus saving time and computation power. If an application is running in the cloud this can also mean saving money in CPU time or increasing the web traffic throughput.

It further illustrates Micro Focus' ongoing commitment to enhancing the COBOL language. Note that this is currently only available in our latest release of Visual COBOL for .NET technology.

Visual COBOL is available as a 30-day free trial, visit our product page for more information.

Labels:

Visual COBOL
Mainframe
COBOL