June 16, 2018

This article is based on a post by https://www.bernd-leitenberger.de/pascal-und-c.shtml and has been updated by Holger Klemt in some places based on recent developments.

Introduction

There is an essay by Kernigham, one of the developers of C, “Why Pascal is not my favorite programming language.” This essay from the early 80s is worth reading. I was then able to much better understand why he has developed C, but: he has not understood the benefits of Pascal at all! Well I’m not Kernigham and I do not intend to submit a tit-for-tat response to this article 37 years later. But I think it’s time to explain why I cannot understand the role that C plays today.

The evolutionary history of both languages

Why both languages divide the user base also has to do with their history and the resulting language options, and also with the personal ideas of the developers, which were reflected in the language.

The history of Pascal

Pascal is the older of the two languages. It was developed by Niklaus Wirth from 1968-1972. Wirth was already familiar with the development of programming languages. He had previously collaborated on the language Algol-68. Algol is the forefather of almost all of today’s procedural programming languages. Previously developed languages were largely unstructured. They only offered GOTO to make conditional jumps. Algol is often seen as the first step in the pursuit for a higher level of abstraction – from machine to model: structuring the code.

But Algol also had weaknesses. The language was, like FORTRAN, primarily focused on calculations. It lacked both powerful string functions and input/output functions. The syntax was not so neat yet either. Wirth wanted to improve that with Pascal. The language was to be primarily used as a teaching language; not as a language to write commercial programs, but as a language to learn programming. Thereby Pascal actually had good prerequisites to set a new standard.

For this reason, the syntax was designed so that Pascal programs are very easy to read and understand. Wirth’s second goal was the introduction of the type concept. All previous languages knew only elementary data types: characters, numbers. In Pascal it was possible to define your own types. Either by combining existing ones (Record), or as an enumeration or a partial area of an existing type. New types introduced were the quantity type (SET OF) and the pointer type (^).

Not only that, the compiler also supervised the type compliance, and if wished, at runtime. Gone were the days when you could pass a string to a subroutine that expected an integer. Pascal had improved string functions, but unfortunately in the original form, with just as few ways to edit files as Algol.

1970 saw the first implementation for the CDC-6600 supercomputer. Very soon the language spread, not only in the classroom but also in the programming world. Pascal already had the role in the seventies and eighties of today’s C. For example, for the Cray supercomputers there was a FORTRAN and PASCAL compiler, but not a C compiler until much later. For a quick adaptation, a virtual machine was later developed, which interpreted P-code, much like Java today interprets byte code. The implemented principle of the stack was later adopted by hardware manufacturers.

Wirth, who also wrote books about algorithms and compiler construction, then made a mistake that is surely to blame for the fact that Pascal does not play the role it deserves today. He addressed the next level of encapsulation of machine-specific details. Algol introduced the structuring of code, Pascal the structuring of data. The next is the principle of information hiding: the concealment of details that are unimportant. However, this did not happen in “Pascal-2”, but in a new language: Modula-2. It is clear that a language, which the developer is no longer committed to, is in a poor position. Modula-2 appeared in the early 80s. At the beginning of the nineties Wirth added Wiron as a third language: an object-oriented language, whose runtime system is an atypical small 200 Kbyte.

For Wirth, academic recognition was more important than the possibility that the language he developed was widely used. This is a significant difference to Kernigham and Ritchie. Regardless of this however, Pascal has evolved further. Today there is an ANSI standard, which essentially eliminated the limitations that prevented Pascal from being used as a commercial language. A commercial spin-off became considerably more successful, but more about that later.

The history of C

The story of C is, as many know, linked to UNIX. The initial versions of UNIX were still written in assembler. At the time, Kernigham and Ritchie still used the BCPL language, a language for machine-oriented programming. C evolved from BCPL. (It’s the next letter in the alphabet). The goal was to develop a language that could replace assemblers for programming operating systems and machine-oriented programs.
C therefore already differs from the Pascal concept. Many see it as an intermediate step between assembler and a higher-level language, very often you stumble across the term “super assembler”. I find this very fitting, because as in assembler, there are only a few non-elementary data types in C. And, as in assembler, the language does not forgive mistakes and it has only rudimentary tests implemented. However, there are those possibilities for structured programming available that were introduced by Algol.

Kernigham and Ritchie published the book “Programming in C” in 1978, which is also regarded as the date of birth of the language. C spread via UNIX. This was given away for free for a long time by AT&T. This included, of course, the C compilers. Especially universities, who had to save money where possible, used this operating system. The software costs were thus reduced. As UNIX was implemented in C, students could also learn to understand the operating system. Since they had to learn C to do this, this was probably one reason why C prevailed. Because: What is the university graduate’s preferred programming language? Primarily the language he has already learned. Thus, C spread slowly but surely.

Because C is a programming language for hardware-oriented programming, operating systems were also developed in C. For example, Windows and Mac OS. But the interface to the operating system is a matter of agreement. How should data be passed over the stack? How are strings defined? By setting its interface here, C made it harder to develop applications in other languages, because they first had to convert the data.

C was normalized twice by the ANSI committee. Once in 1989 in a version that eliminated the worst problems in Kernigham and Ritchie’s implementation (for example, that a function could be declared without parameters, and then called with as many parameters as desired). Then in 1999 a second normalization was made, which essentially consisted of adopting the non-object-oriented elements of C ++, such as // comments, const as a keyword for true typed constants, etc. …

C has influenced many other languages; this will be discussed later.

C and Pascal – a comparison

It is not easy to compare two programming languages. Every developer usually has his own implementation in mind. For example, what I disliked about the above-mentioned article by Kernigham was the Pascal implementations he drew upon. My first Pascal was Turbo Pascal 3.0. An implementation that needed only 32K of memory with the Editor and ran on an 8-bit CP/M machine. Although there was no viable C compiler for this platform (this machine was not powerful enough), this implementation was superior to the one Kernigham used, and many statements he made did not apply to Turbo Pascal back then.
It therefore makes sense to limit yourself to the core areas of language standards.

Legibility

As Pascal is a language intended to be used in teaching, Pascal programs are very easy to read. Many things contribute to this, which have been omitted in C.

A function to convert a string to uppercase in Pascal looks like this:

Function StringToUppercase(Row: String): String;
type Lowercase = [‘a’..’z’];
var temp: String;
i : Byte;
begin
temp:=row;
for i:=1 to Length(row) do
if row[i] in Lowercase then temp[i]:=chr(ord(temp[i])-32);
StringToUppercase:=temp;
end;
The corresponding routine in C looks like this:
char * StringToUpper(char * row)
{
char * temp;
int i;
int p = strlen(row); temp = (char *) malloc(p);
for (i=0; row[i]!=0 && i<256; i++)
if (row[i]>=’a’ && row[i]<=’z’)
temp[i]=(char) row[i]-32; else temp[i]=row[i];
temp[i]=0;
return temp;
}

We can already see a very clear difference between the two languages. C alone comes off worse due to the massive use of special characters as operators (here *, ++, &&,! =). But Pascal was also invented to allow an abstraction of the problem, and that can be recognised in the syntax.

Every Pascal function also has a label as “Function” or “Procedure”. This entails more writing, but you can navigate the source code better. Data and code are strictly separated: the VAR part with the variables and the type part are both in front of the code. And even simple declarations are logically adapted. What is easier to comprehend: “var temp: String” or “char temp [256]”? In the first case you can read the information almost literally. “The variable Temp is a string”. On the other hand, C exchanges the definition and declares the variable type first, and with arrays this becomes obscure, because the dimension depends not on the variable type but on the name.

Of course, the poor legibility of C is a direct consequence of the use of special characters. Here you can see that the authors just did not have the experience that Wirth had, as many operators are poorly chosen. The symbol ^ for differencing in Pascal reproduces the nature of a pointer much better than the star, which is also used as a multiplication sign. It has done better with the “->”, with which composite components can be addressed. And I have never understood why == and != is used for comparisons, instead of = and <>. I often have the impression that the sole aim of C syntax is to be different from Algol or Pascal, and not more easily comprehensible.

Perhaps the original aim was to save space, but this means that C programs have to be commented much more, which wins you nothing. The partially cryptic nature of C actually attracts some programmers who love this; there are even programming competitions in C such as “Obfusticated C”. Here programs that no one can read win prizes. In this example the need to avoid a buffer overflow and append the binary zero makes the C program even longer than the Pascal program. (Note: Of course, “Obfusticated C” competitions have nothing directly to do with C, but they represent a culture that sees an art in writing cryptic programs that are neither readable nor easy-to-understand. The fact that people who are predisposed to using C instead of Pascal does however have something to do with the programming language.)

Complexity and illogicality

One feature of Pascal is that it tries to approach the syntax of a real language. That’s not the case by far in C. I think this is also one of the major problems of C.

Take the struct statement. This is used to declare a composite type. But it can also be specified by name, without declaring it or creating variables; yes, you can even create variables of a type without creating a type:

struct mystruct; // Definition of the name
struct mystruct { int a; float b;}; // Type definition
struct {int a; float b} astruct; // Variable definition without type definition
struct mystruct {int a; float b;} astruct *, bstruct // Type and variable definition. astruct is a pointer to mystruct, bstruct is a mystruct type!

The whole thing is so complicated and confusing, that I wonder if there is not perhaps intention behind it. The same applies to other language components. Why do procedures have to return a void (nothing) data type? What is returned, if I return a value for a function declared with void, and why does it work? (Unfortunately in C, there is too much that is not regulated and implementation-dependent – each compiler constructor can do his own thing.)

The unclean syntax runs right through the language: whilst with Pascal

Type newtype = oldtype

it is clear which one is the old type, the same in C reads:

typedef oldtype newtype

Without the equal sign there is no easy memorability, nor can you attach variable declarations to the definition of this type. This makes the whole thing confusing.

In order not to make it too easy for people switching from other languages, C has broken with other conventions: the colon as part of the assignment operator or declarations in Algol and Pascal is used, for example, as a delimiter in the question mark operator, and assignments are now made with “=” and comparisons with “==”. The logic in the Repeat…Until loop is reversed in C:

Instead of

Repeat …. UNTIL condition is met, it means:

do … while condition is not met.

Pascal therefore repeats as long as the condition is false; in C it is repeated as long as it is true. A similar oddity can be encountered in multiple selections, called CASE in Pascal and Switch in C. In Pascal it is formulated as follows:

case charval of
‘a’..’z’,’A’..’Z’ : art:=alpha;
‘0’..’9′ : art:=numeric;
else art:=undef;
end;

It is necessary in C to set a break; behind every case, so that the following cases are not also processed. There’s really no reason why that should be useful. In any case, a break command is necessary, so why doesn’t the compiler create it, as in Pascal? If I want to share multiple points, why not introduce a powerful type like the Pascal subrange type, rather than this error-prone construction?

With regard to operators, you very often have to take into consideration that these can have “constraints”. You need to have a list of the order of operators stuck on your monitor (like a professor at our Polytechnic who holds C in such great esteem), in order to know the result of the following expression:

int x;
x=5;
–x=(++x)–;

No, the result is not 4 but 6. The order of the operators is chosen very poorly, often you have to set brackets, especially for comparisons and the frequently-used dereferencing operator *. Overall, C severely lacks clarity. The preprocessor further contributes to this, a noble name for a simple search/replace function which replaces characters in the source code with others and can do even more fun things with the source code using macros.
The confusion also arises from the multiple use of keywords. static is both a local variable on the heap [really?] as well as an externally declared function. With C ++ the confusion is increased even further, as keywords have even more meanings here.

Of course, Pascal also has some logical weaknesses. The standardization of types is poorly planned. It is very strict and based on type names, rather than types. Thus

a = [A’..’Z’];

and

b = [‘A’..’Z’];

are different types, but not if assigned in the form:

type atyp = [‘A’..’Z’];
var a : atyp;
b : atyp;

One goal may have been to force the user to consistently introduce types with the benefits of type checking. However, for strings which can have different lengths, this concept is wrong. (And there it is also weakened – for example, assignments between strings of different lengths are possible.) Furthermore, the comparison operators AND, OR and NOT have a lower priority than comparison operations, so that brackets need to be used a lot in comparisons. The variable record in Pascal is defined just as unclearly as its counterpart in C. In Pascal however there is another form that supports security.

Datatypes

C and Pascal both know elementary data types such as integers and floating-point numbers. C has also inherited the composite type from Pascal, called Struct in C and Record in Pascal. But that is where the similarities end, and newcomers need to start learning.

Enumeration Types: An enumerated type only accepts values that you specify. In Pascal this is, for example, something like this:

Color = (yellow,red,blue,green);

It’s a form of named constants which makes life easier, because you can now for example, write in the source code

if choice=red then Alarm(err);

C also offers a simulation of the type enum. But that’s where the similarities end. In C it is nothing other than saving a lot of #define lines. Since these types are internally stored as numbers, they can be assigned any integer, including, for example, choice = 10, although we have only defined 4 colors. In Pascal, the assignment of a number goes through a type conversion and raises an error. Here it also becomes apparent that the lack of C typification is of no advantage. Because: what is the point of assigning 10 to a variable of a type for which only 4 values are defined? Then you would have to either manually start an error check or expand the type, or you can work just with #defines and an unlimited integer type like int.
Subrange types: They are a subset of an existing type, and they exist only in Pascal. A subrange type is e.g.

type Lowercase = [‘a’..’z’];

The compiler can check if a lower-case variable can include other values such as “9”, “A” or “ü”. Kernigham has proposed replacing this automatic compiler check with a function such as islower (..). But what does this mean?

