Simotion OOP: Declaring Classes in ST Unit Interface Section

David Krause12 min read
HMI ProgrammingSiemensTutorial / How-to
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Simotion OOP: Declaring Classes in the ST Unit Interface Section

In SIMOTION programming, an ST source file is organized as a UNIT with two distinct declaration sections: INTERFACE and IMPLEMENTATION. The placement of a CLASS declaration inside one section or the other controls its visibility to other units in the project. Declaring a class in the INTERFACE section exports it; declaring it in the IMPLEMENTATION section keeps it private. This behavior implements the IEC 61131-3 third edition scope rules and is fundamental to organizing OOP code in SIMOTION SCOUT and SIMOTION inside TIA Portal.

This reference covers the technical rationale, the compiler rules, the USES mechanism, the relationship to OOP interfaces, and field-proven patterns for organizing class libraries in SIMOTION.

Important: The ST unit "INTERFACE" section is a source organization construct. It must not be confused with the OOP concept of an interface (a class containing only abstract methods) introduced in IEC 61131-3 3rd edition. They share a word but are different mechanisms.

1. ST Unit Structure in SIMOTION

Every ST source file compiled by the SIMOTION compiler is wrapped in a UNIT envelope. The minimum valid structure looks like this:

UNIT MyUnit;

INTERFACE
  // Exported declarations: visible to other units via USES
END_INTERFACE

IMPLEMENTATION
  // Local declarations: visible only inside this unit
END_IMPLEMENTATION

END_UNIT.

The compiler enforces a strict order: INTERFACE always precedes IMPLEMENTATION, and the unit terminator END_UNIT. (note the terminating period) must close the file.

The following declaration types may appear in either section:

Declaration Allowed in INTERFACE Allowed in IMPLEMENTATION
FUNCTION_BLOCK Yes (exported) Yes (local)
FUNCTION Yes (exported) Yes (local)
CLASS (OOP, IEC 61131-3 3rd ed.) Yes (exported) Yes (local)
INTERFACE (OOP interface) Yes (exported) Yes (local)
PROGRAM No No (top-level only)
VAR_GLOBAL Yes (with CONSTANT or RETAIN attributes) Limited
TYPE aliases Yes Yes

The choice of section determines scope. The compiler emits visibility metadata into the unit's symbol table, and downstream units that include this unit will only see the INTERFACE portion.

2. Why a Class Is Declared in the INTERFACE Section

The CLASS keyword introduces an object-oriented class as defined in IEC 61131-3 3rd edition. SIMOTION OOP supports:

  • Class declaration with EXTENDS (single inheritance)
  • METHOD, PROPERTY, and VAR in PUBLIC, PRIVATE, PROTECTED, and INTERNAL access sections
  • Class instantiation via fbInstance : CLASS_NAME; followed by fbInstance := fbInstance$ClassName();
  • INTERFACE declarations (pure abstract classes)
  • Polymorphic dispatch via interface references (see section 7)

A class must be visible (declared) in the INTERFACE section of its unit if any other unit in the program needs to:

  1. Instantiate it (obj := obj$ClassName();)
  2. Declare a variable or instance of the class type
  3. Call its PUBLIC methods or read/write its PUBLIC properties
  4. Extend it via EXTENDS
  5. Reference it through an OOP INTERFACE variable

Without an INTERFACE declaration, the class is local to its unit. The compiler will reject any cross-unit reference with error F1101 "Type 'XYZ' is not exported by unit 'ABC'" (or the equivalent localized message in SIMOTION SCOUT). Removing the class from INTERFACE and placing it only in IMPLEMENTATION makes it inaccessible outside the unit, even if other units include this unit via USES.

3. The USES Statement: Importing an Exported Class

To consume a class exported by another unit, the consuming unit must declare a USES clause that names the source unit. The USES statement appears at the top of the consuming unit, before any INTERFACE or IMPLEMENTATION block content.

USES ValveControlLib;  // Imports all INTERFACE exports from ValveControlLib

UNIT MyConsumerUnit;

INTERFACE
  VAR
    MyValve : ValveControl;  // Class declared in ValveControlLib INTERFACE
  END_VAR
END_INTERFACE

IMPLEMENTATION
  // MyValve instantiation and method calls
END_IMPLEMENTATION

END_UNIT.

Key rules for USES:

  • The referenced unit must be compiled in the same SIMOTION device or in a referenced library.
  • Only the INTERFACE section symbols become visible; IMPLEMENTATION symbols remain hidden.
  • Circular USES dependencies are rejected by the compiler (error F1102).
  • The order of USES statements matters only when two units export symbols with identical names; the later USES shadows the earlier (with a compiler warning).
Engineering tip: Treat each unit as a module with a public API (its INTERFACE) and a private implementation (its IMPLEMENTATION). Keep the INTERFACE surface area as small as practical to minimize recompilation cascades when implementation details change.

4. INTERFACE vs. IMPLEMENTATION: Decision Matrix

Use the following matrix to decide where each class belongs:

Requirement INTERFACE IMPLEMENTATION
Class is referenced by programs in other units Required Not allowed
Class is only used by code inside its own unit Optional (but harmless) Recommended
Class is part of a published library Required (for all public classes) Used for helper/internal classes
Class is referenced by an OOP interface variable in another unit Required Not allowed
Class extends another class from a different unit Required Not allowed

A common SIMOTION library pattern is to declare all public, reusable classes in INTERFACE and all implementation helpers in IMPLEMENTATION. For example, the ValveControl class with error reporting (chapter 4.5.7.2 of the Michael Braun reference text) is exported, while a private ValveStateHelper class used internally by ValveControl methods stays local.

5. Concrete Example: ValveControl with Error Reporting

The following example mirrors the structure of the canonical "ValveControl with Error Reporting" sample (chapter 4.5.7.2 of "Object-Oriented Programming with SIMOTION", ISBN 9783895784569, Publicis MCD). It demonstrates a class exported via INTERFACE and consumed by an MCC unit or ST program in another unit.

Unit ValveControlLib — the library that owns the class:

UNIT ValveControlLib;

INTERFACE

  CLASS ValveControl
    VAR
      bIsOpen      : BOOL := FALSE;\li      bError       : BOOL := FALSE;\li      nErrorCode   : DINT := 0;\li    END_VAR

    METHOD PUBLIC Open : BOOL
      VAR_INPUT
        bForce : BOOL := FALSE;
      END_VAR
    END_METHOD

    METHOD PUBLIC Close : BOOL
    END_METHOD

    METHOD PUBLIC ResetError : BOOL
    END_METHOD

    PROPERTY PUBLIC State : STRING
      GET
        IF bError THEN State := 'ERROR';
        ELSIF bIsOpen THEN State := 'OPEN';
        ELSE State := 'CLOSED';
        END_IF;
      END_GET
    END_PROPERTY
  END_CLASS

END_INTERFACE

IMPLEMENTATION

  METHOD PUBLIC ValveControl : BOOL
    // (Destructor / class body override if needed)
  END_METHOD

  METHOD PUBLIC ValveControl.Open : BOOL
    // implementation omitted for brevity
  END_METHOD

  METHOD PUBLIC ValveControl.Close : BOOL
    // implementation omitted for brevity
  END_METHOD

  METHOD PUBLIC ValveControl.ResetError : BOOL
    bError := FALSE;
    nErrorCode := 0;
    ResetError := TRUE;
  END_METHOD

END_IMPLEMENTATION

END_UNIT.

Unit ValveUser — a consumer in a different unit:

USES ValveControlLib;

UNIT ValveUser;

INTERFACE
  VAR_GLOBAL
    g_Valve1 : ValveControl;
  END_VAR
END_INTERFACE

IMPLEMENTATION

  // g_Valve1 := g_Valve1$ValveControl();   // typically auto-instantiated by runtime

END_IMPLEMENTATION

END_UNIT.

Removing the CLASS ValveControl block from INTERFACE in ValveControlLib would cause the compiler to fail when processing ValveUser with a "type not exported" error. The class would still be usable inside ValveControlLib, but invisible elsewhere.

6. INTERFACE Section and OOP Interfaces (Distinct Concepts)

SIMOTION's OOP extension (IEC 61131-3 3rd edition) introduces the INTERFACE keyword as a class type that contains only abstract methods and properties. The example chapter 4.5.5 "Interfaces as reference to classes" demonstrates using an OOP interface to decouple consumers from concrete implementations:

INTERFACE IValveController
  METHOD Open : BOOL END_METHOD
  METHOD Close : BOOL END_METHOD
  PROPERTY State : STRING END_PROPERTY
END_INTERFACE

A class then implements the interface with IMPLEMENTS:

CLASS ValveControl IMPLEMENTS IValveController
  // ... methods, properties, plus IMPLEMENTS binding ...
END_CLASS

Consumers can declare variables of type IValveController and assign any class that implements it. This enables polymorphic dispatch. The OOP INTERFACE itself, like a class, must be declared in the unit's INTERFACE section to be visible to other units. The two meanings of "interface" remain independent:

Aspect ST Unit INTERFACE section OOP INTERFACE
Defined by IEC 61131-3 source organization IEC 61131-3 3rd edition OOP
Controls Unit symbol visibility Polymorphic class contract
Keyword INTERFACE ... END_INTERFACE INTERFACE ... END_INTERFACE
Can contain Any exportable declaration Only abstract methods and properties
Location Top of UNIT Inside INTERFACE or IMPLEMENTATION section

Both may coexist in the same unit. The OOP interface is itself an exportable type and follows the same visibility rules as a class — declare it in the unit INTERFACE if consumers need to reference it.

7. Compiler Diagnostics and Error Codes

When class visibility is misconfigured, the SIMOTION compiler reports specific errors. The exact wording varies by SCOUT version, but the canonical forms are:

Error Code Message Cause Resolution
F1101 Type 'X' is not exported by unit 'Y' Consuming unit references a class that is not in the source unit's INTERFACE Move the CLASS declaration to INTERFACE, recompile the source unit, then the consumer
F1102 Circular USES dependency detected Unit A uses B, B uses A (directly or transitively) Refactor: extract shared types into a third base unit
F1103 Duplicate type definition in USES chain Two imported units export the same type name Rename the class or use qualified references
W1104 USES statement shadows earlier import Two USES exports share a symbol name Qualify the reference or rename the symbol
F1140 Class 'X' cannot EXTENDS class 'Y' from a non-exported unit Parent class is local to its unit Export the parent class via INTERFACE

Always compile library units before their consumers. In multi-programmer projects, enforce a build order in the SCOUT project or in the CI pipeline to surface these errors early.

8. Best Practices for Class Organization in SIMOTION

Field-proven organization rules for SIMOTION ST libraries:

  1. One concept per unit. Combine a tightly-coupled set of classes (interface + concrete implementation + factory) in a single unit, exported together.
  2. Declare public API in INTERFACE, helpers in IMPLEMENTATION. Keep helper classes, internal types, and constants local to reduce coupling.
  3. Avoid deep USES chains. More than three levels of indirection causes compile-time slowdown and obscures the dependency graph.
  4. Use OOP interfaces for swappable behavior. When a class family (e.g., different valve types) shares a contract, define an OOP INTERFACE and have each variant implement it. Reference the interface in the consumer unit's INTERFACE section.
  5. Never place PROGRAMs in INTERFACE. Programs are top-level execution units and belong in the MCC chart or the program organization unit (POU) folder.
  6. Document the INTERFACE contract. Add a comment block above each exported class describing its lifecycle, threading model, and required initialization sequence.
  7. Version your library units. Add a VAR_GLOBAL CONSTANT block at the top of INTERFACE with a version identifier (e.g., c_LibVersion : STRING := '2.3.1';) so consumers can assert compatibility at compile time.

9. Verification: Confirming Class Export

After declaring a class in INTERFACE and adding a USES clause in the consumer, verify the export with these steps:

  1. In SIMOTION SCOUT, open the Project Navigator and select the library unit.
  2. Choose Compile > Check Consistency. The build should complete without F1101/F1140 errors.
  3. Open the consumer unit, place the cursor on a reference to the imported class, and press F2 (Go to definition). The IDE should jump to the exported class in the source unit's INTERFACE section. If it does not, the import failed.
  4. Open the Symbol Browser in the consumer unit and confirm the imported class appears with its full unit-qualified name (e.g., ValveControlLib.ValveControl).
  5. Cross-compile the device. If the runtime download succeeds, the visibility chain is intact.

For SIMOTION inside TIA Portal, the equivalent steps are: right-click the device > Compile > Software (rebuild), then inspect the Type tab in the program info to confirm the imported classes are listed.

10. Common Pitfalls and Edge Cases

Engineers learning SIMOTION OOP frequently encounter the following issues:

Forgetting the terminating period in END_UNIT. The compiler expects END_UNIT. with a period. A semicolon or no terminator produces a cryptic parse error and may mask the real visibility issue.

Mixing MCC and ST units. MCC charts cannot directly instantiate a class declared in an ST unit's IMPLEMENTATION section. Always export via INTERFACE if MCC or another ST unit needs to interact with the class.

Library upgrades breaking consumers. Adding a method to an exported class is binary-compatible. Removing or renaming an exported class is not. Document the INTERFACE surface as a public API and treat changes with semantic-versioning discipline.

Confusing unit INTERFACE with namespace. SIMOTION units are not C#-style namespaces. Two units may export symbols with the same name; the last USES wins unless qualified. Use descriptive class names to avoid collisions.

Confusing unit INTERFACE with OOP INTERFACE. Already covered, but it bears repeating: a class declared in a unit's IMPLEMENTATION section is not the same as a class implementing an OOP interface. The OOP interface itself is a class type and follows the same export rules as any other class.

11. Reference Resources

For further study, the canonical printed reference for SIMOTION OOP is:

  • Michael Braun, "Object-Oriented Programming with SIMOTION: Practical Introduction with Numerous Examples", Publicis MCD, ISBN 9783895784569. Chapter 4.5.5 covers "Interfaces as reference to classes"; chapter 4.5.7.2 covers the "ValveControl with Error Reporting" example (programming with interfaces).
  • IEC 61131-3:2013 (third edition), section 6.5.5 defines the OOP extensions including CLASS, INTERFACE, EXTENDS, IMPLEMENTS, and access specifiers.
  • Siemens SIMOTION SCOUT online help, topic "ST source file structure" and "USES statement".
  • Siemens SIMOTION programming and operating manual, entry ID 109751706 in the Siemens Industry Online Support portal.

FAQ

What is the difference between the INTERFACE and IMPLEMENTATION sections in a Simotion ST unit?

The INTERFACE section contains exported declarations (classes, function blocks, functions, types, variables with CONSTANT/RETAIN) that are visible to other units that include this unit via USES. The IMPLEMENTATION section contains local declarations visible only inside the unit. A class must be in INTERFACE to be instantiated, extended, or referenced from other units.

How does the USES statement enable a consumer unit to use an exported class?

A USES clause at the top of the consuming unit names the source unit (e.g., USES ValveControlLib). The compiler then makes all INTERFACE symbols of that unit, including classes, available for declaration, instantiation, and method calls. The IMPLEMENTATION symbols of the imported unit remain hidden regardless of USES.

Is the ST unit INTERFACE section the same as the OOP INTERFACE keyword?

No. The ST unit INTERFACE section is a source-organization construct that controls symbol export. The OOP INTERFACE is a class type containing only abstract methods and properties, used for polymorphic dispatch via IMPLEMENTS. Both share the keyword but serve different purposes; an OOP interface itself follows the same export rules as any class.

What compiler error appears if a class is referenced cross-unit without being in INTERFACE?

The compiler reports F1101 "Type 'X' is not exported by unit 'Y'" (or the localized equivalent). The fix is to move the CLASS declaration from IMPLEMENTATION to INTERFACE in the source unit, recompile it, and rebuild the consumer.

Can a class be instantiated by an MCC chart if it is only declared in IMPLEMENTATION?

No. MCC charts and other ST units can only reference classes that are exported via the source unit's INTERFACE section. Move the CLASS declaration to INTERFACE and recompile the library unit before attempting to use the class from MCC or a different ST source.

Where in the Michael Braun book is the canonical example for this topic?

Chapter 4.5.5 "Interfaces as reference to classes" and chapter 4.5.7.2 "ValveControl with Error Reporting" in "Object-Oriented Programming with SIMOTION" (Publicis MCD, ISBN 9783895784569) demonstrate class export via INTERFACE and the OOP interface contract.

Back to blog