IEC 61131-3: Abstract FB vs. Interface

Function blocks, methods and properties can be marked as abstract since TwinCAT V3.1 build 4024. Abstract FBs can only be used as basic FBs for inheritance. Direct instantiation of abstract FBs is not possible. Therefore, abstract FBs have a certain similarity to interfaces. Now, the question is in which case an interface and in which case an abstract FB should be used.

A very good description of abstract can be found in the post The ABSTRACT keyword from the blog PLCCoder.com or Beckhoff Information System. So, the most important things should be repeated only briefly.

abstract methods

METHOD PUBLIC ABSTRACT DoSomething : LREAL
  • consist exclusively of the declaration and do not contain any implementation. The method body is empty.
  • can be public, protected or internal. The access modifier private is not allowed.
  • cannot additionally be declared as final.

abstract properties

PROPERTY PUBLIC ABSTRACT nAnyValue : UINT
  • can contain getters, setters, or both.
  • getter and setter consist only of the declaration and do not contain any implementation.
  • can be public, protected or internal. The access modifier private is not allowed.
  • cannot additionally be declared as final.

abstract function blocks

FUNCTION_BLOCK PUBLIC ABSTRACT FB_Foo
  • As soon as a method or a property is declared as abstract, the function block must also be declared as abstract.
  • No instances can be created from abstract FBs. Abstract FBs can only be used as basic FBs when inherited.
  • All abstract methods and all abstract properties must be overwritten to create a non-abstract FB. An abstract method or an abstract property becomes a non-
    abstract method or a non-abstract property by overwriting.
  • Abstract function blocks can additionally contain non-abstract methods and/or non-abstract properties.
  • If not all abstract methods or not all abstract properties are overwritten during inheritance, the inheriting FB can again only be an abstract FB (step-by-step concretization).
  • Pointers or references of an abstract FB type are permitted. However, these can refer to non-abstract FBs and thus call their methods or properties (polymorphism).

Differences between an abstract FB and an interface

If a function block consists exclusively of abstract methods and abstract properties, then, it does not contain any implementations and thus has a certain similarity to interfaces. However, there are some special features to consider in detail.

Interfaceabstract FB
supports multiple inheritance+
can contain local variables+
can contain non-abstract methods+
can contain non-abstract properties+
supports further access modifiers besides public+
applicable with array+only via POINTER

The table can give an impression that interfaces can be almost completely replaced by abstract FBs. However, interfaces offer greater flexibility because they can be used in different inheritance hierarchies. The post IEC 61131-3: Object composition with the help of interfaces shows an example of this.

As a developer, you therefore want to know when an interface and when an abstract FB should be used. The simple answer is preferably both at the same time. This provides a standard implementation in the abstract base FB, which makes it easier to derive. However, every developer has the freedom to implement the interface directly.

Example

Function blocks should be designed for the data management of employees. A distinction is made between permanent employees (FB_FullTimeEmployee) and contract employees (FB_ContractEmployee). Each employee is identified by his first name (sFirstName), last name (sLastName) and the personnel number (nPersonnelNumber). Corresponding properties are provided for this purpose. In addition, a method is required that outputs the full name including personnel number as a formatted string (GetFullName()). The calculation of the monthly income is done by the method GetMonthlySalary().

The two functional blocks differ in the calculation of the monthly income. While the permanent employee receives an annual salary (nAnnualSalary), the monthly salary of the contract employee results from the hourly wage (nHourlyPay) and the monthly working hours (nMonthlyHours). The two function blocks for calculating the monthly income therefore have different properties. The GetMonthlySalary() method is contained in both function blocks, but differs in implementation.

1. Solution approach: Abstract FB

Since both FBs have a lot in common, it is obvious to create a basic FB (FB_Employee). This basic FB contains all methods and properties that are contained in both FBs. However, since the methods GetMonthlySalary() differ in their implementation, it is marked as abstract in FB_Employee. This means that all FBs that inherit from these base FBs must overwrite GetMonthlySalary().

(abstract elements are displayed in italics)

Sample 1 (TwinCAT 3.1.4024) on GitHub

The cons

The solution approach looks very solid at first glance. However, as mentioned above, the use of inheritance can also have disadvantages. Especially when FB_Employee is part of an inheritance chain. FB_FullTimeEmployee and FB_ContractEmploye also inherit everything that FB_Employee inherits via this chain. If FB_Employee is used in a different context, an extensive inheritance hierarchy can lead to further problems.

There are also restrictions when trying to store all instances in an array as references. The compiler does not allow the following declaration:

aEmployees : ARRAY [1..2] OF REFERENCE TO FB_Employee; // error

Pointers must be used instead of references:

aEmployees : ARRAY [1..2] OF POINTER TO FB_Employee;

However, there are some things to consider when using pointers (e.g., online change). For this reason, I try to avoid pointers as far as possible.

The pros

Although it is not possible to create an instance of an abstract FB directly, the methods and properties of an abstract FB can be accessed by reference.