• More work for the programmer rather than setting the compiler switch a single time.
• The possibility that this function may be forgotten just once – the compiler switch then applies globally.
• The code gets more confusing – it is necessary to look into the function each time, instead of having the code right in front of your eyes.
• After eliminating all errors, the Pascal programmer can set the range check switch to “off” and the checks are omitted during compilation, whilst in C, all the functions are still in there requiring memory and computation time.

Strings

Strings differ fundamentally in both languages. In Pascal, strings have a fixed length, which is stored in byte 0 (thus a maximum of 255 characters). In C, strings are pointers to a character table. Everything they point to is interpreted as a character table (even if it is not). The length is therefore dynamic and the end is specified by the character 0.

Both concepts have disadvantages. The Pascal concept wastes space and limits strings to max. 255 characters in length. However, it also allows simpler string operations. This known length specification prevents any writing over the specified length. Pascal is also very good-natured, if you specify more characters for Copy, Delete and Insert than fit into the string. It simply copies as much as the length allows and the rest is cut off. Some authors are of the opinion that Strings in C should not be regarded as a separate data type, but simply as a special array of Char.

The C concept allows arbitrarily long strings, since malloc and calloc can request new memory areas at any time. The concept is however very insecure and requires that the programmer always manually insert the binary 0. If this is overwritten, then you have a problem. The concept is also slow, because you have to iterate over the string even with a length specification. Scripting languages such as Perl like to point out that their string routines are faster than those of C – because many people think of C as a very fast language. But this is not the case with the strings. For almost every operation (copying, assigning, finding length) you have to iterate over the string.

The associated string routines are not worth their names. [wrong] Here you should note that C is a language for the development of operating systems, where strings mainly only occur as messages. There aren’t any operators for strings such as concatenation, comparison or assignment, only routines. Due to the binary zero concept, only C programs are subject to so-called buffer-overflow attacks on web servers, since a string that is too long overwrites the end identifier and code, and thus it is possible to infiltrate your own code into foreign systems. [wrong: if the recipient is programmed correctly, the same thing happens as in Pascal: the part protruding over the end is cut off.]

The string routines are also ineffective, because you cannot just determine the length of a string but must also iterate over the array. This takes time and makes code ineffective. For example, if you want to copy a string, you cannot use a processor assembler command that copies an entire block of memory. If you want to compare two strings, you could abort immediately when different lengths are detected. if you want to concatenate two strings you have to determine the length twice.

The Pascal concept is simpler here, but should not be used for applications, as it consumes too much memory and does not allow long strings. Therefore, there were libraries which did it all dynamically via memory allocation, or in the case of Turbo Pascal, C introduced the pointer to a string (PChar). But that was just as flawed and cumbersome as in C.

C ++, as well as Java and the Pascal successor Delphi, use a modified Pascal string design. Here two fields are used before the string for the storage of max. length and act. length. Strings can then be larger (up to 2 GB) and, if you interconnect the administration to the storage manager, you can dynamically resize it without having to modify old Pascal code.

Arrays

Arrays are primarily static in Pascal, while in C, arrays are used as pointers to memory areas that are interpreted as arrays. Again, the C concept looks better at first glance, because you can request new memory via calloc. But actually only memory arithmetic is used here, which is also possible in Pascal via Getmem and Freemem, but here, in addition to the dynamic arrays without any verification, you also have the static arrays with range check. In C arrays always start at 0 and are indexed by integer variables. In Pascal, on the other hand, with any lower limit and every ordinal type as an index. Also, programs are significantly easier to read and write.

The array of char takes on a special role in C. Actually, char is an integer type with 1-byte size. This can also be assigned letters, i.e. characters. This is a result of C‘s weak typification. So only one string is simulated, you could just as well give the string routines a block of memory that you have read from the hard disk, also a consequence of the missing typification.

Sets

Sets are only available in Pascal. These are quantity types that consist of the types already described. Special feature: While normally only one value can be assumed, there are multiple values for quantities. There are the classic set operations such as intersection (-) and union set (+). Very popular is the “in” operation:

if a in [‘A’..’Z’] then

this would have to be rewritten in C in the following construct:

if (a>=’A’ && a<=’Z’)

Quantity types allow a lot of comparisons and queries to be formulated more concisely and minimize errors, because you can declare them as separate types, and you do not have to manually write lots of checks.

Unions

Unions are only available in C. These are bit fields which can be used to address the individual bits of a byte. Of course, such data structures require a low-level language to set or query them. The keyword volatile belongs in the same category, indicating the low-levelness of C, which instructs not to hold a variable in a register, but always at the hardware address (e.g. if this is a card in which a write access to the memory triggers an action).

Pointer

Pointers are available in both languages. In Pascal, pointers are fundamentally typified. In C fundamentally not. In both languages, pointers can be converted into each other. For this purpose, there is an untypified memory in both languages, called Pointer in Pascal and void * in C. Pointers are necessary in Pascal to point to the next element in concatenated structures (trees/lists), and to dynamically request memory.

In C, pointers are the lifeline for missing parts of the language specification:

• They serve as a replacement for a real string type (pointer to an array of byte variables)
• They serve as a replacement for a missing Call by Reference interface

That’s the reason why in C you constantly stumble over pointers and it is so error-prone. Because of these characteristics, there are only a few checks for pointers and a large potential for errors. Sometimes you cannot see the mistakes for all the dereferencing stars.

Of course, you can do more with pointers in C. If A is a pointer to an Int and B to a float, B can be assigned to A and the contents of the floating-point number interpreted. Such examples are often boasted as a special language feature. What this is supposed to be good for however, has remained a mystery to me.

Function types

Also only available in C. However, these are very useful and have now also been adopted by Pascal’s Extended Standard. This makes it possible to modify code yourself or to replace an interpreting parser with a compiler if constructions occur frequently. Windows exploits this means of speech very thoroughly as a “callback”.

Language resources

As the younger language C naturally contains more language resources, but it has its limits. Actually, it’s just interrupting a loop with break and continue. There are differences of course. The FOR loop is very simple in Pascal and very powerful in C, and the accepting loop, implemented in Pascal as REPEAT…UNTIL and in C as do…while, has a reverse condition check in C.

However, there are differences in the procedures that are available and their implementation. C works with a system of header files that declare the function headers. In Pascal on the other hand, the system knows certain functions as an integral part of the language. The C system is clearly more flexible than Pascal’s. This comes at the price of a longer compile time by including the many header files in the compilation, and in larger projects by the need of make files, which control the compilation.

I consider the system-oriented language resources in C to manipulate bits and unions as well as compiler statements such as register to be much more important. This makes C an improvement over assembler in system programming. C is a good language for creating operating systems or programming drivers. Here, the disadvantages of C hardly come into play, and you can use it expediently.

Security

Computer science considers a language to be safe, if it detects as many errors in the program as possible, and if and when they occur, they influence the stability of the program as little as possible. Here are the most distinct differences between Pascal and C.

Pascal is a strictly typified language. Only compatible data can be convoluted. This is the case, for example, when a byte value is assigned to an integer variable, since this variable also covers the value range of bytes. For other conversions you can use a conversion function such as Trunc(), which for example converts a floating-point value into an integer number, or you can write one yourself.

C, on the other hand, is weakly typified. Using the Cast Operator () you can convert any variable into a different one, even if this is nonsense, due to the internal representation of the data. In the few cases where this is not possible, there is the type void * as a universal pointer for conversion. Most routines must use this pointer to implement a Call by Reference interface. This means that a C compiler can detect fewer errors of its own accord. It often looks as if there are many types in C, such as time_t. If you take a closer look, these are just simple data types without range checks. Whether a year number of -1 million is a meaningful value cannot be recognized by a C program.

C has no checks at runtime. Overflows, range overruns are not detected. This can lead to other variables and code ranges being overwritten. This is especially true for strings. And the compiler itself also seems to be open to obvious nonsense. Used to Pascal writing no parentheses for functions without parameters, I initially wrote:

void func(void)
{

}

void main(void)
{
func;
}

However, this is not a call of the function func, but a function pointer without a variable declaration. It’s nothing other than nonsense. However, this has still been compiled correctly. Since C had to produce very efficient code, there are many operators and constructions that other languages do not have. This allows an assignment (=) in an IF construction, which is often confused with a comparison (==). This was originally done to be able to use a return value of a function that is 0, in case of an error, as a way to check whether the function worked correctly.

In Pascal, all variables are created on the stack, but the return value of a function always exists. In C there are also variables on the heap (the values survive a function call), but if you are not careful and do not pass static variables as the result, the result can be overwritten by subsequent functions.

While Pascal has a runtime system that can detect errors which only occur during program execution, C introduces one to implement the format specifications in printf. Anyone who has ever specified the wrong data type in printf knows how faulty this is.

Function calls are also a source of errors in C. In C the calling function clears the stack, in Pascal the called function. This unimportant detail has far-reaching consequences. If a local variable is declared in a function and returns this as a result, the result still exists, even after the function is exited (and the memory area on the heap overwritten). In C, on the other hand, further function calls fill up the stack and overwrite the result. To prevent this, you have to explicitly declare a local variable as “static”. Those who not take this into consideration, may well have functioning programs, however they calculate wrongly.

The problem of “Buffer Overflow Errors” has already been addressed in the Arrays section. It is a real specialty of C, which is often used for attacks on web servers if the programmer does not think about testing the size of passed strings.

The Preprocessor

The preprocessor is nothing more than a global search/replace function before translation. As C does not know any constants, texts are defined via #define which are then replaced. The same applies to macros that can replace functions. In addition to the lack of type checking by such replacement functions, these can also result in puzzling program behavior when brackets are not set correctly, and thus parameters are passed incorrectly.

Old languages such as FORTRAN or COBOL only recognized capital letters for variable names. Pascal is not case-sensitive. So “Size” and “size” are one and the same variable. C, on the other hand, is case-sensitive. This makes life difficult when programming. Because nobody, who does not want to make their life unnecessarily difficult, will define two variables which differ only by the uppercase and lowercase letters. In fact, this seems to have only been introduced so that you can recognize the preprocessor in the source code. Because in C, all constants defined with #define are always written in CAPITAL letters by convention. As you only have a limited view of what datatype a variable in the source code in C in operations is, many companies introduced their own notation systems, so that larger programs are at least reasonably legible. The best known is the Hungarian notation, which is also used by Microsoft. Here you can use upper/lower case to make the prefixes more legible. There is no such system in Pascal, if you don’t recognize the type by the variable name, this is always unique in the source code for assignments and operations.

Summary

C and Pascal have two concepts that are diametrically opposed. C renounces language possibilities, which already existed under the much older Pascal. Many things are imposed on the programmer. In return, you get more freedom, which you can also use to write efficient programs. When C was created compilers were even more stupid than today, so many commands enabled you to explicitly tell the compiler what to do, e.g. using the ++ operator to use an Inc instead of an Add command. Maybe Kernigham and Ritchie just wanted to be able to create a compiler faster, so they forewent a lot of what Pascal already offered. Maybe they weren’t such good compiler builders, so that they had to slim down. It was not without good reason that Wirth had already worked at Algol, and his works on compiler construction and algorithms are among the standard works in computer science today.

There were many advantages using C for programming operating systems or machine-level programming. Many of C’s disadvantages do not occur in such environments, since they are rarely associated with complex data types or larger complex functions. String processing is also not required here, but rather the frequent movement of untypified data such as memory blocks. Such low-level functions did not exist in the original Pascal, but they were retrofitted in almost every implementation used. Pascal was conceived as a learning language, with the goal of teaching students to write clean programs. Therefore, the language is more stringent in testing and overall safer to use. Unfortunately there was no library of functions, especially for hardware-related operations and input/output, provided as part of the teaching language.

Pascal has real shortcomings when it comes to creating very large programs in commercial environments, since the original standard contained only a poor I/O library, and there is a lack of language resources to modularize code, as is possible in C (albeit cumbersome due to the separation of headers and program files). However, modern implementations such as Delphi and Lazarus/fpc largely compensate for this.

With C you can see that its creators had no previous experience with the design of programming languages. It is very confusing and illogical. Some parts have probably especially been made differently to Pascal, just to be different. What the point of that is I just don’t understand. (Were K & R envious of Pascal?) In order to complete a compiler as quickly as possible, many things were deliberately omitted that Pascal had already introduced, such as type checks, arrays with different lower limits or a runtime check. Not surprisingly, the first standardization in 1983 abolished much of what was allowed at Kernigham & Ritchie, and at least introduced some type tests. Rarely have language creators been slapped around like this. As a rule, languages are extended and not reduced in size.

It is therefore no wonder that supporters of both programming languages get into each other’s hair because they usually have different applications in mind, each of which is better suited to one of the two programming languages.

The development of both languages in the last 37 years

The comparison of the two languages by Kernigham is now 37 years old – how have both languages developed since then? Well C has changed relatively little. There were two ANSI standards, in the first the worst linguistic blunders by Kernigham and Ritchie were removed, in the second some language features of C++ were adopted, provided they were not object-oriented.

Pascal has also been standardized twice and there is an ANSI draft for object-oriented Pascal. This has been available since 1993 but has not been adopted. The changes mainly concerned tearing down existing barriers, which Kernigham also criticised in his paper. Today Pascal has dynamic arrays (without using calloc and malloc as in C) and open string parameters.

“Company standards” such as Delphi and Lazarus/fpc go much further here, using concepts from other languages where suitable, such as units from Modula, and object orientation or interfaces from Java. What the user gets is an incredibly powerful tool, which is however incompatible with other standards.
Instead of developing C further, there is C++. C++ contains C as a subset. Moreover, the language is very complex because its creator Bjarne Stroustrup believes that a language must be powerful enough to cover all areas of application. The fact that C is contained as a subset makes evaluation difficult. Although C ++ offered alternatives for many C problems – templates as a replacement for macros, references as a replacement for untypified pointers when passing, and objects instead of pointers to structs. But you do not have to use them, because C is still included as a subset.
Accordingly, there are “C-like” C++ development systems and more “Java-like” development systems. The first is certainly Visual Studio, where without countless macros, vagabond pointers to GDI objects and resources, you think you are programming C instead of C++. On the other hand, there are component-based development environments such as CBuilder, which works with objects, properties and methods.

Influence on other languages

Each of the two languages has had an influence on other languages. C was more successful in this respect. There are comparatively few programming languages similar to Pascal. Besides the successors Modula and Oberon, I only know Ada, Delphi, Lazarus/fpc and COMAL. This may also be due to the fact that many Pascal compilers have simply retrofitted missing language components. Thus Delphi and Lazarus/fpc offer an “object Pascal”, but much more powerful than the original Pascal. It is more like a Java with Pascal syntax than the original Pascal.

C has passed on the most essential elements of its syntax to many languages. This seems incomprehensible, because even the greatest C supporters do not consider it very clear and easy to read. But C is linked to UNIX. The C/Unix inventors also created shell scripting languages based on C. Many learned C because of UNIX and when they went on to a new language, they chose one similar in syntax to C. The basic elements can be found in Java, C#, PHP, JavaScript, Perl.

However, taking a look at the series C++ -> PHP -> Java, it can be seen that more and more concepts have been adopted from Pascal. C++ introduced the type-safe pointer concept and the Call by Reference interface. In Java there are no longer any pointers, but references to memory areas, as in Pascal, which are allocated with New.

Delphi and Lazarus/fpc show where Pascal might be today if it had been consistently developed. Both are not only modular like Modula (by the unit concept), they are object-oriented like C++ or Java. They are also systems that allow GUI applications to be built very easily by representing the elements as objects. The “published” namespace, which is not implemented in C ++, also makes it possible to provide properties to a visual IDE, which the user can change without having to write any code in an object inspector.

If you have programmed with Delphi or Lazarus/fpc and are then confronted with C, you will be subjected to a culture shock. What struck me about most during my software engineering studies is that professors are largely unaware of it. When introducing C++, Java or now C# in class you are told every time “With C++ we don’t need pointers as in C”, “With Java we can now also program GUI”, “With C# you can program visually”. As if this were the newest and greatest: Delphi has been here since 1994. The influence in Java and especially C#, where the former creator of Turbo Pascal, Anders Hejlsberg, is head of the development department, can be seen very clearly. Pascal programmers are almost a decade ahead of their C colleagues. I find it especially amusing that everything that is supposed to make C so great, is now “unsafe code” in C#. Finally it’s been admitted!

Those who grew up with such language tools and then moves on to a “Visual Studio” of a certain famous Redmond manufacturer, feel transported back to the computer stone age. This is Windows programming the hard way and API functions. Unfortunately, Delphi is only a force to be reckoned with on Windows. That’s just the problem why Pascal hasn’t really been developed further. Even the successors Modula and Oberon have remained much less successful than C ++ or Java.

True multi-platform capabilities are currently offered by Lazarus/fpc with Win32/Win64/Linux/ MacOSX, and via the integrated pas2js compiler most mobile devices are available as target platforms with the same Pascal programming language.

However, it is reassuring to see that many modern languages are now emerging, such as Python or Ruby, based on a clean syntax as in Pascal and runtime checks. While the benefits of C are today irrelevant, due to the rapid progress in computer performance, which makes much smarter compilers possible, the language still lacks the possibilities Pascal offers. Like Windows, C is probably one of the most successful provisional solutions in the computer world.

Why is C so successful?

It is indisputable that C / C ++ are today the most sought-after languages. Many consider this success to be proof that these languages are better than Pascal. Here is a list of the big C myths:

C generates very fast code

C certainly has features that allow a compiler to produce fast code. However, it is not de facto faster for this reason alone. Of course, pointers that iterate through arrays are a requirement for the compiler to access the elements in this way. But the days when compilers were so stupid that they couldn’t recognize that i=i+1 is the same as i++ are long gone. Even Turbo Pascal showed in 1983 that a compiler could also effectively convert Pascal into code. At that time there was no C compiler at PC level which generated faster code. Pascal compilers on Cyber and Cray supercomputers had already demonstrated that Pascal does not have to hide behind C or FORTRAN in terms of speed.

C has prevailed because it is better than Pascal

C has prevailed because UNIX/Linux has spread. C of course, as a machine-oriented language, has an influence on the creation of operating systems. The entire API of an operating system written in C then consists of calls for C. The entire documentation and examples of how to program are then in C. This is not only true for UNIX/Linux – if you install the help for the Windows API, you will find all routines with C parameters and also all program examples are in C. Besides the problem of strings, Pascal and C also put their parameters the other way around on the stack. Other languages (not just Pascal) are therefore disadvantaged. But the whole thing also has a psychological effect. This can be seen with Microsoft and Windows. Many companies and programmers program under Windows with Visual Studio. Why: There is a service from Microsoft, the MSDN, which provides the developer with information, bug fixes and help, all of course in C and adapted to the in-house product. Many companies know competitive products and know that some can do a lot more, but with Visual Studio you are on the safe side. Microsoft in particular shows that not always the best product is also the most successful…

Seriously: There are many examples of programming languages illustrating that not always the most successful are the best. Anyone who knows Smalltalk will shake his head over the speed of how quickly Java has prevailed. For scripting languages, the contrasts are certainly Perl and Python or Rub

C is more portable than Pascal

C certainly paid more attention to the problem of portability than Pascal. Pascal was never interested in creating a commercial language. However, any language that generates direct code for a machine will never be 100% successful. Data types vary in width on different machines, file systems differ. With most C compilers this degenerates into an incredibly long typedef or #define orgy. Which doesn’t do much to improve the legibility of the source code either. In addition, there is the problem that in C, unlike Pascal, there are many details that are not fixed, so each compiler manufacturer can implement differently.

To cite two examples, Lazarus/fpc is arguably Pascal’s best object-oriented extension for multiplatform development. Lazarus/fpc can be used on Linux, Windows and OSX. These are three completely different platforms, and we are not talking here about console programs but about graphical applications, i.e. it also copes with very different APIs in the systems. By contrast, the Intel C++ compiler for Linux cannot compile the sources of KDE, which are pure C++. And more: Different Linux programs require different versions of the GNU-C++ compiler.

As long as you don’t use a virtual machine such as Java you will always have to adapt a lot when changing the hardware platform. In addition, manufacturer-specific libraries play a very important role today. Almost nobody still uses only the standard routines in his C or Pascal program anymore.

The future

It is certain that the C successors C++ and Java will continue to be important in the future. But I think C will slowly be replaced by C++, because it also offers much better concepts for procedural programming. (Beside the points already mentioned, also the exception concept.) Pascal may not experience the big run as a language anymore, even though I wish Delphi and similar systems would become even more prevalent. But it is satisfying to see that the trend is moving away from the cryptic C syntax to a clean syntax such as Pascal offers. This is shown by Java as well as other new languages such as Ruby or Python. C++ has also become less widespread due to Java, and in certain areas such as the web environment, script languages, in which you can do considerably more than in the compiled languages Pascal and C, will become even more widespread.

Finally, the answer to the question: C is not my favourite language, because it is worse in almost all areas than even the now outdated Turbo Pascal. I can’t see any real benefits, just more effort and more potential for errors. The latter does not seem to be just my opinion. One reason why interpretive languages like Java or Python are used so much more today is that they offer much more checks, especially at runtime. There are more possibilities than in Pascal with its static type test.

Is this all nonsense?

There is a satirical article “UNIX inventors admit – all nonsense”. In this it is written that the inventors of C wrote this only to throw the Soviets back 20 years by inventing a programming language that made it as difficult as possible for the user to program cleanly. This is just a satire, but isn’t there perhaps a grain of truth in it? If you look through the resumes of Kernigham and Ritchie at Bell Laboratorium, you will notice that they have developed nothing but C and UNIX. The last 40 years – cut! Why have you not developed C further, why has UNIX remained limited to the user comfort of CP/M and DOS? You couldn’t or you didn’t want to? I think if you get these questions answered, there would be more clarity as to why C is the way it is.

One Comment

  • A few points here:

    The language Wirth introduced in the 1990s (1988 actually) was Oberon, not Wiron. I’ve never heard of Wiron. Typo?

    You say Windows and MacOS were developed in C. Actually, MacOS (not the modern Unix-based one) was developed in Pascal.

    One further note. The arrow and PgUp/PgDn keys don’t work to scroll through this site. Only the scrollbar works.

Leave a Reply

Your e-mail address will not be published. Required fields are marked *