Object Oriented Programming¶
IEC 61131-3 Edition 3 (2013) added object-oriented programming to the standard. It builds on the function block — the language’s existing unit of reusable, stateful behavior — and adds three ideas: inheritance, interfaces, and abstract types. This page explains those concepts and the terminology the standard uses for them.
Note
The object-oriented syntax described here is recognized only when it is enabled; otherwise the keywords are ordinary identifiers. See Enabling Dialects and Features for the flag and dialects reference. How far IronPLC takes each construct beyond parsing varies — Object Oriented Programming gives the per-keyword status, and what is not yet analyzed reports P9999. This page describes the language concepts; it is not a statement of what IronPLC executes today.
Why object-oriented programming?¶
A function block already bundles data and behavior: it has internal state and runs code that acts on that state. Object-oriented programming extends this in two directions. First, it lets one function block type build on another instead of copying it — so shared behavior is written once and reused. Second, it lets code work with an instance through a contract rather than a specific type — so the same code can drive many different implementations. The standard expresses these with a small set of keywords.
Inheritance¶
Inheritance lets a function block type build on an existing one. A type is derived from a base type using the EXTENDS keyword. The derived type inherits the base type’s variables and methods, and it can add its own or refine what it inherited.
FUNCTION_BLOCK FB_Motor
VAR
running : BOOL;
END_VAR
END_FUNCTION_BLOCK
FUNCTION_BLOCK FB_AdvancedMotor EXTENDS FB_Motor
VAR
speed : INT;
END_VAR
END_FUNCTION_BLOCK
Here FB_AdvancedMotor is the derived type and FB_Motor is its base
type. A function block type has at most one direct base type — the standard
provides single inheritance for function block types. An instance of a derived
type is a kind of its base type, so it can be used wherever the base type is
expected.
Hiding inherited names¶
A derived type can declare a variable whose name is already used by an inherited variable. The declaration in the derived type hides (or shadows) the inherited one: within the derived type’s own body the name refers to the member declared there, not to the one it inherited. The inherited member is not removed — it still exists on every instance and is reached through the base type.
FUNCTION_BLOCK FB_Base
VAR
state : INT;
END_VAR
END_FUNCTION_BLOCK
FUNCTION_BLOCK FB_Derived EXTENDS FB_Base
VAR
state : BOOL;
END_VAR
END_FUNCTION_BLOCK
Inside FB_Derived, state names the BOOL declared there; the
inherited INT is hidden but still present on the instance.
Hiding is different from declaring the same name twice in one place. Two
declarations of the same name in a single scope — for example two variables in
one VAR block — are a duplicate and are rejected
(P4014). Hiding involves two
different scopes, the base type and the derived type, so the name is
resolved by choosing the nearer declaration rather than reported as an error.
Referring to the instance and to the base type¶
Hiding raises a question: once a derived type has hidden an inherited name, how does it reach the hidden one? The standard answers with two names for the instance a method is running on — THIS and SUPER.
THIS^ is the instance itself. It is what makes an instance variable
reachable when a nearer name — a method parameter, say — hides it.
SUPER^ is the same instance seen as its base type. A derived type that
overrides an inherited method uses it to call the implementation it
overrode, so the derived behavior can add to the base behavior rather than
replace it:
FUNCTION_BLOCK FB_LoggingMotor EXTENDS FB_Motor
METHOD Stop
SUPER^.Stop();
END_METHOD
END_FUNCTION_BLOCK
Both are pointers to an instance, which is why each is written with the
dereference operator ^. SUPER^ is resolved when the program is
compiled, not while it runs: “the base type’s implementation” is decided by
the declaration, not by what the instance turns out to be.
Interfaces¶
An interface is a named contract: a set of method signatures — the
name, parameters, and return type of each method — with no implementation. An
interface is declared with
INTERFACE and closed
with END_INTERFACE. A function block type states that it fulfils the
contract with the
IMPLEMENTS keyword,
which obliges it to supply a body for every method the interface declares.
INTERFACE I_Drivable
END_INTERFACE
FUNCTION_BLOCK FB_Motor IMPLEMENTS I_Drivable
VAR
running : BOOL;
END_VAR
END_FUNCTION_BLOCK
Unlike inheritance, interfaces are not limited to one: a function block type may implement several interfaces, and interfaces themselves may extend other interfaces to combine their contracts. Because any implementing type satisfies the same contract, code written against an interface can operate on instances of unrelated types — this is polymorphism, and selecting the right method implementation for the actual instance at run time is called dynamic binding (dynamic dispatch).
Interfaces and inheritance are complementary. Inheritance shares an implementation down a single line of descent; an interface shares a contract across any number of otherwise unrelated types. A declaration can use both at once — extend a base type and implement one or more interfaces.
Abstract types¶
A type marked ABSTRACT is one that is intended to be extended rather than instantiated on its own. An abstract function block type defines the shared shape of a family of types — common variables and method signatures — while leaving some behavior for derived types to complete. Because it is incomplete, an instance of an abstract type cannot be created directly; only a concrete type that extends it can be instantiated.
FUNCTION_BLOCK ABSTRACT FB_BaseAxis
VAR
enabled : BOOL;
END_VAR
END_FUNCTION_BLOCK
FUNCTION_BLOCK FB_LinearAxis EXTENDS FB_BaseAxis
VAR
position : REAL;
END_VAR
END_FUNCTION_BLOCK
FB_BaseAxis establishes what every axis has in common; FB_LinearAxis
extends it into a concrete type that can be instantiated.
Terminology¶
Term |
Meaning |
|---|---|
Base type |
The type another type is derived from. |
Derived type |
A type that extends a base type and inherits its members. |
Inheritance |
Deriving one type from another so it reuses the base type’s members. |
Hiding (shadowing) |
A member declared in a derived type takes precedence, within that type, over an inherited member of the same name. |
Interface |
A named set of method signatures with no implementation. |
Implement |
Supply a body for every method an interface declares. |
Abstract type |
A type that cannot be instantiated directly and is meant to be extended. |
Polymorphism |
Using instances of different types through a shared base type or interface. |
Dynamic binding |
Choosing the method implementation for the actual instance at run time. |
Beyond EXTENDS, IMPLEMENTS, ABSTRACT, and INTERFACE, Edition 3
also defines
METHOD,
THIS and SUPER,
PROPERTY, OVERRIDE, and FINAL for writing and refining methods.
IronPLC parses METHOD, THIS, and SUPER; it does not parse
PROPERTY, OVERRIDE, or FINAL yet.
See Also¶
Object Oriented Programming — the object-oriented keywords
FUNCTION_BLOCK — the
FUNCTION_BLOCKunitVariable Scope — variable scope and resolution
P4014 — duplicate name in a single scope
Enabling Dialects and Features — enabling the object-oriented syntax
P9999 — the diagnostic reported for not-yet-supported object-oriented constructs
References¶
IEC 61131-3:2013 — object-oriented extensions (
EXTENDS,SUPER, class and function block inheritance)CODESYS: Static Analysis SA0013 (Declarations with the same variable name)
Stefan Henneken: IEC 61131-3 — Methods, Properties and Inheritance