34

In Pascal, nil (the pointer value to "nothing") is a reserved word. Why wasn't it simply a predefined identifier as true and false are, for example?

This is stated in PASCAL User Manual and Report p. 109, as well in the ISO documents ISO 7185:1990 (Pascal) and ISO 10206:1990 (Extended Pascal) both in section 6.1.2.

22
  • 2
    You could fantasize on implementations where NIL could be a function that would return different values over time.
    – tofro
    Commented May 7, 2018 at 10:08
  • 4
    Because this is Pascal. There is no such logic as "simply". Why you have to write PROCEDURE and FUNCTION for every function - in C there is no keyword for this, it is obvious and defined by the context.
    – i486
    Commented May 8, 2018 at 12:03
  • 9
    @i486 Actually, C's decision not to have a keyword for function (or type) declaration is problematic for compilers and humans. This is why almost no other languages follow its lead.Off the top of my head I can think of only Java and C++.
    – JeremyP
    Commented May 8, 2018 at 14:36
  • 6
    Re pascal's PROCEDURE and FUNCTION keywords: Pascal's syntax is largely a result of the first Pascal compiler being recursive descent. For that, you have to be able to tell what you're parsing with only one token of lookahead. Commented May 8, 2018 at 20:49
  • 3
    @Luaan Lisp wasn't the obvious choice at the time, it wasn't even an option. Common Lisp didn't exist yet (although of course there were other lisp implementations), and it would be another couple of decades for Lisp Compilers to come out that both ran fast and produced fast code. at (i486): Text I/O might've sucked at the time, but text I/O never sucked so hard that it actually was a limiting factor during development. If writing fewer characters would lead to faster development we'd all be writing in codegolf languages.
    – Cubic
    Commented May 9, 2018 at 10:21

5 Answers 5

65

The definition of PASCAL is, above all else, intended to be simple. PASCAL was designed as a pedagogical language (with aspirations to be useful for commercial purposes, but that was a secondary concern). For this purpose, the definition had to be small and orthogonal so that it could be explained simply and concisely. For ease of implementation, the number of special cases had to be kept to a minimum.

The boolean type is handled by the system as simply an example of an enumerated type. It is effectively equivalent to having a definition

type boolean = (false, true)

automatically included in the program. Specficially: it can be implemented by entering false and true into the symbol table with associated type of boolean. They can then never be used for any other type, as PASCAL identifiers are associated with a single type only in any scope.

nil, however, could not be defined by an existing language mechanism. The language simply does not provide any means of creating a pointer value other than via new, which creates a value while nil refers to an absence of value. Therefore, a new language feature was required to implement it, so a new keyword was added for that feature.

Also, nil does not behave the same way an identifier does: it does not have a predetermined type. The type of a nil expression is determined by its context -- it may become any type pointer that is required to make the expression type check. If it were implemented as an identifier rather than a keyword, that would have required a special case for polymorphic identifiers, of which only a single instance was required for the language and no way provided of defining new ones: clearly not a useful way of approaching the problem.

14
  • 1
    The fact that there would be no way to create nil if no predefined form existed wouldn't have to be a problem. Many predefined symbols for built-in procedures and functions would behave likewise. On the other hand, in Pascal dialects without a generic Pointer type that can be implicitly coerced to any other, there would be no way to create a constant which behaved like nil even if one could use nil to set its value.
    – supercat
    Commented May 7, 2018 at 17:14
  • 1
    Java has null for similar reasons to Pascal, any language that discourages direct pointer manipulation but allows for pointers needs a way to detect if a pointer is uninitialized. Commented May 9, 2018 at 15:35
  • 4
    @MichaelShopsin - right. C got away without needing a keyword (at least until recent versions) due to the fact that it allows conversion of integers to pointers, but both Java and PASCAL prevent that. (Interestingly, I see a lot of people think of Java as being a stripped-down C++, but my experience was the opposite way around - I've always viewed it as an enhanced Object Pascal ... perhaps because the old OO extensions to Turbo Pascal were my first experience of working with an object oriented language, but I do think it really is a more similar system in many respects)
    – Jules
    Commented May 9, 2018 at 16:19
  • 2
    @Cubic - the semantics of Java can't work without null. What should references in objects be initialized to by default? Not having a way to do that is a showstopper in a language with Java's structure. It can't just automatically create an object, but the semantics require a default value for every field in an object, and requiring the developer to provide one for everything would be too much hard work.
    – Jules
    Commented May 9, 2018 at 16:24
  • 1
    ... a reference must always point to a valid object, so you can't have a reference of a type if you don't have an object of that type first), but that results in a substantially different style of language that would be difficult to achieve Java's goals with. It could be done with modern Java, but don't forget Java 1.0 didn't have generics, so implementing something like Optional couldn't be done there. And null is a much simpler mechanism to implement than generics...
    – Jules
    Commented May 10, 2018 at 7:18
20

Unlike Boolean constants, the value of NIL cannot be assigned a particular type. That's why it has to be parsed in a special way, that is, it has to be a keyword.

Another reason for NIL to be a keyword is to disallow explicitly dereferencing NIL by writing NIL@. If NIL were a predefined constant of any pointer type, even a magic polymorphic pointer, it would have been syntactically allowed.

