<?xml version="1.0" encoding="UTF-8"?>        <rss version="2.0"
             xmlns:atom="http://www.w3.org/2005/Atom"
             xmlns:dc="http://purl.org/dc/elements/1.1/"
             xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
             xmlns:admin="http://webns.net/mvcb/"
             xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
             xmlns:content="http://purl.org/rss/1.0/modules/content/">
        <channel>
            <title>
									Knowledge Base - twinControls Forum				            </title>
            <link>https://twincontrols.com/community/twincat-knowledgebase/</link>
            <description>twinControls  Discussion Board</description>
            <language>en-US</language>
            <lastBuildDate>Wed, 22 Apr 2026 23:34:32 +0000</lastBuildDate>
            <generator>wpForo</generator>
            <ttl>60</ttl>
							                    <item>
                        <title>Advanced Interfaces: Functional Interfaces - Part 2 (Context &amp; Capturing)</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/advanced-interfaces-functional-interfaces-part-2-context-capturing/</link>
                        <pubDate>Wed, 31 Dec 2025 07:02:09 +0000</pubDate>
                        <description><![CDATA[In Part 1, we explored the concept of functional interfaces, where we used an interface with a single abstract method to pass logic around like a variable. We looked at a pure Aggregate  fun...]]></description>
                        <content:encoded><![CDATA[<p>In <a href="https://twincontrols.com/community/postid/2304/" target="_blank" rel="noopener">Part 1</a>, we explored the concept of <strong>functional interfaces</strong>, where we used an interface with a single abstract method to pass logic around like a variable. We looked at a pure <strong><em><span style="color: #000000">Aggregate</span></em></strong>  function that summed or multiplied values, or returned the largest value in an array.</p>
<p>Those examples were "stateless", meaning that the operations depended only on the arguments passed to them (<strong><em><span style="color: #000000">a</span></em></strong> and <strong><em><span style="color: #000000">b</span></em></strong> in <strong><em><span style="color: #000000">(a, b) =&gt; &lt;expression&gt;</span></em></strong>). In the real world, however, logic rarely exists in a vacuum. Functions often need <strong>context</strong>: thresholds, configuration values, or system parameters that aren't part of the function arguments themselves.</p>
<div>
<div><span>In modern languages like C#, Java, Python, and C++, this is solved through a concept called </span><span><strong>closures</strong></span><span> or </span><span><strong>lambda capturing</strong></span><span>. This is when a function "captures" variables from its surrounding scope so it can use them later, even after the original scope has ended.</span></div>
</div>
<div> </div>
<div>
<div>
<div><span>Here's an example in C++ that demonstrates capturing:</span></div>
<div>
<pre contenteditable="false">#include &lt;iostream&gt;

int main() 
{
    int scale = 10;
    
    // Capture by value (copy)
    auto scaleByValue = (int a, int b) { return (a + b) * scale; };

    // Capture by reference (observes changes)
    auto scaleByRef = (int a, int b) { return (a + b) * scale; };

    scale = 20;

    std::cout &lt;&lt; scaleByValue(1, 2) &lt;&lt; std::endl; // 30 (uses original scale = 10)
    std::cout &lt;&lt; scaleByRef(1, 2) &lt;&lt; std::endl;   // 60 (uses updated scale = 20)

    return 0;
}</pre>
</div>
</div>
</div>
<div>
<div>
<div><span>In this example:</span></div>
<div><span>- </span><span><strong><em><span style="color: #000000">scaleByValue</span></em></strong></span><span> captures </span><span><strong><em><span style="color: #000000">scale </span></em></strong></span><span><strong>by value</strong></span><span>, storing a copy of </span><span><strong><em><span style="color: #000000">10</span></em></strong></span><span> that won't change even when the original variable is modified.</span></div>
<div><span>- </span><span><strong><em><span style="color: #000000">scaleByRef</span></em></strong></span><span> captures </span><span><strong><em><span style="color: #000000">scale </span></em></strong></span><span><strong>by reference</strong></span><span>, observing changes to the original variable.</span></div>
<br />
<div><span>This flexibility allows functions to carry context with them, making them far more powerful and adaptable.</span></div>
<div> </div>
</div>
</div>
<div>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">The Challenge in Structured Text</span></h2>
</div>
<div>
<div>
<div> </div>
<div><span>Unfortunately, as discussed in <a href="https://twincontrols.com/community/postid/2304/" target="_blank" rel="noopener">Part 1</a></span><span>, ST doesn't support closures or lambda capturing. We can't create inline functions that automatically capture surrounding variables. However, we can achieve similar functionality using two approaches:</span></div>
</div>
</div>
<ol>
<li><strong>Function blocks with state</strong> - storing context as member variables</li>
<li>
<div><span><strong>Fluent interfaces</strong></span><span> - chainable methods that configure and return the function block</span></div>
</li>
</ol>
<p>The fluent interface approach is particularly elegant, as it allows us to configure operations inline, similar to how we'd use closures in modern languages.</p>
<p>&nbsp;</p>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">Approach 1: Direct Configuration</span></h2>
<p>&nbsp;</p>
<div>
<div><span>Let's start with the straight-forward approach of configuring function blocks before use:</span></div>
</div>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this function block directly is not allowed'}
FUNCTION_BLOCK FB_SumIfInRangeFunction IMPLEMENTS I_BiFunction
    VAR_INPUT
        nLowerThreshold,
        nUpperThreshold : INT;
    END_VAR

    METHOD Apply : INT
        VAR_INPUT
            nA, nB : INT;
        END_VAR

        // Only add nB if it's within the range
        IF nB &gt;= nLowerThreshold AND nB &lt;= nUpperThreshold THEN
            Apply := nA + nB;
        ELSE
            Apply := nA;
        END_IF
    END_METHOD
END_FUNCTION_BLOCK</pre>
<p>&nbsp;</p>
<h4 id="example-usage" class="code-line" dir="auto" data-line="166"><span style="font-size: 14pt">Example Usage</span></h4>
<p>&nbsp;</p>
<pre contenteditable="false">PROGRAM P_Example2_Direct
VAR
    arNumbers       : ARRAY OF INT := ;
    fbSum           : FB_SumIfInRangeFunction;
    nFilteredSum    : INT;
END_VAR

// Configure the thresholds
fbSum.nLowerThreshold := 10;
fbSum.nUpperThreshold := 20;

// Apply operation
nFilteredSum := P_Operations.Aggregate(arNumbers, fbSum);
// Result: 15 + 12 + 19 = 46 (8 and 23 are excluded)</pre>
<p>&nbsp;</p>
<div>
<div><span>This works, but it's limiting and requires separate configuration steps. We can do better.</span></div>
</div>
<p>&nbsp;</p>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">Approach 2: Fluent Interface (Method Chaining)</span></h2>
<p>&nbsp;</p>
<p>A <strong>fluent interface</strong> allows us to chain method calls together, configuring the function block inline. The key is that configuration methods return a reference to the function block itself (<span><strong><em><span style="color: #000000">THIS^</span></em></strong></span>), enabling multiple calls to be chained together.</p>
<div><br />
<div><span>By defining separate interfaces for different configuration capabilities, we can create a flexible and type-safe fluent API that guides developers toward correct usage.</span></div>
<div> </div>
<div>First, let's define interfaces that represent different configuration capabilities:</div>
</div>
<pre contenteditable="false">INTERFACE I_GreaterThanCondition
    METHOD AnyGreaterThan : I_BiFunction
        VAR_INPUT
            nThreshold : INT;
        END_VAR
    END_METHOD
END_INTERFACE</pre>
<pre contenteditable="false">INTERFACE I_LessThanCondition
    METHOD AnyLessThan : I_BiFunction
        VAR_INPUT
            nThreshold : INT;
        END_VAR
    END_METHOD
END_INTERFACE</pre>
<pre contenteditable="false">INTERFACE I_InRangeCondition
    METHOD AnyInBetween : I_BiFunction
        VAR_INPUT
            nLowerThreshold, nUpperThreshold : INT;
        END_VAR
    END_METHOD
END_INTERFACE</pre>
<div>
<div><span>Now we can implement a function block that supports multiple configuration interfaces: </span></div>
</div>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this function block directly is not allowed'}
FUNCTION_BLOCK FB_SumFunction 
IMPLEMENTS I_BiFunction, I_GreaterThanCondition, I_LessThanCondition, I_InRangeCondition
    VAR_STAT CONSTANT
        _nMIN_INT : INT := -32768;
        _nMAX_INT : INT := 32767;
    END_VAR
    VAR
        _nLowerThreshold : INT := _nMIN_INT;
        _nUpperThreshold : INT := _nMAX_INT;;
    END_VAR
    
    // Sets the minimum threshold (inclusive)
    // Values must be GREATER THAN OR EQUAL to this threshold
    METHOD AnyGreaterThan : I_BiFunction
        VAR_INPUT
            nThreshold : INT;
        END_VAR
        AnyGreaterThan   := THIS^;

        _nLowerThreshold := nThreshold;
        _nUpperThreshold := _nMAX_INT;
    END_METHOD

    // Sets the maximum threshold (inclusive)
    // Values must be LESS THAN OR EQUAL to this threshold
    METHOD AnyLessThan : I_BiFunction
        VAR_INPUT
            nThreshold : INT;
        END_VAR
        AnyLessThan      := THIS^;

        _nLowerThreshold := _nMIN_INT;
        _nUpperThreshold := nThreshold;
    END_METHOD

    // Sets the lower and upper threshold (inclusive)
    // Values must be BETWEEN these thresholds
    METHOD AnyInBetween : I_BiFunction
        VAR_INPUT
            nLowerThreshold, nUpperThreshold : INT;
        END_VAR
        AnyInBetween     := THIS^;

        _nLowerThreshold := nLowerThreshold;
        _nUpperThreshold := nUpperThreshold;
    END_METHOD

    // Resets the configuration so that all values are allowed
    METHOD Everything : I_BiFunction
        VAR_INPUT
        END_VAR
        Everything := THIS^;

        _nLowerThreshold := _nMIN_INT;
        _nUpperThreshold := _nMAX_INT;
    END_METHOD

    METHOD Apply : INT
        VAR_INPUT
            nA, nB : INT;
        END_VAR
        // Only add nB if it's within the configured range
        IF nB &gt;= _nLowerThreshold AND nB &lt;= _nUpperThreshold THEN 
            Apply := nA + nB;
        ELSE
            Apply := nA;
        END_IF
    END_METHOD
END_FUNCTION_BLOCK</pre>
<p>&nbsp;</p>
<h4 id="example-usage" class="code-line" dir="auto" data-line="166"><span style="font-size: 14pt">Example Usage</span></h4>
<p>&nbsp;</p>
<div>
<div><span>Now we can configure and use operations in clean, readable expressions:</span></div>
<div>
<pre contenteditable="false">ROGRAM P_Example2_Fluent
VAR
    arNumbers        : ARRAY OF INT := ;
    fbSum            : FB_SumFunction;
    nFilteredSum1,
    nFilteredSum2,
    nFilteredSum3    : INT;
END_VAR

// Configure and apply operations inline
nFilteredSum1 := P_Operations.Aggregate(arNumbers, fbSum.AnyLessThan(20));
// Result: 15 + 8 + 12 + 19 = 54 (23 is excluded)

nFilteredSum2 := P_Operations.Aggregate(arNumbers, fbSum.AnyGreaterThan(10));
// Result: 15 + 23 + 12 + 19 = 69 (8 is excluded)

nFilteredSum3 := P_Operations.Aggregate(arNumbers, fbSum.AnyInBetween(10, 20));
// Result: 15 + 12 + 19 = 46 (8 and 23 are excluded)

nSum          := P_Operations.Aggregate(arNumbers, fbSum.Everything());
// Result: 15 + 8 + 23 + 12 + 19 = 77 (all values are included)</pre>
</div>
</div>
<p>&nbsp;</p>
948
<p>&nbsp;</p>
<h4 id="example-usage" class="code-line" dir="auto" data-line="166"><span style="font-size: 14pt">Benefits of the Fluent Approach</span></h4>
<p>&nbsp;</p>
<div>
<div>
<div>
<div><span>The fluent interface pattern provides several advantages:</span></div>
<br />
<ol>
<li><span><strong>Readability</strong></span><span>: Configuration reads like natural language</span></li>
<li><span><strong>Type Safety</strong></span><span>: Each interface clearly defines what operations are available</span></li>
<li><span><strong>Inline Configuration</strong></span><span>: No need for separate setup steps</span></li>
<li><span><strong>Discoverability</strong></span><span>: Separate interfaces guide developers through available options</span></li>
<li><span><strong>Immutability Simulation</strong></span><span>: Each call appears to create a configured version without mutating the original (though technically it does modify the instance)</span></li>
<li><span><strong>Composability</strong></span><span>: Easy to build complex behaviors from simple building blocks</span></li>
</ol>
</div>
</div>
</div>
<div> </div>
<div>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">Real World Applications</span></h2>
</div>
<div>
<div>
<div> </div>
</div>
</div>
<div>
<div><span>Context-aware operations with fluent interfaces are invaluable across many automation scenarios:</span></div>
</div>
<p><strong>Data Transformation &amp; Mapping</strong></p>
<pre contenteditable="false">// Transform raw ADC values to engineering units with calibration offset
fCalibratedTemps := P_DataTransform.Map(
    nRawSensorData,
    fbADCToTemp.WithOffset(nZeroOffset).WithGain(fCalibrationGain)
);</pre>
<p><strong>Filtering &amp; Selection</strong></p>
<pre contenteditable="false">// Select production batches exceeding quality threshold
nCount := P_DataFilter.Filter(
    arAllBatches,
    fbQualityCheck
        .AnyGreaterThan(nPremiumThreshold)
        .WithMargin(fSafetyMargin),
    arPremiumBatches
);

// Find active alarms above critical severity
nCount := P_DataFilter.Filter(
    arAlarmList,
    fbAlarmFilter
        .AnyGreaterThan(E_Severity.High)
        .IsActive()
        .NotAcknowledged(),
    arCriticalAlarms
);</pre>
<p><strong>Validation &amp; Predicates</strong></p>
<pre contenteditable="false">// Verify all safety sensors are within safe range
bSystemSafe := P_SafetyCheck.Every(
    arSafetySensors,
    fbSafetyValidator
        .AnyInBetween(nSafeMin, nSafeMax)
        .WithHysteresis(nHysteresisBand)
);</pre>
<p><strong>Sorting &amp; Ranking</strong></p>
<pre contenteditable="false">// Sort machines by efficiency, excluding standby units
P_EquipmentSort.Sort(
    arMachines,
    fbEfficiencyCompare.AnyGreaterThan(nMinEfficiency).ByDescending()
);

// Rank production runs by yield within quality band
P_BatchSort.Sort(
    arProductionRuns,
    fbYieldCompare.AnyInBetween(nMinQuality, nMaxQuality).ByYield()
);</pre>
<p><strong>Search &amp; Analysis</strong></p>
<pre contenteditable="false">// Find first sensor reading exceeding alarm threshold
ipFirstAlarm := P_DataSearch.Find(
    arSensorReadings,
    fbThresholdCheck.AnyGreaterThan(nAlarmThreshold).Confirmed(T#2s)
);

// Identify optimal batch by cost-to-quality ratio
ipBestBatch := P_BatchAnalysis.FindOptimal(
    arBatches,
    fbCostAnalysis.AnyGreaterThan(nMinYield).WithQualityWeight(0.6)
);</pre>
<p><strong>Statistical Aggregation</strong></p>
<pre contenteditable="false">// Calculate weighted average excluding statistical outliers
fWeightedAvg := P_Statistics.Aggregate(
    arMeasurements,
    fbWeightedAvg
        .AnyInBetween(fMean - 3*fStdDev, fMean + 3*fStdDev)
        .WithWeights(arWeights)
);

// Compute RMS vibration in bearing frequency range
fBearingVibration := P_VibrationAnalysis.Aggregate(
    arFFTData,
    fbRMS
        .AnyInBetween(fBearingFreqLow, fBearingFreqHigh)
        .WithHanningWindow()
);</pre>
<div>
<div><span>The key advantage across all these scenarios is that </span><span><strong>different functional interfaces</strong></span><span> (</span><span><strong><em><span style="color: #000000">Map</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Filter</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Every</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Some</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">None</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Sort</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Find</span></em></strong></span><span>, </span><span><strong><em><span style="color: #000000">Aggregate</span></em></strong></span><span>) provide the appropriate abstraction for each use case, while fluent configuration makes the code expressive and maintainable.</span></div>
</div>
<div> </div>
<div>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">Conclusion</span></h2>
</div>
<div>
<div>
<div> </div>
</div>
</div>
<div>
<div><span>While Structured Text doesn't support closures or lambda capturing, we can achieve remarkably similar functionality using function blocks with fluent interfaces. By:</span></div>
<br />
<ol>
<li><span><strong>Storing context as member variables</strong></span><span> within function blocks</span></li>
<li><span><strong>Exposing configuration through dedicated interfaces</strong></span><span> for type safety and discoverability</span></li>
<li><span><strong>Returning references to the functional interface</strong></span><span> (</span><span><strong><em><span style="color: #000000">THIS^</span></em></strong></span><span>) to enable inline configuration</span></li>
</ol>
<br />
<div><span>We create expressive, readable code that rivals modern functional programming languages. The fluent interface pattern provides:</span></div>
<br />
<ul>
<li><span><strong>Inline configuration</strong></span><span> that mimics closure capturing</span></li>
<li><span><strong>Type-safe composition</strong></span><span> through interface segregation</span></li>
<li><span><strong>Natural, readable syntax</strong></span><span> that expresses intent clearly</span></li>
<li><span><strong>Flexible, reusable components</strong></span><span> that adapt to different contexts</span></li>
</ul>
<br />
<div><span>This approach bridges the gap between traditional PLC programming and modern functional paradigms, bringing greater modularity, maintainability, and expressiveness to industrial automation code without sacrificing the determinism and reliability that automation systems demand.</span></div>
<br />
<div><span>In Part 3, we'll explore how to extend this pattern further with </span><span><strong>function composition</strong></span><span> and </span><span><strong>higher-order functions</strong></span><span>, building even more powerful abstractions that allow us to combine simple operations into complex processing pipelines.</span></div>
</div>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>FisoThemes</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/advanced-interfaces-functional-interfaces-part-2-context-capturing/</guid>
                    </item>
				                    <item>
                        <title>Advanced Interfaces: Functional Interfaces - Part 1</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/advanced-interfaces-functional-interfaces-part-1/</link>
                        <pubDate>Wed, 24 Dec 2025 03:53:36 +0000</pubDate>
                        <description><![CDATA[Lately, I’ve been thinking a lot about how to abstract complexity and improving the flexibility of code in industrial automation systems. With systems growing in size and complexity, it&#039;s im...]]></description>
                        <content:encoded><![CDATA[<p class="code-line" dir="auto" data-line="2">Lately, I’ve been thinking a lot about how to abstract complexity and improving the flexibility of code in industrial automation systems. With systems growing in size and complexity, it's important to find a balance between control and modularity. I’ve been exploring different approaches to achieve this, and I decided to start by talking about<span> </span><strong>functional interfaces</strong><span> </span>- a powerful tool that can help you break down large systems into smaller, reusable components.</p>
<p class="code-line" dir="auto" data-line="4">Many modern programming languages, like Rust, Java, Python, or C#, have what is known as<span> </span><strong>first-class functions</strong>. These are functions that can be passed around just like variables, meaning they can be assigned to variables, passed as arguments to other functions, or even returned as values from functions. This flexibility allows for more dynamic and reusable code. This is the fundamental concept behind<span> </span><strong>lambdas</strong>,<span> </span><strong>closures</strong>, and<span> </span><strong>anonymous functions</strong>, which are compact ways to define behaviour on the fly without needing to declare a full function or method. By embedding logic directly where it’s needed, they allow developers to write cleaner, more concise, and more modular code.</p>
<p class="code-line code-active-line" dir="auto" data-line="6">Here’s an example of an anonymous function in C# that reduces a list of numbers:</p>
<pre contenteditable="false">using System;
using System.Linq;

int[] numbers = {2, 1, 3, 5, 4};

// Using an anonymous function to sum the array
int sum = numbers.Aggregate((a, b) =&gt; a + b);

// Using an anonymous function to get the product of the array
int product = numbers.Aggregate((a, b) =&gt; a * b);

// Output: 15
Console.WriteLine(sum);

// Output: 120
Console.WriteLine(product);</pre>
<p dir="auto" data-line="6"> </p>
<p class="code-line" dir="auto" data-line="26">In this example, the <strong><em><span style="color: #000000">Aggregate</span></em></strong> method uses a lambda expression to define how two numbers should be combined, either summing (<strong><em><span style="color: #000000">(a, b) =&gt; a + b</span></em></strong>) or multiplying (<strong><em><span style="color: #000000">(a, b) =&gt; a * b</span></em></strong>) the values. The power here is that the <strong><em><span style="color: #000000">Aggregate</span></em></strong> <strong>method itself is decoupled from the specific operation</strong>. It doesn’t care whether you’re summing or multiplying numbers. This makes the logic highly reusable and flexible, allowing the function to process data in different ways based on the behaviour you pass in.</p>
<p class="code-line" dir="auto" data-line="28">Unfortunately, Structured Text (ST) doesn’t have first-class functions (<a href="https://stackoverflow.com/questions/43139073/how-to-create-pointer-to-function-in-codesys-v3" data-href="https://stackoverflow.com/questions/43139073/how-to-create-pointer-to-function-in-codesys-v3">sort of...</a>), but we can still introduce some of these principles through functional interfaces. Although ST doesn’t support lambdas, closures, or anonymous functions, functional interfaces can give us a way to mimic some of this functionality.</p>
<h2 class="code-line" dir="auto" data-line="30"><span style="font-size: 18pt">What is a Functional Interface?</span></h2>
<p class="code-line" dir="auto" data-line="32">A functional interface is an interface that contains exactly<span> </span><strong>one</strong><span> </span>abstract method. This single-method contract allows for a concise and focused interaction between components, making it ideal for situations where you need to define a single behaviour or action. While functional interfaces can have other members like default methods or constants (these aren't supported in ST), they are designed around the core idea of<span> </span><strong>one abstract method</strong>, ensuring they remain lightweight and purpose-driven.</p>
<p class="code-line" dir="auto" data-line="34">Here's an example of a functional interface in Java:</p>
<pre contenteditable="false">@FunctionalInterface
public interface BiFunction&lt;T, U, R&gt; {
     R apply(T t, U u); 
}</pre>
<p class="code-line" dir="auto" data-line="34"> </p>
<p class="code-line" dir="auto" data-line="42">This<span> <strong><em><span style="color: #000000">BiFunction</span></em></strong><b><i> </i></b></span>interface represents a function that accepts two arguments (<span><strong><em><span style="color: #000000">T</span></em></strong><b><i> </i></b></span><b><i> </i></b>and<span> <b><i><strong><em><span style="color: #000000">U</span></em></strong> </i></b></span>) and returns a result (<b><i><span><strong><em><span style="color: #000000">R</span></em></strong></span></i></b>). The <strong><em><span style="color: #000000">Apply</span></em></strong><span><b><i> </i></b></span>method is the single abstract method that makes this a functional interface.</p>
<p class="code-line" dir="auto" data-line="44">Here's an example of using this interface:</p>
<pre contenteditable="false">import java.util.function.BiFunction;

public class Main
{
    public static void main(String[] args) {
        // Define a BiFunction that adds two integers
        BiFunction&lt;Integer, Integer, Integer&gt; foo = (a, b) -&gt; a + b;

        // Invoke the BiFunction to add two integers
        Integer result = foo.apply(2, 3);

        // Output: 5
        System.out.println(result);
    }
}</pre>
<p class="code-line" dir="auto" data-line="34"><br /><span>In this example, we create a <strong><em><span style="color: #000000">BiFunction</span></em></strong><b><i> </i></b>to add two integers. The lambda expression <strong><em><span style="color: #000000">(a, b) =&gt; a + b </span></em></strong></span><span>defines the behaviour, and the <b><i>apply </i></b></span><span>method calls the function with the specified arguments.<br /></span></p>
<h2 id="application-in-industrial-automation" class="code-line" dir="auto" data-line="65"><span style="font-size: 18pt">Application in Industrial Automation</span></h2>
<p class="code-line" dir="auto" data-line="67">In<span> </span><strong>automation systems</strong>, functional interfaces can be used to define well-scoped behaviours that can be applied across different components or modules. By encapsulating specific functionality within a clear, single-purpose interface, functional interfaces help make systems easier to maintain, extend, and understand. This modularity also enables greater flexibility when it comes to introducing new behaviours or modifying existing ones without affecting the overall system.</p>
<p class="code-line" dir="auto" data-line="69">In this section, I’ll walk you through a simple example that demonstrate the use of functional interfaces in Codesys/TwinCAT's implementation of the IEC 61131-3 Structured Text language. I’ll be replicating the aggregate function discussed earlier <span>to perform operations like summing and finding the maximum in an array of numbers.</span></p>
<h4 dir="auto" data-line="75"> </h4>
<h4 id="step-1-define-the-functional-interface" class="code-line" dir="auto" data-line="75"><span style="font-size: 14pt">Define the Functional Interface</span></h4>
<h4 dir="auto" data-line="75"> </h4>
<p class="code-line" dir="auto" data-line="34"><span>First, let's define the <strong><em><span style="color: #000000">I_BiFunction</span></em></strong><b><i> </i></b>interface that will serve as a blueprint for any function that performs an operation on two integers and returns an integer result:<br /></span></p>
<pre contenteditable="false">INTERFACE I_BiFunction
    METHOD Apply : INT 
    VAR_INPUT 
        nA, nB : INT;
    END_VAR 
END_INTERFACE</pre>
<p class="code-line" dir="auto" data-line="34"><span>This interface contains a single method, <strong><em><span style="color: #000000">Apply</span></em></strong><b><i> </i></b>, which takes two integers as inputs (<strong><em><span style="color: #000000">nA</span></em></strong><b><i> </i></b><b><i>, <strong><em><span style="color: #000000">nB</span></em></strong> </i></b>) and returns an integer result.</span></p>
<h4 dir="auto" data-line="75"> </h4>
<h4 class="code-line" dir="auto" data-line="75"><span style="font-size: 14pt">Implement a Method that Utilises the Functional Interface</span></h4>
<h4 dir="auto" data-line="75"> </h4>
<p class="code-line" dir="auto" data-line="34"><span>Next, we’ll create the <strong><em><span style="color: #000000">P_Operations</span></em></strong><b><i> </i></b> program that contains a method called <strong><em><span style="color: #000000">Aggregate</span></em></strong>. This method will iterate over an array of integers and apply the operation defined by the <strong><em><span style="color: #000000">I_BiFunction</span></em></strong><b><i> </i></b>interface to aggregate the values in the supplied array.<br /></span></p>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this program directly is not allowed'}
PROGRAM P_Operations
    METHOD Aggregate : INT
    VAR_IN_OUT CONSTANT
        {warning disable C0228}
        arNumbers : ARRAY  OF INT;
    END_VAR
    VAR_INPUT
        ipOperation : I_BiFunction;
    END_VAR
    VAR
        i : __XINT;
    END_VAR

    // Exit the function call if the operation is not supplied.
    IF ipOperation = 0 THEN RETURN; END_IF

    // Initialise the result with the first element of the array.
    Aggregate := arNumbers;

    // Loop through the array and apply the operation defined by the interface.
    FOR i := LOWER_BOUND(arNumbers, 1) + 1 TO UPPER_BOUND(arNumbers, 1) DO
        Aggregate := ipOperation.Apply(Aggregate, arNumbers);
    END_FOR

    END_METHOD
END_PROGRAM</pre>
<h4 id="explanation" class="code-line" dir="auto" data-line="121">Explanation:</h4>
<ul class="code-line" dir="auto" data-line="123">
<li class="code-line" dir="auto" data-line="123">
<p class="code-line" dir="auto" data-line="123">The <span><strong><em><span style="color: #000000">ipOperations</span></em></strong><b><i> </i></b> </span>input parameter is an instance of the <span><strong><em><span style="color: #000000">I_BiFunction</span></em></strong><b><i> </i></b></span>interface, which defines the operation to be applied (such as summing or multiplying).</p>
</li>
<li class="code-line" dir="auto" data-line="125">
<p class="code-line" dir="auto" data-line="125">The method initialises the result (<span><strong><em><span style="color: #000000">Aggregate</span></em></strong></span>) with the first element of the array.</p>
</li>
<li class="code-line" dir="auto" data-line="127">
<p class="code-line" dir="auto" data-line="127">It then iterates through the rest of the array, applying the operation (via <span><strong><em><span style="color: #000000">ipOperations.Apply(...)</span></em></strong></span>) to the running result and each element of the array.</p>
</li>
</ul>
<h4 dir="auto" data-line="75"> </h4>
<h4 class="code-line" dir="auto" data-line="75"><span style="font-size: 14pt">Implementing the Operations</span></h4>
<h4 dir="auto" data-line="75"> </h4>
<p><span>Now, let’s implement specific operations by creating function blocks that implement the <strong><em><span style="color: #000000">I_BiFunction</span></em></strong><b><i> </i></b> interface. We will use these to perform different actions on the array elements.</span></p>
<h4 id="product-operation" class="code-line" dir="auto" data-line="133">Product Operation</h4>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this function block directly is not allowed'}
FUNCTION_BLOCK FB_ProductFunction IMPLEMENTS I_BiFunction
    METHOD Apply : INT
    VAR_INPUT
        nA, nB : INT;
    END_VAR

    // Return the product of two values
    Apply := nA * nB;

    END_METHOD
END_FUNCTION_BLOCK</pre>
<h4 id="maximum-value-operation" class="code-line" dir="auto" data-line="150">Maximum Value Operation</h4>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'calling this function block directly is not allowed'}
FUNCTION_BLOCK FB_MaximumValueFunction IMPLEMENTS I_BiFunction
    METHOD Apply : INT
    VAR_INPUT
        nA, nB : INT;
    END_VAR

    // Return the maximum of two values
    Apply := MAX(nA, nB);

    END_METHOD
END_FUNCTION_BLOCK</pre>
<h4 dir="auto" data-line="75"> </h4>
<h4 id="example-usage" class="code-line" dir="auto" data-line="166"><span style="font-size: 14pt">Example Usage</span></h4>
<h4 dir="auto" data-line="75"> </h4>
<p class="code-line" dir="auto" data-line="34"><span>Now that we've defined the functional interface and its implementations, we can use the <strong><em><span style="color: #000000">P_Operations</span></em></strong><b><i> </i></b>program to apply different operations to an array of numbers.<br /></span></p>
<pre contenteditable="false">PROGRAM P_Example1
VAR
    nProduct, 
    nLargest    : INT;
    arNumbers   : ARRAY OF INT := ;
    fbProduct   : FB_ProductFunction;
    fbLargest   : FB_MaximumValueFunction;
END_VAR

nProduct := P_Operations.Aggregate(arNumbers, fbProduct);
nLargest := P_Operations.Aggregate(arNumbers, fbLargest);</pre>
<p class="code-line" dir="auto" data-line="34"><span> </span></p>
947
<h4 dir="auto" data-line="75"> </h4>
<h4 id="step-1-define-the-functional-interface" class="code-line" dir="auto" data-line="75"><span style="font-size: 14pt">Real World Applications</span></h4>
<div>
<div> </div>
<div><span>Here are some practical examples of how functional interfaces shine in industrial automation:</span></div>
</div>
<div> </div>
<div><strong>Data Processing</strong></div>
<div>
<pre contenteditable="false">// Transform sensor data through different conversion functions
fCelsius    := P_DataTransform.Map(nRawSensorData, fbADCToCelsius);
fFahrenheit := P_DataTransform.Map(nRawSensorData, fbADCToFahrenheit);</pre>
</div>
<div> </div>
<div><strong>Batch Operations</strong></div>
<div>
<pre contenteditable="false">// Apply different operations to production batches
bAllPassed := P_BatchProcessor.Every(arQualityChecks, fbMeetsStandard);
bAnyFailed := P_BatchProcessor.Some(arQualityChecks, fbBelowThreshold);</pre>
</div>
<div> </div>
<div><strong>Validation and Filtering</strong></div>
<div>
<pre contenteditable="false">// Filter arrays based on different validation criteria
// Filter(&lt;source&gt;, &lt;predicate&gt;, &lt;destination&gt;) -&gt; &lt;Count&gt;
nCount := P_DataFilter.Filter(arSensorData, fbWithinTolerance, arValidReadings);
nCount := P_DataFilter.Filter(arSensorData, fbOutsideExpected, arOutliers);
nCount := P_DataFilter.Filter(arAlarms, fbHighSeverity, arCritical);</pre>
</div>
<div> </div>
<div><strong>Validation and Filtering</strong></div>
<div>
<pre contenteditable="false">// Sort machine data by different criteria
P_DataSort.Sort(arMachines, fbByEfficiency);
P_DataSort.Sort(arMachines, fbByUptime);
P_DataSort.Sort(arMachines, fbByProductionCount);</pre>
</div>
<p class="code-line" dir="auto" data-line="34">The key advantage here is that the processing logic (<strong><em><span style="color: #000000">Aggregate</span></em></strong>, <strong><em><span style="color: #000000">Map</span></em></strong>, <strong><em><span style="color: #000000">Filter</span></em></strong>, etc.) remains unchanged while the behaviour is completely customisable through different function block implementations.<span></span></p>
<h2 id="application-in-industrial-automation" class="code-line" dir="auto" data-line="65"><span style="font-size: 18pt">Conclusion</span></h2>
<p class="code-line" dir="auto" data-line="220">Functional interfaces bring a powerful abstraction mechanism to Structured Text programming. While ST lacks first-class functions, lambdas, and closures, functional interfaces allow us to:</p>
<ol class="code-line" dir="auto" data-line="222">
<li class="code-line" dir="auto" data-line="222">
<p class="code-line" dir="auto" data-line="222"><strong>Decouple algorithms from operations</strong>: The <strong><em><span style="color: #000000">Aggregate</span></em></strong> method doesn't know or care whether it's summing, multiplying, or finding maximums. It just applies the provided operation.</p>
</li>
<li class="code-line" dir="auto" data-line="224">
<p class="code-line" dir="auto" data-line="224"><strong>Increase code reusability</strong>: Write the processing logic once, then reuse it with countless different behaviors by simply implementing new function blocks.</p>
</li>
<li class="code-line" dir="auto" data-line="226">
<p class="code-line" dir="auto" data-line="226"><strong>Improve testability</strong>: Each operation is encapsulated in its own function block, making it easy to test in isolation.</p>
</li>
<li class="code-line" dir="auto" data-line="228">
<p class="code-line" dir="auto" data-line="228"><strong>Enhance maintainability</strong>: Changes to specific operations don't affect the core processing logic, and vice versa.</p>
</li>
<li class="code-line" dir="auto" style="text-align: left" data-line="230">
<p class="code-line" dir="auto" data-line="230"><strong>Create more expressive code</strong>: The intent becomes clear when you read <strong><em><span style="color: #000000">P_Operations.Aggregate(arNumbers, fbProduct) </span></em></strong>versus a hardcoded multiplication loop.</p>
</li>
</ol>
<p class="code-line" dir="auto" data-line="230">While we've focused on simple, stateless operations in this part, functional interfaces become even more powerful when combined with context and state. In <a href="https://twincontrols.com/community/postid/2305/" target="_blank" rel="noopener">Part 2</a>, we'll explore how to add <strong>context and capturing</strong> to our functional interfaces, allowing operations to carry configuration and state-mimicking the closure behaviour found in modern programming languages.</p>
<div>
<div><span>This approach bridges the gap between traditional PLC programming and modern software engineering practices, allowing for greater flexibility and maintainability in industrial automation systems without sacrificing the determinism and reliability that automation demands.</span></div>
</div>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>FisoThemes</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/advanced-interfaces-functional-interfaces-part-1/</guid>
                    </item>
				                    <item>
                        <title>System time to DT</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/system-time-to-dt/</link>
                        <pubDate>Mon, 29 Sep 2025 06:17:57 +0000</pubDate>
                        <description><![CDATA[Hi
I have a very simple task that I am struggling with. 
I need to write systemtime to a var type DT.
I try using F_GetSystemtime(); but I can not figure out how to convert the UNLINT to ...]]></description>
                        <content:encoded><![CDATA[<p>Hi</p>
<p>I have a very simple task that I am struggling with. </p>
<p>I need to write systemtime to a var type DT.</p>
<p>I try using F_GetSystemtime(); but I can not figure out how to convert the UNLINT to DT. </p>
<p>DateTime:= ULINT_TO_DT(F_GetSystemTime()) gives me a very strange result. </p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>jthyge</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/system-time-to-dt/</guid>
                    </item>
				                    <item>
                        <title>How to MC_trackconveyerbelt work ?</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/how-to-mc_trackconveyerbelt-work/</link>
                        <pubDate>Tue, 17 Jun 2025 07:44:30 +0000</pubDate>
                        <description><![CDATA[I have a project that use delta robot to pick and plate object that move on conveyor , I write program and config follow up from Infosys but it doesn&#039;t work , Can anyone help and explain ? ...]]></description>
                        <content:encoded><![CDATA[<p>I have a project that use delta robot to pick and plate object that move on conveyor , I write program and config follow up from Infosys but it doesn't work , Can anyone help and explain ? </p>
<p> </p>
<p>Thank you in advance </p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>best_pj</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/how-to-mc_trackconveyerbelt-work/</guid>
                    </item>
				                    <item>
                        <title>TwinCAT on virtual machine: can not deploy any code on local and there is no connection</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/twincat-on-virtual-machine-can-not-deploy-any-code-on-local-and-there-is-no-connection/</link>
                        <pubDate>Wed, 26 Mar 2025 21:01:32 +0000</pubDate>
                        <description><![CDATA[Dear all
I am new to TwinCAT (just started yesterday) and and I have no PLC for the moment.
I am uing TwinCAT on virtual machine (Windows 11) created on virtualBOX.
I installed TwinCAT di...]]></description>
                        <content:encoded><![CDATA[<p>Dear all</p>
<p>I am new to TwinCAT (just started yesterday) and and I have no PLC for the moment.</p>
<p>I am uing TwinCAT on virtual machine (Windows 11) created on virtualBOX.</p>
<p>I installed TwinCAT directly on my virtual machine, and tried to do a first "hello word" program.</p>
<p>After building my program, i am trying to deploy it to the local target (my virtual machine).</p>
<p>But there is no possiblity to perfom deployment (Action configuration button is grayed-out, and there is no communication with the local target).</p>
<p>Many thanks for your help.</p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>semamina</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/twincat-on-virtual-machine-can-not-deploy-any-code-on-local-and-there-is-no-connection/</guid>
                    </item>
				                    <item>
                        <title>HTTPS / REST (TF 6760) - on CX 9020 Beckhoff PLC</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/https-rest-tf-6760-on-cx-9020-beckhoff-plc/</link>
                        <pubDate>Fri, 27 Dec 2024 07:59:20 +0000</pubDate>
                        <description><![CDATA[i am trying to run a code on my cx 9020 (ARM Controller Windows CE 7 - Build 4024.53 ) using twincat 3 (build 4024.64) I have to call a rest api POST method the code runs without errors and ...]]></description>
                        <content:encoded><![CDATA[<p>i am trying to run a code on my cx 9020 (ARM Controller Windows CE 7 - Build 4024.53 ) using twincat 3 (build 4024.64) I have to call a rest api POST method the code runs without errors and a build is produced and loaded into plc in run mode i receive an error Socket_Err_No_Connection in one of the flags and I believe this what is creating this error. Please advise</p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>shafibug</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/https-rest-tf-6760-on-cx-9020-beckhoff-plc/</guid>
                    </item>
				                    <item>
                        <title>What is the role of time compensation in TwinCAT, and how does it affect synchronization between master and slave axes?</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/what-is-the-role-of-time-compensation-in-twincat-and-how-does-it-affect-synchronization-between-master-and-slave-axes/</link>
                        <pubDate>Tue, 01 Oct 2024 13:42:25 +0000</pubDate>
                        <description><![CDATA[I’m trying to understand how time compensation works in TwinCAT, as mentioned in the Beckhoff documentation.
We have a PTO axis (EL2522 module) connected to a DAQ to match the signal with p...]]></description>
                        <content:encoded><![CDATA[<div class="votecell post-layout--left">
<div class="js-voting-container d-flex jc-center fd-column ai-center gs4 fc-black-300" data-post-id="79043316" data-referrer="None">
<div class="js-vote-count flex--item d-flex fd-column ai-center fc-theme-body-font fw-bold fs-subheading py4" data-value="0"> </div>
<button id="saves-btn-79043316" class="js-saves-btn s-btn s-btn__unset c-pointer py4" type="button" data-controller="s-tooltip" data-s-tooltip-placement="right" data-s-popover-placement="" data-post-id="79043316" data-post-type-id="1" data-user-privilege-for-post-click="-1" aria-controls="" data-s-popover-auto-show="false" aria-describedby="--stacks-s-tooltip-s989j6if"></button></div>
</div>
<div class="postcell post-layout--right">
<div class="s-prose js-post-body">
<p>I’m trying to understand how time compensation works in TwinCAT, as mentioned in the Beckhoff documentation.</p>
<p><a href="https://infosys.beckhoff.com/english.php?content=../content/1033/tf50x0_tc3_nc_ptp/10650596235.html&amp;id=" rel="nofollow noreferrer">https://infosys.beckhoff.com/english.php?content=../content/1033/tf50x0_tc3_nc_ptp/10650596235.html&amp;id=</a></p>
<p>We have a PTO axis (EL2522 module) connected to a DAQ to match the signal with position data. This PTO axis acts as the master for multiple physical slave axes in our device.</p>
<p>During cam movement, we observed that the slaves are not in the expected position according to the cam table at any given time. This mismatch is consistent, and we suspect it may be related to time synchronization or compensation between the master and slave axes.</p>
<p>Could someone explain how time compensation in TwinCAT works and how it affects the synchronization between the master and slave axes during camming operations? Could it be the cause of the observed position mismatch?</p>
</div>
</div>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>Gerard</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/what-is-the-role-of-time-compensation-in-twincat-and-how-does-it-affect-synchronization-between-master-and-slave-axes/</guid>
                    </item>
				                    <item>
                        <title>TwinCAT 3 vs. laptops with ARM (Qualcomm Snapdragon)</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/twincat-3-vs-laptops-with-arm-qualcomm-snapdragon/</link>
                        <pubDate>Mon, 30 Sep 2024 20:29:32 +0000</pubDate>
                        <description><![CDATA[There are more and more new notebooks with Windows 10/11 built on ARM processors  (Qualcomm Snapdragon).ASUS Vivobook S
Acer Swift Edge
Samsung Galaxy Book4
LG GramPlease, post here feedb...]]></description>
                        <content:encoded><![CDATA[<p>There are more and more new notebooks with Windows 10/11 built on ARM processors  (Qualcomm Snapdragon).<br /><br />ASUS Vivobook S</p>
<p>Acer Swift Edge</p>
<p>Samsung Galaxy Book4</p>
<p>LG Gram<br /><br />Please, post here feedback with using them for TwinCAT3 (development environment + real-time).</p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>dayslypper</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/twincat-3-vs-laptops-with-arm-qualcomm-snapdragon/</guid>
                    </item>
				                    <item>
                        <title>JSON eaxamples</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/json-eaxamples/</link>
                        <pubDate>Wed, 24 Apr 2024 13:38:01 +0000</pubDate>
                        <description><![CDATA[I want to create recipes files in JSON.I need some examples to be able to read / write / change / delete json files from the Twincat code.]]></description>
                        <content:encoded><![CDATA[<p>I want to create recipes files in JSON.<br />I need some examples to be able to read / write / change / delete json files from the Twincat code.</p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>RonSchaap</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/json-eaxamples/</guid>
                    </item>
				                    <item>
                        <title>Operator Overloading in TwinCAT using OOP</title>
                        <link>https://twincontrols.com/community/twincat-knowledgebase/operator-overloading-in-twincat-using-oop/</link>
                        <pubDate>Fri, 19 Jan 2024 05:07:37 +0000</pubDate>
                        <description><![CDATA[Introduction
Operator overloading can somewhat be achieved in TwinCAT/Codesys systems through Object-Oriented Programming (OOP). Before we dive into practical examples, let&#039;s grasp the fund...]]></description>
                        <content:encoded><![CDATA[<h2 id="introduction" class="code-line" dir="auto" data-line="2">Introduction</h2>
<p class="code-line" dir="auto" data-line="4">Operator overloading can somewhat be achieved in TwinCAT/Codesys systems through Object-Oriented Programming (OOP). Before we dive into practical examples, let's grasp the fundamental concept of operator overloading and understand how it seamlessly integrates with interfaces.</p>
<h3 id="what-is-operator-overloading" class="code-line" dir="auto" data-line="6">What is Operator Overloading?</h3>
<p class="code-line code-active-line" dir="auto" data-line="8">In the realm of programming, operator overloading allows us to redefine the behavior of operators for custom data types. Instead of adhering strictly to their predefined operations, operators can be customised to work with user-defined types, enhancing the expressiveness and flexibility of your code.</p>
<h3 id="leveraging-interfaces-for-operator-overloading" class="code-line" dir="auto" data-line="10">Leveraging Interfaces for Operator Overloading</h3>
<p class="code-line" dir="auto" data-line="12">In TwinCAT/Codesys, the synergy of operator overloading and Object-Oriented Programming (OOP) comes to life through the strategic use of interfaces. Interfaces serve as blueprints for classes, defining a set of methods that implementing classes must adhere to. This modularity not only enhances code organisation but also facilitates the powerful concept of<span> </span><strong>functional interfaces</strong>.</p>
<h3 id="functional-interfaces-enhancing-flexibility" class="code-line" dir="auto" data-line="14">Functional Interfaces: Enhancing Flexibility</h3>
<p class="code-line" dir="auto" data-line="16"><strong>Functional interfaces</strong><span> </span>play a pivotal role in our exploration. These interfaces focus on a specific functionality, in our case, operator overloading. By designing interfaces such as<strong><em> I_Operator</em> </strong>and <strong><em>I_Object</em></strong>, we create a structured foundation for overloading basic arithmetic operators. This ensures that our classes adhere to a consistent and standardised interface, promoting code clarity and reusability.</p>
<h2 id="overloading-arithmetic-operators-designing-functional-interfaces" class="code-line" dir="auto" data-line="56">Overloading Arithmetic Operators: Designing Functional Interfaces</h2>
<p class="code-line" dir="auto" data-line="58">Building upon our foundation, let's craft functional interfaces for overloading arithmetic operators in TwinCAT/Codesys. Each interface encapsulates a specific operation, ensuring a clear and modular design.</p>
<h3 id="functional-interfaces-to-overload" class="code-line" dir="auto" data-line="60">Functional Interfaces to Overload</h3>
<pre contenteditable="false">INTERFACE I_Object EXTENDS __SYSTEM.IQueryInterface</pre>
<pre contenteditable="false">INTERFACE I_Operator EXTENDS I_Object </pre>
<pre contenteditable="false">INTERFACE I_Addition EXTENDS I_Operator

METHOD Plus : I_Addition
VAR_INPUT
	ipObject : I_Object;
END_VAR
VAR_OUTPUT
	e : E_Error;
END_VAR</pre>
<pre contenteditable="false">INTERFACE I_Subtraction EXTENDS I_Operator

METHOD Minus : I_Subtraction
VAR_INPUT
	ipObject : I_Object;
END_VAR
VAR_OUTPUT
	e : E_Error;
END_VAR</pre>
<pre contenteditable="false">INTERFACE I_Multiplication EXTENDS I_Operator

METHOD Times : I_Multiplication
VAR_INPUT
	ipObject : I_Object;
END_VAR
VAR_OUTPUT
	e : E_Error;
END_VAR</pre>
<pre contenteditable="false">INTERFACE I_Division EXTENDS I_Operator

METHOD DivideBy : I_Division
VAR_INPUT
	ipObject : I_Object;
END_VAR
VAR_OUTPUT
	e : E_Error;
END_VAR</pre>
<p> </p>
<p>These interfaces provide a standardised structure for implementing classes to define their behavior during addition, subtraction, multiplication, and division operations. Let's now illustrate these principles with a concrete example involving numeric interfaces.</p>
<h2 id="example-numeric-interface" class="code-line" dir="auto" data-line="72">Example: Scalars and Vectors</h2>
<p>To bring the theoretical concepts into practical application, let's consider the I_Scalar and I_Vector interfaces, representing scalar and vector entities, and their respective implementations in FB_Scalar and FB_Vector.</p>
<h3>Scalar Interface Implementation (FB_Scalar):</h3>
<p>The FB_Scalar function block implements the I_Scalar interface, defining methods for converting scalar values to different data types and handling potential errors.</p>
<pre contenteditable="false">INTERFACE I_Scalar EXTENDS I_Object

METHOD ToF64 : LREAL
VAR_OUTPUT
	e : E_Error;
END_VAR

METHOD ToI64 : LINT
VAR_OUTPUT
	e : E_Error;
END_VAR

METHOD ToU8 : BYTE
VAR_OUTPUT
	e : E_Error;
END_VAR</pre>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'do not call this function block directly'}
FUNCTION_BLOCK FB_Scalar IMPLEMENTS I_Scalar, I_Addition, I_Subtraction, I_Multiplication, I_Division
VAR
	_fValue : LREAL; 
END_VAR


-----------------------------------------------------------
METHOD ToF64 : LREAL
VAR_OUTPUT
	e	: E_Error;
END_VAR

ToF64 := THIS^._fValue;

IF TO_STRING(THIS^._fValue) = '#NaN' THEN 
	e := E_Error.NaN;
ELSIF TO_STRING(THIS^._fValue) = '#Inf' THEN
	e := E_Error.PositiveInfinity;
ELSIF TO_STRING(THIS^._fValue) = '-#Inf' THEN
	e := E_Error.NegativeInfinity;
	END_IF


-----------------------------------------------------------
METHOD Plus : I_Addition
VAR_INPUT
	ipObject : I_Object;
END_VAR
VAR_OUTPUT
	e : E_Error;
END_VAR
VAR
	e1, e2 : E_Error;
	ipNumber : I_Scalar;
END_VAR

Plus := THIS^;

IF NOT __QUERYINTERFACE(ipObject, ipNumber) THEN e := E_Error.TypeMismatch; RETURN; END_IF

THIS^._fValue := THIS^.ToF64(e =&gt; e1) + ipNumber.ToF64(e =&gt; e2);

e := MAX(e1, e2);

-----------------------------------------------------------
METHOD Times : I_Multiplication
VAR_INPUT
	ipObject : I_Object;
END_VAR
VAR_OUTPUT
	e : E_Error;
END_VAR
VAR
	e1, e2 : E_Error;
	ipNumber : I_Scalar;
END_VAR

Times := THIS^;

IF NOT __QUERYINTERFACE(ipObject, ipNumber) THEN e := E_Error.TypeMismatch; RETURN; END_IF

THIS^._fValue := THIS^.ToF64(e =&gt; e1) * ipNumber.ToF64( e =&gt; e2);

e := MAX(e1, e2);</pre>
<h3>Vector Interface Implementation (FB_Vector):</h3>
<p><span>Similarly, the FB_Vector function block implements the I_Vector interface, providing methods for vector operations like addition and multiplication.</span></p>
<pre contenteditable="false">INTERFACE I_Vector EXTENDS I_Object

METHOD ToArray : ARRAY OF LREAL
VAR_INPUT
END_VAR

PROPERTY X : LREAL

PROPERTY Y : LREAL

PROPERTY Z : LREAL</pre>
<pre contenteditable="false">{attribute 'no_explicit_call' := 'do not call this function block directly'}
FUNCTION_BLOCK FB_Vector IMPLEMENTS I_Vector, I_Addition, I_Subtraction, I_Multiplication
VAR
	_fX, _fY, _fZ : LREAL;
END_VAR


-----------------------------------------------------------
METHOD Plus : I_Addition
VAR_INPUT
	ipObject : I_Object;
END_VAR
VAR_OUTPUT
	e : E_Error;
END_VAR
VAR
	ipVector : I_Vector;
END_VAR

Plus := THIS^;

IF NOT __QUERYINTERFACE(ipObject, ipVector) THEN e := E_Error.TypeMismatch; RETURN; END_IF

THIS^._fX := THIS^._fX + ipVector.X;
THIS^._fY := THIS^._fY + ipVector.Y;
THIS^._fZ := THIS^._fZ + ipVector.Z;


-----------------------------------------------------------
METHOD Times : I_Multiplication
VAR_INPUT
	ipObject : I_Object;
END_VAR
VAR_OUTPUT
	e : E_Error;
END_VAR
VAR
	ipNumber : I_Scalar;
	ipVector : I_Vector;
	TmpX, TmpY, TmpZ : LREAL;
END_VAR

Times := THIS^;

// Scale vector.
IF __QUERYINTERFACE(ipObject, ipNumber) THEN 
	THIS^.SetValue( THIS^._fX * ipNumber.ToF64(),
					THIS^._fY * ipNumber.ToF64(),
					THIS^._fZ * ipNumber.ToF64());
	RETURN;
	END_IF

// Do the cross-product.
IF __QUERYINTERFACE(ipObject, ipVector) THEN 
	TmpX := THIS^._fX; TmpY := THIS^._fY; TmpZ := THIS^._fZ;
	THIS^.SetValue(	(TmpY*ipVector.Z) - (TmpZ*ipVector.Y),
					(TmpZ*ipVector.X) - (TmpX*ipVector.Y),
					(TmpX*ipVector.Y) - (TmpY*ipVector.X));
	
	RETURN; 
	END_IF

e := E_Error.TypeMismatch; 
</pre>
<p dir="auto" data-line="71"> </p>
<h3>Main Program Implementation:</h3>
<p><span>Now, let's integrate these function blocks into a main program to showcase the practical usage of operator overloading with Scalars and Vectors.</span></p>
<p dir="auto" data-line="71"> </p>
<pre contenteditable="false">PROGRAM MAIN
VAR
	bDoubleSquareScal, bAddVec, bCrossProd, bScaleVec: BOOL;
	eError : E_Error;
	fbScalar : FB_Scalar(2.2);
	fbVec1 : FB_Vector(1,2,3);
	fbVec2 : FB_Vector(3,2,1);
END_VAR
============================================================
IF bDoubleSquareScal THEN 
	bDoubleSquareScal := FALSE;
	fbScalar.Times(fbScalar.Plus(fbScalar));
	END_IF

IF bAddVec THEN
	bAddVec := FALSE;
	fbVec1.Plus(fbVec2);
	END_IF
	
IF bCrossProd THEN
	bCrossProd := FALSE;
	fbVec1.Times(fbVec2);
	END_IF
	
IF bScaleVec THEN
	bScaleVec := FALSE;
	fbVec1.Times(fbScalar);
	END_IF</pre>
<h2 id="conclusion" class="code-line code-active-line" dir="auto" data-line="282">Conclusion</h2>
<p class="code-line" dir="auto" data-line="284">Developers can utilize these concepts and implementations to enhance code expressiveness and flexibility in their projects.<br /><br /><a href="https://github.com/fisothemes/Operator-Overloading-in-TwinCAT-using-OOP" target="_blank" rel="noopener">Example Code can be found here</a></p>]]></content:encoded>
						                            <category domain="https://twincontrols.com/community/twincat-knowledgebase/">Knowledge Base</category>                        <dc:creator>FisoThemes</dc:creator>
                        <guid isPermaLink="true">https://twincontrols.com/community/twincat-knowledgebase/operator-overloading-in-twincat-using-oop/</guid>
                    </item>
							        </channel>
        </rss>
		