Overcoming legacy PLC constraints with OOP lowering
How 2ot's HIR flattens interfaces, abstract methods and dynamic dispatch into flat function blocks — so modern, modular control code can still target rigid legacy hardware.
IEC 61131-3 has supported object-oriented features for years on paper, and grudgingly in practice. Older runtimes either reject inheritance outright, refuse dynamic dispatch, or surface the kind of cryptic error messages that send engineers back to flat function blocks within a week.
2ot takes a different stance: keep the modern source model. The Rust HIR understands interfaces, abstract methods and inheritance natively, and the OopLoweringContext flattens them into target-compliant artifacts before they ever touch the runtime.
What the engine sees
Every source file is parsed into a Knowledge Graph of KnowledgeGraphNode and KnowledgeGraphEdge elements. Semantic dependencies, physical addresses (%I, %Q), call hierarchies and data flows are all first-class. On top of that graph, OopBlock and OopInterface track the OOP structure as a separate, queryable layer.
How lowering happens
- Interfaces become vtable-like dispatch records, materialized as STRUCTs with function-pointer-equivalent fields.
- Abstract methods are resolved to their concrete implementations per call site, so the emitted code is fully monomorphic.
- Inheritance chains collapse into a single function block where parent state is inlined into the child's data section.
- Dynamic dispatch sites become static calls — the runtime never sees an indirect jump it cannot handle.
What the workflow keeps
The source model keeps the things modern languages are good at: composition, dependency injection at construction time, testable units with clear boundaries. The target backend handles the legacy constraints, so the same higher-level workflow does not need a rewrite whenever a more limited controller appears in the BOM.
Lowering is not a workaround; it is a contract. The HIR is the place modern abstractions live, and the target backend is the place they get translated into whatever shape the hardware demands. Move the abstraction up, move the constraint down, and the gap that has held back PLC code reuse for two decades quietly closes.