Table of Contents
- Overview
- The core difference: where your variables live
- When to use each
- What else the strategy changes
- How to set it
- Summary
- Related articles
Audience: developers and build engineers configuring the Heirloom PL/I compiler. Explains the --strategy option, what it changes in the generated Java, and how to pick the right one for batch vs. online programs.
Overview
The compiler can emit two shapes of Java for the same PL/I program, selected with the --strategy option:
| Strategy | Flag | Typical use |
|---|---|---|
| Static (default) | --strategy static |
Batch programs with a main entry point |
| Instance | --strategy instance |
Online programs managed by an application server (CICS, MQ-triggered) |
Both produce a Java class per PL/I program and preserve your logic. The difference is how program state lives between invocations — and that difference matters the moment a program is called more than once in a running process, which is the norm for online (CICS/MQ) workloads.
Note:
--strategyis normally set once for a project in the build (for example inbuild.gradle), not per file. The default isstatic.
The core difference: where your variables live
PL/I's default storage class is AUTOMATIC — automatic variables are fresh for each activation of a procedure. The two strategies model that differently.
Static strategy
The program's variables become static fields on the class, and the program is entered through a static method:
public class P9npq04 {
private static Integer pos = 0; // class-level: one copy, shared
public static void invoke(Pointer ptr) {
P9npq04 _instance = new P9npq04();
_instance.p9npq04(); // pos is NOT reset between calls
}
}
Because the fields are static, their values persist across invocations in the same JVM. For a batch program that runs once and exits, that is fine. But if such a program is called repeatedly in a long-running process, stale values can leak from one call into the next — which violates PL/I's AUTOMATIC semantics.
Instance strategy
The program's variables become instance fields, and each invocation creates a fresh instance, then delegates to it:
public class P9da912 {
private Integer pos = 0; // per-instance: fresh each time
public static void invoke() {
P9da912 _instance = new P9da912();
_instance.p9da912(); // fresh state every call
}
}
Each invoke() builds a new object, so every activation starts with clean AUTOMATIC storage — exactly as on the host. Note that invoke() is still static, so callers reach the program the same way in both strategies; only the state model differs.
When to use each
Use static (the default) when:
- The program is a batch job with a
MAINprocedure that runs and exits. - The process is short-lived and the program is entered once.
Use instance when:
- The program runs inside a long-running application server and is invoked many times — CICS transactions and MQ-triggered programs are the common cases.
- A program is called repeatedly via the
invoke()pattern and must not carry state between calls.
A practical rule of thumb: online (CICS/MQ) → instance; batch → static. If a batch program is reused across invocations inside one process, prefer instance to avoid stale AUTOMATIC state.
What else the strategy changes
The strategy is not only about field placement; the compiler adjusts a few generated patterns to match.
Condition handlers carry an instance reference
ON-condition handlers (for example ON ENDFILE) must know which object to run against. In instance strategy the compiler passes the current instance (this) at registration, using a runtime overload that accepts it:
// Static strategy — register against the class
setConditionHandler(condition, MyProgram.class, "handler", snap);
// Instance strategy — register against the live instance
setConditionHandler(condition, MyProgram.class, this, "handler", snap);
If a program with ON handlers is compiled in the wrong strategy, handlers can fail to find their state at run time. Matching the strategy to the deployment avoids that.
Cross-program calls stay uniform
Even parameterless procedures keep a static invoke() wrapper in instance strategy, so other programs call them the same way regardless of strategy. The wrapper constructs the instance and delegates — callers never need to know which mode a callee was built with.
How to set it
Pass the option to the compiler (or set it in your build):
--strategy instance
Invalid values fall back to static with a warning. Combine it with the processing flags your programs need — for example --cics for online transaction programs or --sql for embedded SQL:
--strategy instance --cics --sql
Symptom to watch for: a batch-style program that "remembers" values it should not between runs in the same JVM is the classic sign of static strategy applied where instance was needed. Recompiling that program with
--strategy instancerestores fresh-per-activation behavior.
Summary
-
--strategychooses how program state lives between invocations: static (default, fields shared across calls) or instance (fresh object per call). - Static fits batch programs that run once; instance fits long-running online programs (CICS, MQ) invoked many times.
- Instance strategy matches PL/I AUTOMATIC semantics (fresh variables per activation) and wires
ON-condition handlers to the live instance. -
invoke()stays static in both modes, so callers are unaffected by a callee's strategy. - Set it once in the build; mismatched strategy shows up as stale state or misbehaving condition handlers.
Related articles
- How the Heirloom PL/I Compiler Translates Your Code — where strategy sits in the pipeline.
-
Reading Your Generated Java — the
invoke()and condition-handler patterns in context. - How Transactions Are Managed (ETP + PL/I Runtime) — how online programs are dispatched at run time.
- How to Configure and Deploy a Migrated CICS Application — deploying instance-strategy online programs.
0 Comments