With the object orientated options we’ve got available with IEC 61131-3 last years the time has come to talk about design patterns and best practices in the world of PLC programming. In this series of three posts ‘The three pillars of OOP‘ I will explain the concepts of: Encapsulation, Inheritance and Polymorphism with some examples in TwinCAT. This post is about the second pillar ‘Inheritance’.
What is inheritance?
Inheritance is defined as a mechanism by which a function block derives from a base function block. Meaning that the derived function block inherits all the properties, methods and local variables from a base function block. This can be extended with it’s own defined behavior. However, a derived function block can only access the properties and methods which are declared as Public, Protected or Internal. In TwinCAT the local variables are always accessible for the derived function block.
Why is inheritance important?
- Reuse of existing functionality without rewriting the same code
- We can extend existing functionality without modifying its original function block. This is particularly useful if you want to extend functionality which comes from a third party library.
- With inheritance we will be able to override the methods and properties of the base class. This is closely related to the third pillar of OOP: Polymorphism.
How do we achieve inheritance in TwinCAT?
In TwinCAT we can manually derive a function block from a base by using “EXTEND” keyword in the derived function block header:
FUNCTION_BLOCK FB_Derived EXTENDS FB_Base
As alternative when adding a new function block TwinCAT can fill it in for you:
A practical example
Take a look at our load cell function block from the post about encapsulation. It is a function block containing the basic behaviour of a load cell. Suppose we want to extend this with a gain and tare value. However, we want this without modifying the original function block. We can do this by creating a function block ‘fbExtendedLoadcell’ which derives from fbLoadCell. We add our extended behaviour to the fbExtendedLoadcell function block. In a UML diagram it looks like this:
The implementation of this extended behaviour could look like this: In the fbExtendedLoadCell declaration text we use the EXTEND keyword to derive from the fbLoadCell. We also add some private fields we gonna use for the implementation of our gain and tare values.
FUNCTION_BLOCK fbExtendedLoadCell EXTENDS fbLoadCell VAR _Gain:LREAL:=1; _Tare:LREAL; END_VAR
Now the implementation of the properties is pretty straight forward:
PROPERTY PUBLIC Gain : LREAL
PROPERTY PUBLIC Tare : LREAL
With the properties in place we can write our ScaledWeight property. This property gets the calculated weight from its base function block and applies the scaling on it. Notice that this would not be allowed if the ActualWeight property was a private property!
PROPERTY PUBLIC ScaledWeight : LREAL
ScaledWeight:=ActualWeight * Gain +Tare;
And with that we have a our extended load cell function block!
Inheritance is the second pillar of OOP. A derived function block inherits the behaviour (properties, methods, fields) of a base function block. Inheritance is useful to extent existing functionality without rewriting the same code. In addition this will also help to keep your code DRY. We have seen an example of a extended load cell function block as example of inheritance.
That was it for now! In the next post we will talk about the next pillar of OOP : ‘Polymorphism’.
Happy coding 🙂