VAR
  fbFullTimeEmployee :  FB_FullTimeEmployee;
  refEmployee        :  EFERENCE TO FB_Employee;
  sFullName          :  STRING;
END_VAR
refEmployee REF= fbFullTimeEmployee;
sFullName := refEmployee.GetFullName();

It can also be an advantage that the method GetFullName() and the properties sFirstName, sLastName and nPersonnelNumber are already completely implemented in the abstract base FB and are not declared as abstract there. It is no longer necessary to overwrite these elements in the derived FBs. For example, if the formatting for the name is to be adapted, then this is to be accomplished only at one place.

2. Solution approach: Interface

An approach with interfaces is very similar to the previous variant. The interface contains all methods and properties that are the same for both FBs (FB_FullTimeEmployee and FB_ContractEmployee).

Sample 2 (TwinCAT 3.1.4024) on GitHub

The cons

Because the FB_FullTimeEmployee and FB_ContractEmployee implement the I_Employee interface, each FB must also contain all methods and all properties from the interface. This also applies to the method GetFullName(), which performs the same calculation in both cases.

If an interface has been published (e.g., by a library) and used in different projects, changes to this interface are no longer possible. If you add a property, all function blocks that implement this interface must also be adapted. This is not necessary when inheriting FBs. If a basic FB is expanded, no FBs that inherit from it have to be changed unless the new methods or properties are abstract.

Tip: If it happens that you have to adapt an interface later, you can create a new interface. This interface inherits from the original interface and is extended by the necessary elements.

The pros

Function blocks can implement several interfaces. Interfaces can therefore be used more flexibly in many cases.

With a function block, a specific interface can be queried at runtime using __QUERYINTERFACE(). If this has been implemented, access to the FB is possible via this interface. This makes the use of interfaces very flexible.

If the implementation of a certain interface is known, the access via the interface can also be done directly.

VAR
  fbFullTimeEmployee :  FB_FullTimeEmployee;
  ipEmployee         :  I_Employee;
  sFullName          :  STRING;
END_VAR
ipEmployee := fbFullTimeEmployee;
sFullName := ipEmployee.GetFullName();

In addition, interfaces can be used as data type for an array. All FBs that implement the interface I_Employee can be added to the following array.

aEmployees : ARRAY [1..2] OF I_Employee;

3. Solution approach: Combination of abstract FB and interface

Why not combine both approaches and thus benefit from the advantages of both variants?

(abstract elements are displayed in italics)

Sample 3 (TwinCAT 3.1.4024) on GitHub

When combining the two approaches, the interface is provided first. Then, the use of the interface is simplified by the abstract function block FB_Employee. The same implementations of common methods can be provided in the abstract FB. A multiple implementation is not necessary. If new FBs are added, they can also use the I_Employee interface directly.

The effort for the implementation is initially a little higher than with the two previous variants. However, this extra effort can be worth it, especially with libraries that are used by several programmers and further developed over the years.

  • If the user should not create an own instance of the FB (because this does not seem to be useful), then abstract FBs or interfaces are helpful.
  • If one wants to have the possibility to generalize into more than one basic type, then an interface should be used.
  • If an FB can be set up without implementation of methods or properties, then an interface should be preferred over an abstract FB.

Author: Stefan Henneken

I’m Stefan Henneken, a software developer based in Germany. This blog is just a collection of various articles I want to share, mostly related to Software Development.

2 thoughts on “IEC 61131-3: Abstract FB vs. Interface”

  1. I am very interested in the ‘OOP for PLC’ topic but couldn’t find the practical sense yet.
    Seems for me all pros related to program structure can be achieved without OOP but with DUT and FB instances.
    But anyway, I feel like I am close to get the sense but walking around… =)

    Could the OOP approach be useful in such a way:

    – there is AI module with diferent sensors connected to it.
    A ‘sensor’ normally has the following common:
    1) raw input (INT)
    2) scaled value (REAL, property GET)
    3) filtered value (REAL, property GET)
    4) Connection Error (BOOL, property GET)
    5) Overrange Warning (LL/HL, BOOL, property GET)

    The sensors differ from each other with the way of scaling and filtering (e.g., linear scaling or exponential for pressure sensors, or pt1000 when *0.1 is needed). Maybe ‘unit’ property can be used as well for HMI interface (‘mbar’, ‘°C’)

    Would it be OOP approach useful here? normally all this can be done with e.g. DUT_SENSOR (iRaw, rScaled, rFiltered, xError) data structure and FB or FC ‘CalcSensor’ with different inputs for scaling ranges / other parameters (even this sensor-processing-fb can get a pointer to DUT, so the call in the program is very simple)?

    am I right, if use OOP with abstract FB:
    – after creating Base FB ‘sensor’ and all other derived FBs ‘sensor Pressure’/’sensor pt100’/’sensor height’ etc., all the instances can be called with FOR cycle like

    VAR
    fbSensor :??? what type must be here, is all they inherit from FB_Sensor
    END_VAR
    FOR iCounter := 1 TO NUM_SENSORS BY 1 DO
    fbSensor[i]();
    END_FOR

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: