COBOL (ISO/IEC 1989:2023)
This assessment applies the coupling account — coupling as access to a shared resource, and the coupling floor [1], [2] — and the knowledge-embodiment theorem [3]; the language is assessed against its official reference [4].
1 Assessment
This page assesses COBOL in five parts: core coupling — what the language’s own constructs force; ecosystem coupling — what the surrounding platform, tooling, and community cost; engineering readiness — whether the artifact can be reproduced, verified, observed, worked in quickly, connected to other languages, and governed openly; the profile — the unscored facts a score cannot express; and the scoring detail — the mechanism marks and the arithmetic behind every score. A ✅ bullet marks a construct that helps. A ⚠️ or ❌ bullet marks a cost; the scoring model does not price every cost named here.
Core coupling 47/100 · Ecosystem coupling 54/100 · Engineering readiness 61/100
1.1 Core coupling
1.1.1 Type
- ❌ Typing is weak and static: A
PICTUREclause fixes an item’s shape, but aMOVEbetween items with different pictures converts the value silently, so the declared type does not protect it (T2) - ✅ The Data Division declares the shape once: Level numbers and
PICTUREstate each item’s size and category, and the Procedure Division uses that declaration without repeating it - ✅ Group items give a structured record: Level numbers nest elementary items inside groups, so a record layout is one declaration
- ✅ Fixed decimal arithmetic is exact:
COMP-3packed-decimal operations do not accumulate binary floating-point error, so the numeric representation matches monetary values - ⚠️
USAGEdecides the representation:COMP-3(packed decimal),COMP(binary), andDISPLAYdiffer, and a move between them converts without a type error - ⚠️ An alphanumeric item accepts any character string: An
X(n)item holds any text, so a category mistake is caught only by the program’s own checks
1.1.2 Construction
- ❌ Every data item is visible to every paragraph: A
WORKING-STORAGEitem can be read and modified from any procedure, and before COBOL-85 the language offered no way to restrict access to it (C1) - ✅ The four divisions separate concerns: Identification, Environment, Data, and Procedure give each declaration a fixed place, so data definition does not share a space with program logic
- ✅
CALL ... USINGpasses parameters to a subprogram: A called program receives its arguments explicitly, so a subprogram boundary is a declared interface - ✅
LOCAL-STORAGEgives per-call state: It is allocated for each invocation, so a re-entrant call does not share the state held inWORKING-STORAGE - ⚠️
PERFORM THRUnames a range of paragraphs and passes nothing: The called region is a text span and the performed code communicates only through shared data items, with no parameter list and no call stack - ⚠️
GO TOandALTERbreak structured flow: The language permits control transfers that obscure which paragraph runs next
1.1.3 Memory
- ✅ Ordinary program data needs no allocator:
WORKING-STORAGEandLOCAL-STORAGEcome from a declared layout, so a program that uses only them calls no allocator and no free - ✅ No garbage collector: Storage is fixed at compile time, so reclamation is deterministic and unobserved
- ✅
OCCURSdeclares fixed-size tables: The size of a table is known at compile time - ⚠️
OCCURS DEPENDING ONvaries a table’s length at run time: The logic then couples to the actual occurrence count - ⚠️
ALLOCATEandFREEput deallocation back on the programmer: The 2002 standard added dynamic allocation for tables and objects, and release is an explicit statement
1.1.4 Error
- ❌ Error handling has no structured path:
USE AFTER STANDARD ERRORand other declaratives are declared globally in theDECLARATIVESsection, and control may or may not return to the failing statement (Er1) - ✅ The declaratives section is separated from the main procedure: Recovery code is declared apart from the normal path
- ✅
FILE STATUSreports I/O results as data: A file’sFILE STATUSitem holds a two-character code that the program can test after each I/O statement - ✅
INVALID KEYandAT ENDput the failure case at the statement:READ ... INVALID KEY ... NOT INVALID KEYandAT ENDhandle the result inside the operation itself - ❌ An error need not terminate the program: A declarative can return control after a failure, so a caller cannot rely on termination
- ⚠️ No value carries the failure: There is no exception object and no result type, so detail travels only through shared items
1.1.5 Concurrency
- ✅ Concurrency belongs to the transaction monitor:
EXEC CICSand IMS link a program to a transaction environment instead of a language thread model - ✅ Batch steps are single-threaded by design: A batch program runs to completion without shared-memory concurrency
- ✅ The 2023 standard defines asynchronous messaging: ISO/IEC 1989:2023 adds asynchronous message handling and transaction processing, so a program need not hand-roll that loop
- ⚠️ The language has no threads or synchronisation primitives: Any parallel work couples the program to the monitor
- ⚠️ Shared
WORKING-STORAGEacross transactions needs external discipline: A pseudo-conversational program must reset its state between transactions
1.1.6 Platform
- ❌ A large share of production runs on IBM mainframes: Much COBOL executes on z/OS with IBM compilers, so practice is largely one vendor’s (P2)
- ✅ The language is an ISO standard: ISO/IEC 1989:2023 is the current edition, so the language is not owned by a single vendor
- ✅ GnuCOBOL is an independent compiler: It is an open-source project separate from GCC and translates COBOL to C
- ⚠️ Vendor extensions bind a program to a compiler:
EXEC CICS,EXEC SQL, and vendor libraries do not compile unchanged elsewhere - ⚠️ Newer standard features are unevenly implemented: The 2002 object-oriented features and the 2023 additions are not uniformly available across compilers
1.1.7 Trade-offs (not coupling)
- The small standard library is a scope decision: The standard specifies 43 statements, 87 functions, and one class, and adds no general-purpose library beyond them
- The fixed reference format comes from the punched card: Columns 1–6 hold a sequence number and column 7 an indicator, and free format is now permitted, so the old constraint is optional
- Mainframe batch orientation is a scope decision: COBOL assumes file and transaction processing in a monitor, which suits high-volume work and excludes systems programming
- The
PICTURE-driven fixed record suits flat files: The declared layout matches a fixed-length record, which is a modelling choice for the domain - The installed base is a business constraint: Retaining legacy programs is an organisational decision, not a property of the language
1.2 Ecosystem coupling
1.2.1 Performance
- ✅ Compiled ahead of time to native code: IBM Enterprise COBOL and GnuCOBOL (through generated C) produce machine code, so no interpreter and no JIT warm-up sits on the path
- ✅
USAGEselects the representation per item:COMP-3packs two digits per byte where compact storage matters - ✅ A batch step amortises start-up over millions of records: One run processes the whole job
- ⚠️ Tuning is platform-specific: IBM’s optimiser and GnuCOBOL produce different code, so a tuned program does not transfer unchanged
- ⚠️ Exact decimal arithmetic is slower than binary:
COMP-3operations cost more than native binary arithmetic
1.2.2 Ecosystem
- ❌ The ecosystem is legacy and vendor-fragmented: IBM, Micro Focus, and GnuCOBOL each supply their own compiler, runtime, and tooling (Ec3)
- ❌ The mainframe tooling is proprietary: The compilers, monitors, and debuggers are commercial products (Ec4)
- ✅ GnuCOBOL is open source and maintained: It gives the language a free compiler
- ✅ A long-lived body of documentation exists: The ISO standard and the vendor manuals are complete and stable over decades
- ✅ The deployed base is enormous: Gartner reported over 200 billion lines of COBOL in 1997, and the language remains among the most widely deployed
- ⚠️ The skills base is shrinking: Retirements reduce the pool of maintainers, a risk exposed by the COVID-era unemployment-systems crisis
1.2.3 Evolution
- ✅ The standard is backward compatible across decades: COBOL-74, -85, 2002, 2014, and 2023 code coexist, and programs written decades ago still compile
- ✅ ISO/IEC 1989:2023 added modern features: Asynchronous messaging, transaction processing, and dynamic-capacity tables join the language
- ⚠️ Revisions are infrequent: A new standard edition arrives at intervals of a decade or more, so a needed feature waits a long time
- ⚠️ Adoption of a new feature is uneven: A compiler may not implement a standard feature for years after publication
1.2.4 Domain
- ❌ Strong lock-in to mainframe transaction and batch processing: The language assumes fixed records, files, and a monitor runtime, so code carries that shape outside its home domain (D1)
- ✅ Superb for high-volume batch and transaction processing: The fit to financial and administrative workloads is close
- ✅ Still runs the bulk of card-payment background processing: The source reports COBOL behind most credit and debit-card swipe processing
- ✅ Fixed-point decimal arithmetic fits money: The data model matches monetary computation without floating-point error
- ⚠️ Poor for nearly everything else: Interactive, systems, and scientific work have little COBOL tooling
1.2.5 Learning
- ❌ The learning curve is steep in practice: Verbosity and over 300 reserved words must be learned (L1)
- ✅ The syntax is English-like:
MOVE A TO B,ADD ... GIVING,IF ... END-IF, andDISPLAYread close to prose - ✅ The division structure is a fixed learning path: Four divisions in a defined order give a predictable place for each declaration
- ⚠️ The vocabulary is large: More than 300 reserved words, and each verb carries many optional clauses
- ⚠️ The tooling is not beginner-friendly: Mainframe editors, JCL, and compile procedures are learned separately from the language
1.2.6 Syntax
- ❌ Verbose: Every statement names its verb and its operands, and paragraphs need explicit names (S1)
- ✅ English-like and self-describing: The verb names the operation, so a statement is readable without symbol decoding
- ✅
END-IF,END-PERFORM, andEND-READbound a scope: Explicit terminators remove the ambiguity of implicit scope - ⚠️ Fixed-format column rules still shape style: Column 7 is an indicator and the code sits in columns 8–72 in the classic reference format, and free format is an option
- ⚠️ The four-division prologue is long: Even a minimal program declares Identification, Environment, Data, and Procedure
1.2.7 Testing
- ✅
FILE STATUSandINVALID KEYgive checkable I/O outcomes: A test can assert on the status item after a file operation - ✅ Compilers supply tracing and dump facilities: IBM Debug Tool and GnuCOBOL’s runtime tracing report execution, and
COB_SET_TRACEenables a trace at run time - ✅ GnuCOBOL runs on ordinary workstations: The open-source compiler executes test jobs locally
- ⚠️ No test framework is in the language or the standard: A harness is external, so a suite couples to the tooling
- ⚠️ A batch test needs representative data: The job needs real files and JCL, not just a unit of code
1.2.8 Security
- ✅ Fixed
PICTUREsizes bound every item: An oversized source value is truncated or padded on assignment rather than overrunning a buffer - ✅ No pointers in the classic language: A COBOL program cannot forge an address
- ✅ The transaction monitor authorises access: CICS and RACF check a transaction’s resource use
- ⚠️ Truncation is silent: A value that does not fit an item is truncated without an error, so data can be lost quietly
- ⚠️ Dynamic SQL is injectable unless host variables are used:
EXEC SQLwith host variables is parameterised, but a statement built from a string re-opens SQL injection
1.3 Engineering readiness
1.3.1 Reproducibility
- ❌ Builds are not byte-reproducible by default.
- ❌ Dependencies resolve without a lock by default.
1.3.2 Supply chain
- ⚠️ Published packages carry no signed provenance by default.
1.3.3 Observability
- ⚠️ No stable tracing and metrics standard.
- ⚠️ The standard library has no structured logging.
1.3.4 Feedback
- ✅ No charged mechanism in this dimension.
1.3.5 Interop
- ⚠️ No maintained portable target.
1.3.6 Governance
- ✅ No charged mechanism in this dimension.
1.4 Profile
Unscored, and kept separate from every score on purpose. The profile records what a mechanism price cannot express: what a running program costs, how well a coding model and an agent work in the language, and whether a safety-critical path exists.
1.4.1 Energy and cost
What this axis asks: what does a running program cost in energy and time?
1.4.2 AI and agent readiness
What this axis asks: how well does a coding model and an agent work in this language?
- ❌ Sparse training data: models write it unreliably [8].
1.4.3 Safety certification
What this axis asks: is there a certified or standards-qualified path to a safety-critical system?
- ⚠️ No certified or standards-qualified path for safety-critical systems.
1.5 Scoring detail
1.5.1 Core coupling Dimensions
| Dimension | Mechanism | Description | Present | Cost |
|---|---|---|---|---|
| Type | T1 |
dynamic no static check | — | 0 |
T2 |
weak static | ✅ | −8 | |
T3 |
dynamic/duck dispatch | — | 0 | |
T4 |
no sum types | — | 0 | |
T5 |
no generics | — | 0 | |
T6 |
no namespaces | — | 0 | |
T7 |
type erasure/reflection | — | 0 | |
T8 |
operator overloading | — | 0 | |
T9 |
inheritance required for polymorphism | — | 0 | |
T10 |
no null-safety | — | 0 | |
T11 |
no module boundary | — | 0 | |
T12 |
no effect tracking | ✅ | −8 | |
T13 |
async/sync colouring | — | 0 | |
T14 |
unchecked foreign boundary | ✅ | −4 | |
| Type subtotal | −15 (−20) | |||
| Construction | C1 |
global mutable state by default | ✅ | −15 |
C2 |
no immutability by default | — | 0 | |
C3 |
constructors coupled to allocation | — | 0 | |
C4 |
no constructor/validation | — | 0 | |
| Construction subtotal | −15 | |||
| Memory | M1 |
manual deallocation | — | 0 |
M2 |
GC non-deterministic pauses | — | 0 | |
M3 |
no RAII | — | 0 | |
M4 |
no ownership model | — | 0 | |
| Memory subtotal | 0 | |||
| Error | Er1 |
no structured path | ✅ | −15 |
Er2 |
unchecked exceptions only | — | 0 | |
Er3 |
errors ignored/non-exhaustive | — | 0 | |
Er4 |
no composable result type | — | 0 | |
| Error subtotal | −15 | |||
| Concurrency | K1 |
GIL/no parallel | — | 0 |
K2 |
shared mutable state default | — | 0 | |
K3 |
manual sync no race detection | — | 0 | |
K4 |
no structured concurrency | — | 0 | |
K5 |
no primitives | — | 0 | |
| Concurrency subtotal | 0 | |||
| Platform | P1 |
cannot function outside one vendor/domain | — | 0 |
P2 |
single-vendor but other uses | ✅ | −8 | |
P3 |
legacy/discontinued platform | — | 0 | |
| Platform subtotal | −8 |
Core Dimensions score: 47/100 — total cost = −53 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).
1.5.2 Ecosystem coupling Dimensions
| Dimension | Mechanism | Description | Present | Cost |
|---|---|---|---|---|
| Performance | R1 |
interpreted no AOT/JIT | — | 0 |
R2 |
GC pauses | — | 0 | |
R3 |
JIT warmup | — | 0 | |
| Performance subtotal | 0 | |||
| Ecosystem | Ec1 |
no package manager | — | 0 |
Ec2 |
fragmented tooling | — | 0 | |
Ec3 |
small/niche/discontinued | ✅ | −8 | |
Ec4 |
proprietary | ✅ | −8 | |
Ec5 |
platform-locked tooling | — | 0 | |
Ec6 |
monoculture | — | 0 | |
Ec7 |
legacy burden | — | 0 | |
| Ecosystem subtotal | −15 (−16) | |||
| Evolution | V1 |
breaking changes | — | 0 |
V2 |
frozen | — | 0 | |
V3 |
discontinued | — | 0 | |
V4 |
glacial standards | — | 0 | |
| Evolution subtotal | 0 | |||
| Domain | D1 |
domain/vendor lock-in | ✅ | −15 |
D2 |
poor domain fit | — | 0 | |
D3 |
framework forces architecture | — | 0 | |
| Domain subtotal | −15 | |||
| Learning | L1 |
steep | ✅ | −8 |
L2 |
large surface/multi-paradigm | — | 0 | |
L3 |
sparse docs | — | 0 | |
| Learning subtotal | −8 | |||
| Syntax | S1 |
verbose | ✅ | −8 |
S2 |
inconsistent | — | 0 | |
S3 |
punctuation-heavy | — | 0 | |
| Syntax subtotal | −8 | |||
| Testing | G1 |
weak tooling | — | 0 |
G2 |
poor debugging | — | 0 | |
G3 |
runtime-only errors | — | 0 | |
| Testing subtotal | 0 | |||
| Security | Q1 |
memory-unsafe | — | 0 |
Q2 |
dynamic/weak typing risk | — | 0 | |
Q3 |
known vulnerability/injection | — | 0 | |
| Security subtotal | 0 |
Meta Dimensions score: 54/100 — total cost = −46 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).
1.5.3 Engineering readiness Dimensions
| Dimension | Mechanism | Description | Present | Cost |
|---|---|---|---|---|
| Reproducibility | Y1 |
build not reproducible | ✅ | −8 |
Y2 |
dependencies not pinned | ✅ | −8 | |
| Reproducibility subtotal | −15 (−16) | |||
| Supply chain | Y3 |
no signed provenance | ✅ | −8 |
Y4 |
registry without namespacing | — | 0 | |
| Supply chain subtotal | −8 | |||
| Observability | Y5 |
no stable tracing standard | ✅ | −8 |
Y6 |
no structured logging | ✅ | −4 | |
| Observability subtotal | −12 | |||
| Feedback | Y7 |
slow build | — | 0 |
Y8 |
no fast in-editor analysis | — | 0 | |
| Feedback subtotal | 0 | |||
| Interop | Y9 |
no foreign-function interface | — | 0 |
Y10 |
no portable target | ✅ | −4 | |
| Interop subtotal | −4 | |||
| Governance | Y11 |
single-vendor governance | — | 0 |
Y12 |
closed specification | — | 0 | |
| Governance subtotal | 0 |
Readiness Dimensions score: 61/100 — total cost = −39 (per-dimension subtotals are capped at −15; an uncapped cost is shown in parentheses where the cap bites).
Verdict: COBOL’s two scores are deliberately even: its own constructs impose about as much coupling as its platform and ecosystem do. The four divisions and the PICTURE clause declare a record once, CALL ... USING gives a subprogram an explicit parameter interface, and LOCAL-STORAGE gives per-call state, but the default visibility of every data item to every paragraph, the paragraph-range semantics of PERFORM THRU, and error handling by declaratives that may not terminate the program make global coupling the norm. The platform side is legacy, vendor-fragmented, and locked to mainframe transaction processing, with a shrinking skills base. Inside high-volume batch and transaction processing COBOL is excellent; outside that niche the fit is poor.
The formal development. The definitions, theorems, and proofs behind this page are published in:
- On the Nature of Coupling: All Coupling as Shared Resource Access — Zenodo, 2026 — doi:10.5281/zenodo.21925122
- Coupling as a Consequence of Cohesion: Decomposition, the Coupling Floor, and Domain-Imposed Coupling — Zenodo, 2026 — doi:10.5281/zenodo.21925201
- On the Nature of Cohesion: Cohesion as Correctness Relative to a Partitioning Rule — Zenodo, 2026 — doi:10.5281/zenodo.21703193