PL/I (Programming Language One, pronounced and sometimes written PL/1) is a procedural, imperative computer programming language initially developed by IBM. It is designed for scientific, engineering, business and system programming. It has been in continuous use by academic, commercial and industrial organizations since it was introduced in the 1960s.
A PL/I American National Standards Institute (ANSI) technical standard, X3.53-1976, was published in 1976.
PL/I's main domains are data processing, numerical computation, scientific computing, and system programming. It supports recursion, structured programming, linked data structure handling, fixed-point, floating-point, complex, character string handling, and bit string handling. The language syntax is English-like and suited for describing complex data formats with a wide set of functions available to verify and manipulate them.
Early history
In the 1950s and early 1960s, business and scientific users programmed using different programming languages, usually on different computer hardware. Business users were moving from Autocoders via COMTRAN to COBOL, while scientific users programmed in Fortran, ALGOL, GEORGE, and others. The IBM System/360 (announced in 1964 and delivered in 1966) was designed as a common machine architecture for both groups of users, superseding all existing IBM architectures. Similarly, IBM wanted a single programming language for all users. It hoped that Fortran could be extended to include the features needed by commercial programmers. In October 1963 a committee was formed composed originally of three IBMers from New York and three members of SHARE, the IBM
scientific users group, to propose these extensions to Fortran. Given the constraints of Fortran, they were unable to do this and embarked on the design of a new programming language based loosely on ALGOL labeled NPL. This acronym conflicted with that of the UK's National Physical Laboratory and was replaced briefly by MPPL (MultiPurpose Programming Language) and, in 1965, with PL/I (with a Roman numeral "I"). The first definition appeared in April 1964.
IBM took NPL as a starting point and completed the design to a level that the first compiler could be written: the NPL definition was incomplete in scope and in detail. Control of the PL/I language was vested initially in the New York Programming Center and later at the IBM UK Laboratory at Hursley. The SHARE and GUIDE user groups were involved in extending the language and had a role in IBM's process for controlling the language through their PL/I Projects. The experience of defining such a large language showed the need for a formal definition of PL/I. A project was set up in 1967 in IBM Laboratory Vienna to make an unambiguous and complete specification. This led in turn to one of the first large scale Formal Methods for development, VDM.
Fred Brooks is credited with ensuring PL/I had the CHARACTER data type. Christopher J. Date and a colleague added relational database extensions based on Edgar Codd's work.
The language was first specified in detail in the manual "PL/I Language Specifications. C28-6571", written in New York in 1965, and superseded by "PL/I Language Specifications. GY33-6003", written by Hursley in 1967. IBM continued to develop PL/I in the late sixties and early seventies, publishing it in the GY33-6003 manual. These manuals were used by the Multics group and other early implementers.
The first compiler was delivered in 1966. The Standard for PL/I was approved in 1976.
Goals and principles
The goals for PL/I evolved during the early development of the language. Competitiveness with COBOL's record handling and report writing was required. The language's scope of usefulness grew to include system programming and event-driven programming. Additional goals for PL/I were:
- Orthogonality: each capability to be independent of other capabilities and freely combined with other capabilities wherever meaningful. Each capability to be available in all contexts where meaningful, to exploit it as widely as possible and to avoid "arbitrary restrictions". Orthogonality helps make the language "large".
- Exception handling capabilities for controlling and intercepting exceptional conditions at run time.
- Programs divided into separately compilable sections, with extensive compile-time facilities (a.k.a. macros), not part of the standard, for tailoring and combining sections of source code into complete programs. External names to bind separately compiled procedures into a single program.
- Debugging facilities integrated into the language.
Language summary
The language is designed to provide sufficient facilities to be able to satisfy the needs of all programmers, regardless of what problems the language is being applied to. The summary is extracted from the ANSI PL/I Standard
and the ANSI PL/I General-Purpose Subset Standard. Standardization became a joint effort of ECMA TC/10 and ANSI X3J1. A subset of the GY33-6003 document was offered to the joint effort by IBM and became the base document for standardization. The major features omitted from the base document were multitasking and the attributes for program optimization (e.g., <code>NORMAL</code> and <code>ABNORMAL</code>).
Proposals to change the base document were voted upon by both committees. In the event that the committees disagreed, the chairs, initially Michael Marcotty of General Motors and C.A.R. Hoare representing ICL had to resolve the disagreement. In addition to IBM, Honeywell, CDC, Data General, Digital Equipment Corporation, Prime Computer, Burroughs, RCA, and Univac served on X3J1 along with major users Eastman Kodak, MITRE, Union Carbide, Bell Laboratories, and various government and university representatives. Further development of the language occurred in the standards bodies, with continuing improvements in structured programming and internal consistency, and with the omission of the more obscure or contentious features.
As language development neared an end, X3J1/TC10 realized that there were a number of problems with a document written in English text. Discussion of a single item might appear in multiple places which might or might not agree. It was difficult to determine if there were omissions as well as inconsistencies. Consequently, David Beech (IBM), Robert Freiburghouse (Honeywell), Milton Barber (CDC), M. Donald MacLaren (Argonne National Laboratory), Craig Franklin (Data General), Lois Frampton (Digital Equipment Corporation), and editor, D.J. Andrews of IBM undertook to rewrite the entire document, each producing one or more complete chapters. The standard is couched as a formal definition to specify the semantics. It was the first programming language standard to be written as a semi-formal definition.
A "PL/I General-Purpose Subset" ("Subset-G") standard was issued by ANSI in 1981 and a revision published in 1987. The General Purpose subset was widely adopted as the kernel for PL/I implementations.
Implementations
IBM PL/I F and D compilers
PL/I was first implemented by IBM, at its Hursley Laboratories in the United Kingdom, as part of the development of System/360. The first production PL/I compiler was the PL/I F compiler for the OS/360 Operating System, built by John Nash's team at Hursley in the UK: the runtime library team was managed by I.M. (Nobby) Clarke. The PL/I F compiler was written entirely in System/360 assembly language. Release 1 shipped in 1966. OS/360 is a real-memory environment and the compiler was designed for systems with as little as 64 kilobytes of real storage – F being 64 kB in S/360 parlance. To fit a large compiler into the 44 kilobytes of memory available on a 64-kilobyte machine, the compiler consists of a control phase and a large number of compiler phases (approaching 100). The phases are brought into memory from disk, one at a time, to handle particular language features and aspects of compilation. Each phase makes a single pass over the partially-compiled program, usually held in memory.
Aspects of the language were still being designed as PL/I F was implemented, so some were omitted until later releases. PL/I RECORD I/O was shipped with PL/I F Release 2. The list processing functions Based Variables, Pointers, Areas and Offsets and LOCATE-mode I/O were first shipped in Release 4. In a major attempt to speed up PL/I code to compete with Fortran object code, PL/I F Release 5 does substantial program optimization of DO-loops facilitated by the REORDER option on procedures.
A version of PL/I F was released on the TSS/360 timesharing operating system for the System/360 Model 67, adapted at the IBM Mohansic Lab. The IBM La Gaude Lab in France developed "Language Conversion Programs" to convert Fortran, Cobol, and Algol programs to the PL/I F level of PL/I.
The PL/I D compiler, using 16 kilobytes of memory, was developed by IBM Germany for the DOS/360 low end operating system. It implements a subset of the PL/I language requiring all strings and arrays to have fixed extents, thus simplifying the run-time environment. Reflecting the underlying operating system, it lacks dynamic storage allocation and the controlled storage class. It was shipped within a year of PL/I F.
Multics PL/I and derivatives
Compilers were implemented by several groups in the early 1960s. The Multics project at MIT, one of the first to develop an operating system in a high-level language, used Early PL/I (EPL), a subset dialect of PL/I, as their implementation language in 1964. EPL was developed at Bell Labs and MIT by Douglas McIlroy, Robert Morris, and others. The influential Multics PL/I compiler [sic "PL/1"] was the source of compiler technology used by a number of manufacturers and software groups. EPL was a system programming language and a dialect of PL/I that had some capabilities absent in the original PL/I.
The Honeywell PL/I compiler (for Series 60) is an implementation of the full ANSI X3J1 standard.
IBM PL/I optimizing and checkout compilers
The PL/I Optimizer and Checkout compilers produced in Hursley support a common level of PL/I language and aimed to replace the PL/I F compiler. The checkout compiler is a rewrite of PL/I F in BSL, IBM's PL/I-like proprietary implementation language (later PL/S). (colloquially "The Checker") announced in August 1970 was designed to speed and improve the debugging of PL/I programs. The team was led by Brian Marks. The three-pass design cut the time to compile a program to 25% of that taken by the F Compiler. It can be run from an interactive terminal, converting PL/I programs into an internal format, "H-text". This format is interpreted by the Checkout compiler at run-time, detecting virtually all types of errors. Pointers are represented in 16 bytes, containing the target address and a description of the referenced item, thus permitting "bad" pointer use to be diagnosed. In a conversational environment when an error is detected, control is passed to the user who can inspect any variables, introduce debugging statements and edit the source program. Over time the debugging capability of mainframe programming environments developed most of the functions offered by this compiler and it was withdrawn (in the 1990s?)
DEC PL/I
Perhaps the most commercially successful implementation aside from IBM's was Digital Equipment Corporation's VAX-11 PL/I, later known as VAX PL/I, then DEC PL/I. The implementation is "a strict superset of the ANSI X3.4-1981 PL/I General Purpose Subset and provides most of the features of the new ANSI X3.74-1987 PL/I General Purpose Subset", and was first released in 1980. It originally used a compiler backend named the VAX Code Generator (VCG) created by a team led by Dave Cutler. The front end was designed by Robert Freiburghouse, and was ported to VAX/VMS from Multics. It runs on VMS on VAX and Alpha, and on Tru64. During the 1990s, Digital sold the compiler to UniPrise Systems, who later sold it to a company named Kednos. Kednos marketed the compiler as Kednos PL/I until October 2016 when the company ceased trading.
Teaching subset compilers
In the late 1960s and early 1970s, many US and Canadian universities were establishing time-sharing services on campus and needed conversational compiler/interpreters for use in teaching science, mathematics, engineering, and computer science. Dartmouth was developing BASIC, but PL/I was a popular choice, as it was concise and easy to teach. As the IBM offerings were unsuitable, a number of schools built their own subsets of PL/I and their own interactive support. Examples are:
In the 1960s and early 1970s, Allen-Babcock implemented the Remote Users of Shared Hardware (RUSH) time sharing system for an IBM System/360 Model 50 with custom microcode and subsequently implemented IBM's CPS, an interactive time-sharing system for OS/360 aimed at teaching computer science basics, offered a limited subset of the PL/I language in addition to BASIC and a remote job entry facility.
PL/C, a dialect for teaching, a compiler developed at Cornell University, had the unusual capability of never failing to compile any program through the use of extensive automatic correction of many syntax errors and by converting any remaining syntax errors to output statements. The language was almost all of PL/I as implemented by IBM. PL/C was a very fast compiler.
(Student Language/1, Student Language/One or Subset Language/1) was a PL/I subset, initially available late 1960s, that ran interpretively on the IBM 1130; instructional use was its strong point.
PLAGO, created at the Polytechnic Institute of Brooklyn, used a simplified subset of the PL/I language and focused on good diagnostic error messages and fast compilation times.
The Computer Systems Research Group of the University of Toronto produced the SP/k compilers which supported a sequence of subsets of PL/I called SP/1, SP/2, SP/3, ..., SP/8 for teaching programming. Programs that ran without errors under the SP/k compilers produced the same results under other contemporary PL/I compilers such as IBM's PL/I F compiler, IBM's checkout compiler or Cornell University's PL/C compiler.
Other examples are PL0 by P. Grouse at the University of New South Wales, PLUM by Marvin Victor Zelkowitz at the University of Maryland, and PLUTO from the University of Toronto.
IBM PL/I for OS/2, AIX, Linux, z/OS
In a major revamp of PL/I, IBM Santa Teresa in California launched an entirely new compiler in 1992. The initial shipment was for OS/2 and included most ANSI-G features and many new PL/I features. Subsequent releases provided additional platforms (MVS, VM, OS/390, AIX and Windows), but as of 2021, the only supported platforms are z/OS and AIX. IBM continued to add functions to make PL/I fully competitive with other languages (particularly C and C++) in areas where it had been overtaken. The corresponding "IBM Language Environment" supports inter-operation of PL/I programs with Database and Transaction systems, and with programs written in C, C++, and COBOL, the compiler supports all the data types needed for intercommunication with these languages.
The PL/I design principles were retained and withstood this major extension, comprising several new data types, new statements and statement options, new exception conditions, and new organisations of program source. The resulting language is a compatible super-set of the PL/I Standard and of the earlier IBM compilers. Major topics added to PL/I were:
- New attributes for better support of user-defined data types – the <code>DEFINE ALIAS</code>, <code>ORDINAL</code>, and <code>DEFINE STRUCTURE</code> statement to introduce user-defined types, the <code>HANDLE</code> locator data type, the <code>TYPE</code> data type itself, the <code>UNION</code> data type, and built-in functions for manipulating the new types.
- Type functions, roughly analogous to builtin class methods.
- Additional data types and attributes corresponding to common PC data types (e.g., <code>UNSIGNED</code>, <code>VARYINGZ</code>).
- Improvements in readability of programs – often rendering implied usages explicit (e.g., <code>BYVALUE</code> attribute for parameters)
- Additional structured programming constructs.
- Interrupt handling additions.
- Compile time preprocessor extended to offer almost all PL/I string handling features and to interface with the Application Development Environment
The latest series of PL/I compilers for z/OS, called Enterprise PL/I for z/OS, leverage code generation for the latest z/Architecture processors (z14, z13, zEC12, zBC12, z196, z114) via the use of ARCHLVL parm control passed during compilation, and was the second high-level language supported by z/OS Language Environment to do so (XL C/C++ being the first, and Enterprise COBOL v5 the last.)
Data types
is a new computational data type. The ordinal facilities are like those in Pascal,
e.g.,
but in addition the name and internal values are accessible via built-in functions. Built-in functions provide access to an ordinal value's predecessor and successor. The <code>FIRST</code> and <code>LAST</code> type functions provide access to an ordinal set's range.
The -statement (see below) allows additional s to be declared composed from PL/I's built-in attributes.
The <code>HANDLE(data structure)</code> locator data type is similar to the data type, but strongly typed to bind only to a particular data structure. The <code>=></code> operator is used to select a data structure using a handle.
The attribute (equivalent to in early PL/I specifications) permits several scalar variables, arrays, or structures to share the same storage in a unit that occupies the amount of storage needed for the largest alternative.
Competitiveness on PC and with C
These attributes were added:
- The string attributes <code>VARYINGZ</code> (for zero-terminated character strings), <code>HEXADEC</code>, <code>WIDECHAR</code>, and <code>GRAPHIC</code>.
- The optional arithmetic attributes <code>UNSIGNED</code> and <code>SIGNED</code>, <code>BIGENDIAN</code> and <code>LITTLEENDIAN</code>. <code>UNSIGNED</code> necessitated the <code>UPTHRU</code> and <code>DOWNTHRU</code> option on iterative groups enabling a counter-controlled loop to be executed without exceeding the limit value (also essential for <code>ORDINAL</code>s and good for documenting loops).
- The <code>DATE(pattern)</code> attribute for controlling date representations and additions to bring time and date to best current practice. New functions for manipulating dates include <code>DAYS</code> and <code>DAYSTODATE</code> for converting between dates and number of days, and a general <code>DATETIME</code> function for changing date formats.
New string-handling functions were added to centre text, to edit using a picture format, and to trim blanks or selected characters from the head or tail of text, <code>VERIFYR</code> to <code>VERIFY</code> from the right. and <code>SEARCH</code> and <code>TALLY</code> functions.
Compound assignment operators a la C e.g., <code>+=</code>, <code>&=</code>, <code>-=</code>, <code>||=</code> were added. <code>A+=1</code> is equivalent to <code>A=A+1</code>.
Additional parameter descriptors and attributes were added for omitted arguments and variable length argument lists.
Program readability – making intentions explicit
The attribute declares an identifier as a constant (derived from a specific literal value or restricted expression).
Parameters can have the (pass by address) or (pass by value) attributes.
The and attributes prevent unintended assignments.
<code>DO FOREVER;</code> obviates the need for the contrived construct .
The -statement introduces user-specified names (e.g., ) for combinations of built-in attributes (e.g., <code>FIXED BINARY(31,0)</code>). Thus <code>DEFINE ALIAS INTEGER FIXED BINARY(31.0)</code> creates the name as an alias for the set of built-in attributes FIXED BINARY(31.0). <code>DEFINE STRUCTURE</code> applies to structures and their members; it provides a name for a set of structure attributes and corresponding substructure member declarations for use in a structure declaration (a generalisation of the attribute).
Structured programming additions
A statement to exit a loop, and an to continue with the next iteration of a loop.
and options on iterative groups.
The package construct consisting of a set of procedures and declarations for use as a unit. Variables declared outside of the procedures are local to the package, and can use , or storage. Procedure names used in the package also are local, but can be made external by means of the option of the -statement.
Interrupt handling
The -statement executed in an ON-unit terminates execution of the ON-unit, and raises the condition again in the procedure that called the current one (thus passing control to the corresponding ON-unit for that procedure).
The condition handles invalid operation codes detected by the PC processor, as well as illegal arithmetic operations such as subtraction of two infinite values.
The condition is provided to intercept conditions for which no specific ON-unit has been provided in the current procedure.
The condition is raised when an statement is unable to obtain sufficient storage.
Other mainframe and minicomputer compilers
A number of vendors produced compilers to compete with IBM PL/I F or Optimizing compiler on mainframes and minicomputers in the 1970s. In the 1980s the target was usually the emerging ANSI-G subset.
- In 1974 Burroughs Corporation announced PL/I for the B6700 and B7700.
- UNIVAC released a UNIVAC PL/I, and in the 1970s also used a variant of PL/I, PL/I PLUS, for system programming.
- From 1978 Data General provided PL/I on its Eclipse and Eclipse MV platforms running the AOS, AOS/VS & AOS/VS II operating systems. A number of operating system utility programs were written in the language.
- Paul Abrahams of NYU's Courant Institute of Mathematical Sciences wrote CIMS PL/I in 1972 in PL/I, bootstrapping via PL/I F. It supported "about 70%" of PL/I compiling to the CDC 6600
- CDC delivered an optimizing subset PL/I compiler for Cyber 70, 170 and 6000 series.
- Fujitsu delivered a PL/I compiler equivalent to the PL/I Optimizer.
- Stratus Technologies PL/I is an ANSI G implementation for the VOS operating system.
- IBM Series/1 PL/I is an extended subset of ANSI Programming Language PL/I (ANSI X3.53-1976) for the IBM Series/1 Realtime Programming System.
PL/I compilers for Microsoft .NET
- In 2011, Raincode designed a full legacy compiler for the Microsoft .NET and .NET Core platforms, named The Raincode PL/I compiler.
PL/I compilers for personal computers and Unix
- In the 1970s and 1980s Digital Research sold a PL/I compiler for CP/M (PL/I-80), CP/M-86 (PL/I-86) and IBM PC compatibles with MS-DOS or IBM PC DOS.<!-- PLI-86 -->. It was based on Subset G of PL/I and UNIX/Linux systems, which they acquired from Liant.
- IBM delivered PL/I for OS/2
- Iron Spring PL/I for OS/2 and later Linux was introduced in 2007.
- GCC (pl1gcc) front end; the project's last release was in September 2007.
PL/I dialects
- PL/S, a dialect of PL/I, initially called BSL was developed in the late 1960s and became the system programming language for IBM mainframes. Almost all IBM mainframe system software in the 1970s and 1980s was written in PL/S. It differed from PL/I in that there were no data type conversions, no run-time environment, structures were mapped differently, and assignment was a byte by byte copy. All strings and arrays had fixed extents, or used the <code>REFER</code> option. PL/S was succeeded by PL/AS, and then by PL/X, which is the language currently used for internal work on current operating systems, OS/390 and now z/OS. It is also used for some z/VSE and z/VM components. IBM Db2 for z/OS is also written in PL/X.
- PL/C, is an instructional dialect of the PL/I computer programming language, developed at Cornell University in the 1970s.
- Two dialects of PL/I named PL/MP (Machine Product) and PL/MI (Machine Interface) were used by IBM in the system software of the System/38 and AS/400 platforms. PL/MP was used to implement the so-called Vertical Microcode of these platforms, and targeted the IMPI instruction set. PL/MI targets the Machine Interface of those platforms, and is used in the System/38 Control Program Facility, and the XPF layer of OS/400. The PL/MP code was mostly replaced with C++ when OS/400 was ported to the IBM RS64 processor family, although some was retained and retargeted for the PowerPC/Power ISA architecture. The PL/MI code was not replaced, and remains in use in IBM i.
- PL.8, so-called because it was about 80% of PL/I, was originally developed by IBM Research in the 1970s for the IBM 801 architecture. It later gained support for the Motorola 68000 and System/370 architectures. It continues to be used for several IBM internal systems development tasks (e.g., millicode and firmware for z/Architecture systems) and has been re-engineered to use a 64-bit gcc-based backend.
- Honeywell, Inc. developed PL-6 for use in creating the CP-6 operating system.
- Prime Computer used two different PL/I dialects as system programming languages for the PRIMOS operating system: PL/P, starting from version 18, and then SP/L, starting from version 19.
- XPL is a dialect of PL/I used to write other compilers using the XPL compiler techniques. XPL added a heap string datatype to its small subset of PL/I.
- HAL/S is a real-time aerospace programming language, best known for its use in the Space Shuttle program. It was designed by Intermetrics in the 1970s for NASA. HAL/S was implemented in XPL.
- IBM and various subcontractors also developed another PL/I variant in the early 1970s to support signal processing for the Navy called SPL/I.
- SabreTalk, a real-time dialect of PL/I used to program the Sabre airline reservation system.
- Apple, a PL/I dialect developed by General Motors Research Laboratories for their Control Data Corporation STAR-100 supercomputer, used extensively for graphic design.
Usage
PL/I implementations were developed for mainframes from the late 1960s, mini computers in the 1970s, and personal computers and for system use for writing operating systems on certain platforms. Very complex and powerful systems have been built with PL/I:
- The SAS System was initially written in PL/I; the SAS data step is still modeled on PL/I syntax.
- The pioneering online airline reservation system Sabre was originally written for the IBM 7090 in assembler. The S/360 version was largely written using SabreTalk, a purpose-built subset PL/I compiler for a dedicated control program.
- The Multics operating system was largely written in PL/I.
- PL/I was used to write an executable formal definition to interpret IBM's System Network Architecture.
- Some components of the OpenVMS operating system were originally written in PL/I, but were later rewritten in C during the port of VMS to the IA-64 architecture.
PL/I did not fulfill its supporters' hopes that it would displace Fortran and COBOL and become the major player on mainframes. It remained a minority but significant player. There cannot be a definitive explanation for this, but some trends in the 1970s and 1980s militated against its success by progressively reducing the territory on which PL/I enjoyed a competitive advantage.
First, the nature of the mainframe software environment changed. Application subsystems for database and transaction processing (CICS and IMS and Oracle on System 370) and application generators became the focus of mainframe users' application development. Significant parts of the language became irrelevant because of the need to use the corresponding native features of the subsystems (such as tasking and much of input/output). Fortran was not used in these application areas, confining PL/I to COBOL's territory; most users stayed with COBOL. But as the PC became the dominant environment for program development, Fortran, COBOL and PL/I all became minority languages overtaken by C++, Java and the like.
Second, PL/I was overtaken in the system programming field. The IBM system programming community was not ready to use PL/I; instead, IBM developed and adopted a proprietary dialect of PL/I for system programming. – PL/S. With the success of PL/S inside IBM, and of C outside IBM, the unique PL/I strengths for system programming became less valuable.
Third, the development environments grew capabilities for interactive software development that, again, made the unique PL/I interactive and debugging strengths less valuable.
Fourth, features such as structured programming, character string operations, and object orientation were added to COBOL and Fortran, which further reduced PL/I's relative advantages.
On mainframes there were substantial business issues at stake too. IBM's hardware competitors had little to gain and much to lose from success of PL/I. Compiler development was expensive, and the IBM compiler groups had an in-built competitive advantage. Many IBM users wished to avoid being locked into proprietary solutions. With no early support for PL/I by other vendors it was best to avoid PL/I.
Evolution of the PL/I language
This article uses the PL/I standard as the reference point for language features. But a number of features of significance in the early implementations were not in the Standard; and some were offered by non-IBM compilers. And the de facto language continued to grow after the standard, ultimately driven by developments on the Personal Computer.
Significant features omitted from the standard
Multithreading
Multithreading, under the name "multitasking", was implemented by PL/I F, the PL/I Checkout and Optimizing compilers, and the newer AIX and Z/OS compilers. It comprised the data types and , the -option on the -statement (Fork), the -statement (Join), the <code>DELAY(delay-time)</code>, -options on the record I/O statements and the statement to unlock locked records on files. Event data identify a particular event and indicate whether it is complete ('1'B) or incomplete ('0'B): task data items identify a particular task (or process) and indicate its priority relative to other tasks.
Preprocessor
The first IBM Compile time preprocessor was built by the IBM Boston Advanced Programming Center located in Cambridge, Mass, and shipped with the PL/I F compiler. The <code>%INCLUDE</code> statement was in the Standard, but the rest of the features were not. The DEC and Kednos
Debug facilities
PL/I F had offered some debug facilities that were not put forward for the standard but were implemented by others notably the CHECK(variable-list) condition prefix, <code>CHECK</code> on-condition and the <code>SNAP</code> option. The IBM Optimizing and Checkout compilers added additional features appropriate to the conversational mainframe programming environment (e.g., an <code>ATTENTION</code> condition).
Significant features developed since the standard
Several attempts had been made to design a structure member type that could have one of several datatypes (<code>CELL</code> in early IBM). With the growth of classes in programming theory, approaches to this became possible on a PL/I base <code>UNION</code>, <code>TYPE</code> etc. have been added by several compilers.
PL/I had been conceived in a single-byte character world. With support for Japanese and Chinese language becoming essential, and the developments on International Code Pages, the character string concept was expanded to accommodate wide non-ASCII/EBCDIC strings.
Time and date handling were overhauled to deal with the millennium problem, with the introduction of the DATETIME function that returned the date and time in one of about 35 different formats. Several other date functions deal with conversions to and from days and seconds.
Criticisms
Implementation issues
Though the language is easy to learn and use, implementing a PL/I compiler is difficult and time-consuming. A language as large as PL/I needed subsets that most vendors could produce and most users master. This was not resolved until "ANSI G" was published. The compile time facilities, unique to PL/I, took added implementation effort and additional compiler passes. A PL/I compiler was two to four times as large as comparable Fortran or COBOL compilers, and also that much slower—supposedly offset by gains in programmer productivity. This was anticipated in IBM before the first compilers were written. The PL/I keywords are not reserved so programmers can use them as variable or procedure names in programs. Because the original PL/I(F) compiler attempts auto-correction when it encounters a keyword used in an incorrect context, it often assumes it is a variable name. This leads to "cascading diagnostics", a problem solved by later compilers.
The effort needed to produce good object code was perhaps underestimated during the initial design of the language. Program optimization (needed to compete with the excellent program optimization carried out by available Fortran compilers) is unusually complex owing to side effects and pervasive problems with aliasing of variables. Unpredictable modification can occur asynchronously in exception handlers, which may be provided by " statements" in (unseen) callers. Together, these make it difficult to reliably predict when a program's variables might be modified at runtime. In typical use, however, user-written error handlers (the -unit) often do not make assignments to variables. In spite of the aforementioned difficulties, IBM produced the PL/I Optimizing Compiler in 1971.
PL/I contains many rarely used features, such as multitasking support (an IBM extension to the language) which add cost and complexity to the compiler, and its co-processing facilities require a multi-programming environment with support for non-blocking multiple threads for processes by the operating system. Compiler writers were free to select whether to implement these features.
An undeclared variable is, by default, declared by first occurrence—thus misspelling might lead to unpredictable results. This "implicit declaration" is no different from FORTRAN programs. For PL/I(F), however, an attribute listing enables the programmer to detect any misspelled or undeclared variable.
Programmer issues
Many programmers were slow to move from COBOL or Fortran due to a perceived complexity of the language and immaturity of the PL/I F compiler. Programmers were sharply divided into scientific programmers (who used Fortran) and business programmers (who used COBOL), with significant tension and even dislike between the groups. PL/I syntax borrowed from both COBOL and Fortran syntax. So instead of noticing features that would make their job easier, Fortran programmers of the time noticed COBOL syntax and had the opinion that it was a business language, while COBOL programmers noticed Fortran syntax and looked upon it as a scientific language.
Both COBOL and Fortran programmers viewed it as a "bigger" version of their own language, and both were somewhat intimidated by the language and disinclined to adopt it. Another factor was pseudo-similarities to COBOL, Fortran, and ALGOL. These were PL/I elements that looked similar to one of those languages, but worked differently in PL/I. Such frustrations left many experienced programmers with a jaundiced view of PL/I, and often an active dislike for the language. An early UNIX fortune file contained the following tongue-in-cheek description of the language:
<blockquote>Speaking as someone who has delved into the intricacies of PL/I, I am sure that only Real Men could have written such a machine-hogging, cycle-grabbing, all-encompassing monster. Allocate an array and free the middle third? Sure! Why not? Multiply a character string times a bit string and assign the result to a float decimal? Go ahead! Free a controlled variable procedure parameter and reallocate it before passing it back? Overlay three different types of variable on the same memory location? Anything you say! Write a recursive macro? Well, no, but Real Men use rescan. How could a language so obviously designed and written by Real Men not be intended for Real Man use?</blockquote>
On the positive side, full support for pointers to all data types (including pointers to structures), recursion, multitasking, string handling, and extensive built-in functions meant PL/I was indeed quite a leap forward compared to the programming languages of its time. However, these were not enough to persuade a majority of programmers or shops to switch to PL/I.
The PL/I F compiler's compile time preprocessor was unusual (outside the Lisp world) in using its target language's syntax and semantics (e.g. as compared to the C preprocessor's "#" directives).
Special topics in PL/I
Storage classes
PL/I provides several 'storage classes' to indicate how the lifetime of variables' storage is to be managed <code>STATIC</code>, <code>AUTOMATIC</code>, <code>CONTROLLED</code>, and <code>BASED</code>, and <code>AREA</code>.
<code>STATIC</code> data is allocated and initialized at load-time, as is done in COBOL "working-storage" and early Fortran. This is the default for <code>EXTERNAL</code> variables (similar to C “extern” or Fortran “named common"),
<code>AUTOMATIC</code> is PL/I's default storage class for <code>INTERNAL</code> variables, similar to that of other block-structured languages influenced by ALGOL, like the "auto" storage class in the C language, the default storage allocation in Pascal, and "local-storage" in IBM COBOL. Storage for <code>AUTOMATIC</code> variables is allocated upon entry into the procedure, <code>BEGIN</code>-block, or <code>ON</code>-unit in which they are declared. The compiler and runtime system allocate memory for a stack frame to contain them and other housekeeping information. If a variable is declared with an <code>INITIAL</code>-attribute, code to set it to an initial value is executed at this time. Care is required to manage the use of initialization properly. Large amounts of code can be executed to initialize variables every time a scope is entered, especially if the variable is an array or structure. Storage for <code>AUTOMATIC</code> variables is freed at block exit.
<code>STATIC</code>, <code>CONTROLLED</code>, or <code>BASED</code> variables are used to retain variables' contents between invocations of a procedure or block.
<code>CONTROLLED</code> storage is managed using a stack, but the pushing and popping of allocations on the stack is managed by the programmer, using <code>ALLOCATE</code> and <code>FREE</code> statements.
Storage for <code>BASED</code> variables is also managed using <code>ALLOCATE</code>/<code>FREE</code>, but instead of a stack these allocations have independent lifetimes and are addressed through <code>OFFSET</code> or <code>POINTER</code> variables. <code>BASED</code> variables can also be used to address arbitrary storage areas by setting the associated <code>POINTER</code> variable, for example following a linked list.
The <code>AREA</code> attribute is used to declare programmer-defined heaps. Data can be allocated and freed within a specific area, and the area can be deleted, read, and written as a unit.
Storage type sharing
There are several ways of accessing allocated storage through different data declarations. Some of these are well defined and safe, some can be used safely with careful programming, and some are inherently unsafe or machine dependent.
- : There are other/helpful restrictions on these, especially "in programs ... attribute, in methods, or .. option."<br />
- : One enhancement, which adds built-in documentation, is
- :: (which restricts the variable's value to "one of the labels in the list.")
- (“go to depending on”).
PL/I has statement label variables (with the attribute), which can store the value of a statement label, and later be used in a statement.
