The language PL/I included in its specification many things that are omitted in most modern languages, being implemented in libraries or in the operating system, e.g. for handling threads (tasks in IBM lingo), exceptions, signals, events.
However the integration in the language of those features made them frequently more convenient and I consider the pthreads API available in UNIX/Linux as considerably inferior to the thread handling that PL/I already had in 1965 (e.g. already then PL/I had an equivalent of WaitForMultipleEvents that was better than anything in pthreads).
Even if the C language has evolved from BCPL, most of its evolution has consisted in taking various features either from PL/I or from Algol 68. The C language has introduced very few innovations, i.e. only the "continue" statement and its more general (but more verbose and cumbersome) syntax for the "for" statement. Therefore many features of C and of its descendants come from PL/I, e.g. "struct", ".", "->", "malloc" and "free", signals and many others.
Also PL/I allowed aggregates, i.e. arrays and structures, in many contexts where most modern languages accept only scalar variables, requiring verbose loops for handling aggregates (or the definition of custom object classes, i.e. the implementation of some library for handling them).
However the integration in the language of those features made them frequently more convenient and I consider the pthreads API available in UNIX/Linux as considerably inferior to the thread handling that PL/I already had in 1965 (e.g. already then PL/I had an equivalent of WaitForMultipleEvents that was better than anything in pthreads).
Even if the C language has evolved from BCPL, most of its evolution has consisted in taking various features either from PL/I or from Algol 68. The C language has introduced very few innovations, i.e. only the "continue" statement and its more general (but more verbose and cumbersome) syntax for the "for" statement. Therefore many features of C and of its descendants come from PL/I, e.g. "struct", ".", "->", "malloc" and "free", signals and many others.
Also PL/I allowed aggregates, i.e. arrays and structures, in many contexts where most modern languages accept only scalar variables, requiring verbose loops for handling aggregates (or the definition of custom object classes, i.e. the implementation of some library for handling them).