2
  • About you first point, it could be assigned a "special type", but I think you mean it's simpler to consider it a keyword; see my comment on @Jules' answer. Your second point is very interesting; what makes you think it is a reason for making this design choice and not a consequence of the choice?
    – JeanPierre
    Commented May 12, 2018 at 7:40
  • 1
    @JeanPierre That's right; the last paragraph of @Jules answer echoes what I meant ("...it has to be a keyword, otherwise things will get messy"). My second point is that if you want to disallow NIL@ in the compiler, then doing it at the syntax level by making NIL a keyword is much easier than doing it at the semantic level. It is hard to day now if this consideration has influenced the design choice, but as Pascal was a teaching tool, Wirth must have heard the question "What happens if you dereference NIL?" enough times to take care of it in the compiler.
    – Leo B.
    Commented May 12, 2018 at 16:38
5

Because neither 0 nor false is a pointer. Pointers are pointers and not numeric values that can be used in directly in mathematical expressions. Assigning false to a pointer doesn't make any sense so Pascal assigns nil to it.

Talking about "sense" there's a famous example in C++ where previously pointers were generally compared with the literal 0 or macro NULL and that posed several issues. For example NULL*3 would make no sense but it's valid. Using 0 also creates some confusion/feeling that the null pointer always contains 0 value. That's not correct. A null pointer is just a pointer that points to nothing, the binary representation isn't important and there are architectures that use non-zero values to indicate a null pointer.

Since C++11 they created a new keyword for it: nullptr which solves the problem and making pointer comparison a lot more sense.

So Pascal uses nil right from the beginning and there was no similar problem. It also makes Pascal more typesafe. Other languages like Java or C# also have the null keyword for the same reasons.

8
  • 4
    This isn’t accurate: C++11 did create a keyword for it but they didn’t have to: they chose to. nullptr could be defined in user code. In fact, here it is: std::nullptr_t constexpr my_nullptr{}; (admittedly this is somewhat circular since nullptr_t is defined in terms of nullptr but that, too, isn’t necessary). Commented May 7, 2018 at 15:46
  • 3
    nullptr_t's addition to C++ helps do what the caller expects with regard to templating and overloading; NULL has the nasty habit of silently turning into an int. I guess this answer makes the argument that C++11 had to add a new keyword in order properly to separate the types, so therefore it's no surprise that there's a keyword in Pascal given that the types have always been unambiguously non-convertible?
    – Tommy
    Commented May 7, 2018 at 17:53
  • 1
    @Tommy: Types that are unambiguously non-convertible aren't a problem. The problem is that overloading source-code constructs for different purposes will wreak havoc if later extensions to the language make things convertible. For example, in early versions of Java, references and integers were not implicitly convertible, but later versions added implicit boxing (which was reasonable) and unboxing (which was less so). If there had been separate comparison operators for references and integers, adding implicit boxing but not implicit unboxing would have been fine, since...
    – supercat
    Commented May 7, 2018 at 18:55
  • 1
    ...code that tried to integer-compare an Integer (reference) to an int would be rejected at compile time unlesss the Integer were explicitly converted (indicating a programmer's recognition of a conversion that might fail). Absent implicit unboxing, however, the existence of implicit boxing would cause the comparison to be evaluated by boxing the "int" and then doing a nonsensical reference comparison.
    – supercat
    Commented May 7, 2018 at 18:59
  • 1
    @Tommy: Indeed, there are only a few things one can do with nil. It can be used on a comparison operator with another pointer, it can be used on the right-hand side of an assignment operator, or it can be passed to a function. Except for the latter case, a simplistic compiler may be able to generate better code for "clear a pointer" or "check a pointer against null" than for "load a null value and then store it" or "load a null value and then compare it".
    – supercat
    Commented May 7, 2018 at 20:00
4

There are excellent answers in this thread.

The clearest answer is that nil cannot be a value because it has no type. Whereas true and false are understood to be values of enumerated, i.e.,

type boolean = (false, true);

What type of pointer would nil be an instance of? Recall pointer definitions are:

type p = ^integer;

nil, if it is a value, is compatible with all pointer types.

Second, there is no other fixed value that can be assigned to pointers. In the example:

type p = ^integer;

var ip, xp: p;

new(ip);

xp := ip;
ip := nil;

Thus we can see:

  1. nil is typeless.
  2. nil is the only pointer value that is fixed and not generated at runtime.

So nil does not behave like any other compiler constant, so it is not one, but is a keyword.

3

null pointer has a value reserved for indicating that the pointer does not refer to a valid object

Wikipedia is having good explanation of it. Thus null, or nil, is a value of pointer, chosen by the compiler, which, by default, is not valid within current application environment, or is not reachable by the user code.

Why this word "nil" ever exists? For convenience - many functions returning pointers sometimes need to return "invalid pointer" to the calling code, and this calling code will check for this making decision on successful execution of the function. Very good example is memory allocation routines. If there's enough RAM to allocate, they will return valid pointer to the area, if no more RAM - it will return value of null (nil), and calling program will know that malloc (for example) failed to find the space requested.

Why wasn't it simply a predefined identifier as true and false are, for example?

Because Boolean logic constant or variable can only be true or false, but pointer is having wider range of values (up to size of addressable CPU/MPU space).

@JeanPierre:

but I don't see how the range of pointer values affects the possibility to predefine an id with one specific value of this range

The exact value is selected at the time of compilation by the compiler according to its settings and architecture of the target system. nil or null exists to inform compiler to apply this value to all pointer operations. Writing code like if(ptr==0) may not be portable and not function properly because some systems may have pointer equal to 0 as valid addressable value.

2
  • 5
    This does not appear to answer the question, but rather explain what a null pointer is. Commented May 8, 2018 at 10:21
  • I agree with your description of the purpose of nil, but I don't see how the range of pointer values affects the possibility to predefine an id with one specific value of this range.
    – JeanPierre
    Commented May 12, 2018 at 7:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .