Top
Best
New

Posted by nathan-barry 11/9/2025

The Manuscripts of Edsger W. Dijkstra(www.cs.utexas.edu)
268 points | 125 comments
peterkelly 11/9/2025|
The most important one in the context of 2025 is this one:

On the foolishness of "natural language programming". https://www.cs.utexas.edu/~EWD/transcriptions/EWD06xx/EWD667...

dilawar 11/9/2025||
Thanks for the link. Great read.

Apparently Dijesktra loved using em-dash!

beezlewax 11/10/2025||
If you look at the scanned pdf from what looks like a typewriter written document, he was using two hyphens everywhere. Links on the top of the page.
sfn42 11/9/2025|||
I love that essay. It's such a joy to read, and even though it is very short and to the point it says so much both about the topic itself and society at large.

And its just so obviously correct.

bazoom42 11/9/2025|||
It is not obviously correct. The unstated premise is that programming is - or should be - similar to writing mathematical proofs.
adamddev1 11/9/2025|||
The proofs/programs (Howard/Curry) correspondance has been fairly well established I think.
marcosdumay 11/10/2025|||
It's the requirements discovery phase that always breaks every pure mathematical treatment of software development.

(And also, like DW points, that software is way more complex. But on this case, it's the requirements discovery.)

moi2388 11/10/2025||
That’s because it’s not pure math, but applied math. Which also has the requirements discovery phase.
marcosdumay 11/10/2025||
Yes, and constructing mathematical theories is completely different from finding proofs.
bazoom42 11/10/2025|||
It is a bit like architecture is just physics or painting is just chemistry. Technically true in some reductionist sense, but not necessarily the most useful way to think about it.
sfn42 11/10/2025|||
No, the premise is that programming is the act of writing precise specifications, which is easier in a precise language. Similarly to mathematical proofs.
Atlas667 11/9/2025|||
[flagged]
f1shy 11/9/2025||
IMHO you are going way way way to far. Far in the weeds.
BigGreenJorts 11/9/2025||
Nah, I think they're probably seeing warning signs. So much Djikstra's writing is pseudo intellectual pretensious word salad. Which is a shame bc he was an actual intellectual.
cubefox 11/10/2025|||
Setting aside the the elephant in the room (modern coding LLMs are in some sense indeed compilers for natural language -- except they still "compile to" ordinary programming languages) it nonetheless seems to me that even conventional programming languages use too little, not too much, natural language.

Example:

- "&&" rather than "and",

- "||" rather than "or",

- "if (A) B" rather than "if A then B"

This only makes the code harder to read for beginners without apparent benefit. I'm not sure whether Dijkstra would have agreed.

Thankfully though, programming languages already use mostly explicit (English) language in function names. Which is a much better situation than in mathematics, where almost every function or operator is described by a single nondescript letter or symbol, often even in Greek or in a weird font style.

There is a tradeoff between conciseness and readability. Mathematics has decided long ago to exclusivly focus on the former, and I'm glad this didn't happen with programming. If we read Dijkstra as arguing that only focusing on readability (i.e., natural language) is a bad tradeoff, then he is right.

pm215 11/10/2025|||
I suspect Dijkstra would have disagreed with you about "and" and "or", judging from his criticism of the technical report which had the line "even the standard symbols used for logical connectives have been avoided for the sake of clarity".

Personally I think one advantage of '&&' and '||' is that it's clear they're a notation that you need to know the syntax and semantics of. For instance typically '&&' is "short-circuiting" and will not evaluate its RHS if the LHS is true; a natural-language "if a and b then ..." doesn't suggest that critical detail or necessarily nudge you to go and check. (Not that Dijkstra was in favour of short-circuiting logical operators, to judge by https://www.cs.utexas.edu/~EWD/transcriptions/EWD10xx/EWD100... point 4...)

More generally, I'm not sure of the benefit of tailoring the language syntax for beginners rather than experienced practitioners; the advantage of '&&', '||' and the rest of the "C-like" syntax stuff in a new language is that it's familiar to a wide base of existing experienced programmers.

cubefox 11/10/2025||
We could have "and" and "cand" (conditional and, his terminology), which would be more explanatory. Or we use "and" (conditional) and "ncand" (non-conditional and). Depending on which should be the default.

> More generally, I'm not sure of the benefit of tailoring the language syntax for beginners rather than experienced practitioners; the advantage of '&&', '||' and the rest of the "C-like" syntax stuff in a new language is that it's familiar to a wide base of existing experienced programmers.

At one point in time every awkward and outdated syntax was the more familiar option, but that's of course not a good argument not to improve it, otherwise we would be stuck with it forever.

SirHumphrey 11/10/2025||||
Working a bit with some old programming languages that are very natural language like (FORTRAN’s .and. and .or. or COBOL’s IS GREATER THAN) I don’t think the readability increases that much, maybe the benefit is more approachability. In a more symbolic language skimming code is much easier because the symbols provide visible distinction between more syntactic control flow and the declared functions, variables etc.
dragonwriter 11/10/2025||||
Note that only about 1/3 of this critique (the last example, and with slightly different actual syntax in place of the preferred syntax) of "conventional programming languages" applies to the #1 language on the Tiobe index, which does, in fact, use and instead of && and or instead of || but uses ":" instead of "then" in if statements.
cubefox 11/10/2025||
Yeah that was more a criticism of the common C syntax. The use of the colon in Python is pretty good as it mirrors the usage in ordinary text. Though it still follows the pattern "if (A): B else: C" with parentheses around A. That seems superfluous.

(Unfortunately Python also follows the herd in using "=" for assignment and "==" for equality. It should arguably be "<-" or ":=" for assignment and "=" for equality. But that's a matter of asking for better symbols rather than of asking for better English operator names.)

dragonwriter 11/10/2025||
> The use of the colon in Python is pretty good as it mirrors the usage in ordinary text. Though it still follows the pattern "if (A): B else: C" with parentheses around A.

Python doesn't require parens for the condition in an if-statement, and the default settings of black or Ruff formatters will remove them if present where not needed. (They can be needed if, e.g., you are breaking a condition across multiple physical lines.)

> Unfortunately Python also follows the herd in using "=" for assignment and "==" for equality. It should arguably be "<-" or ":=" for assignment and "=" for equality.

Note that Python uses ":=" for the assignment expression operator as well as "=" for the simple assignment statement operator.

renox 11/10/2025||||
For && and || I disagree: they are 'shortcircuiting' operators and as such they deserve a différent name than just 'and', 'or'. That said &| should have been named and,or which would have freed &| to use for the shortcircuit operators.
mkoubaa 11/10/2025|||
Friend, this filter is a feature not a bug.
f1shy 11/9/2025|||
This is gold! Thanks.
adamddev1 11/9/2025||
> when judging the relative merits of programming languages, some still seem to equate "the ease of programming" with the ease of making undetected mistakes.

This hits so hard. cough dynamic typing enthusiasts and vibe coders cough

noosphr 11/10/2025|||
> Another thing we can learn from the past is the failure of characterizations like "Computing Science is really nothing but X", where for X you may substitute your favourite discipline, such as numerical analysis, electrical engineering, automata theory, queuing theory, lambda calculus, discrete mathematics or proof theory. I mention this because of the current trend to equate computing science with constructive type theory or with category theory.

https://www.cs.utexas.edu/~EWD/transcriptions/EWD12xx/EWD124...

oivey 11/10/2025||||
I’m not sure that is the focus of most serious dynamic language. For me, it’s the polymorphism and code re-use it enables that the popular static languages generally aren’t close to catching up to.
dpark 11/10/2025||
I’m curious, can you give an example that wouldn’t be solved by polymorphism in a modern statically typed OO language? I would generally expect that for most cases the introduction of an interface solves for this.

Most examples I can think of would be things like “this method M expects type X” but I can throw in type Y that happens to implement the same properties/fields/methods/whatever that M will use. And this is a really convenient thing for dynamic languages. A static language proponent would call this an obvious bug waiting to happen in production when the version of M gets updated and breaks the unspecified contract Y was trying to implement, though.

oivey 11/10/2025||
That’s basically the main example I’d give. I think the static proponents with that opinion are a little myopic. Those sorts of relationships could generally be statically checked, it’s just that most languages don’t allow for it because it doesn’t fit in the OOP/inheritance paradigm. C++ concepts seem to already do this.

The “bug waiting to happen” attitude kind of sucks, too. It’s a good thing if your code can be used in ways you don’t originally expect. This sort of mindset is the same trap that inheritance proponents fall into. If you try to guess every way your code will ever be used, you will waste a ton of time making interfaces that are never used and inevitably miss interfaces people actually want to use.

dpark 11/11/2025||
> The “bug waiting to happen” attitude kind of sucks, too. It’s a good thing if your code can be used in ways you don’t originally expect.

Rather than call it myopic I would say this is a hard won insight. Dynamic binding tends to be a bug farm. I get enough of this with server to server calls and weakly specified JSON contracts. I don’t need to turn stable libraries into time bombs by passing in types that look like what they might expect but aren’t really.

> If you try to guess every way your code will ever be used

It’s not about guessing every way your code could be used. It’s about being explicit about what your code expects.

If I’m stuffing aome type into a library that expects a different type, I don’t really know what the library requires and the library certainly doesn’t know what my type actually supports. There’s a lot of finger crossing and hoping it works, and that it continues to work when my code or the library code changes.

oivey 11/12/2025||
> Rather than call it myopic I would say this is a hard won insight. Dynamic binding tends to be a bug farm.

I run into typing issues rarely. Almost always the typing issues are the most trivial to fix, too. Virtually all of my debugging time is spent on logic errors.

> It’s not about guessing every way your code could be used. It’s about being explicit about what your code expects.

This is not my experience in large OOP code bases. It’s common for devs to add many unused or nearly unused (<3 uses) interfaces while also requiring substantial refactors to add minor features.

I think what’s missed in these discussions is massive silent incompatibility between libraries in static languages. It’s especially evident in numerical libraries where there are highly siloed ecosystems. It’s not an accident that Python is so popular for this. All of the interfaces are written in Python. Even the underlying C code isn’t in C because of static safety. I don’t think of any of that is accident. If the community started over today, I’m guessing it would instead rely on JITs with type inference. I think designing interfaces in decentralized open source software development is hard. It’s even harder when some library effectively must solely own an interface, and the static typing requires tons of adapters/glue for interop.

dpark 11/12/2025||
> Almost always the typing issues are the most trivial to fix, too.

For sure. My issue is with the ones I find in production. Trivial to fix doesn’t change the fact that it shipped to customers. The chances of this increases as the product size grows.

> It’s common for devs to add many unused or nearly unused (<3 uses) interfaces while also requiring substantial refactors to add minor features.

I’ve seen some of this, too. The InterfaceNoOneUses thing is lame. I think this is an educational problem and a sign of a junior dev who doesn’t understand why and when interfaces are useful.

I will say that some modern practices like dependency injection do increase this. You end up with WidgetMaker and IWidgetMaker and WidgetMakerMock so that you can inject the fake thing into WidgetConsumer for testing. This can be annoying. I generally consider it a good trade off because of the testing it enables (along with actually injecting different implementations in different contexts).

> I think what’s missed in these discussions is massive silent incompatibility between libraries in static languages.

What do you mean by this?

> It’s especially evident in numerical libraries where there are highly siloed ecosystems. It’s not an accident that Python is so popular for this. All of the interfaces are written in Python.

Are we talking about NumPy here and libraries like CuPy being drop-in replacements? This is no different in the statically typed world. If you intentionally make your library a drop in replacement it can be. If you don’t, it won’t be.

I am not personally involved in any numeric computing, so my opinions are mostly conjecture, but I assume that a key reason python is popular is that a ton of numeric code is not needed long term. Long term support doesn’t matter much if 99% of your work is short term in nature.

bazoom42 11/10/2025|||
It is just a classical Dijkstra strawman - hiding a weak argument behind painting everybody else as idiots. In fact it is much easier to make dangerous undetected mistakes in C than it is in Python.
js8 11/10/2025||
I downvoted you. First of all, your explanation of what "classical Dijkstra strawman" is lacks the substantiation. Second, your statement about C vs Python is a sort of strawman itself in the context of static vs dynamic typing. You should compare Python with things like Java, Rust or Haskell. (Or C with dynamic languages from similar era - LISP, Rexx, Forth etc.)
bazoom42 11/10/2025||
It is a strawman because nobody actually equates the ease of programming with the ease of making undetected mistakes.
vacuity 11/10/2025||
Presumably no one thinks "I love using [dynamically-typed language] because I can make mistakes easier", but on the other hand, isn't it the case that large codebases are written with low initial friction but high future maintenance?
bazoom42 11/10/2025||
So you agree it is a strawman?
vacuity 11/10/2025||
Perhaps Dijkstra was going for the former, but is it bad to consider a stronger argument along the lines of what he said?
bazoom42 11/11/2025||
A charitable interpretation would be he critizises e.g JavaScripts silent type coercion which can hide silly mistakes, compared to e.g Python which will generally throw an error in case of incompatible types.
huijzer 11/9/2025||
> As a result of the educational trend away from intellectual discipline, the last decades have shown in the Western world a sharp decline of people's mastery of their own language

Dijkstra already wrote this in the 80s and today many teachers still complain about this fact. I also know that, at least in the Netherlands, the curriculum is judged based on the percentage of students that pass. If too few students pass, then the material is made easier (never harder!), so you can imagine what happens if this process continued for half a century by now.

kebman 11/10/2025|
South Africa is a sad example of this. And so systems are deteriorating country-wide.
teddyh 11/9/2025||
Something which I occasionally link to, is this: <https://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF>. It not only shows why computer languages should start their indexes at 0 (instead of 1), but also shows why intervals should be specified as lower-inclusive and upper-exclusive.
ufo 11/9/2025||
That particular EWD is one of my pet peeves, because of how it always pops up in discussion about array indexing. There are several situations where 1-based indexing is better, but which Dijkstra doesn't mention. For instance, one-based is much better for iterating backwards.

I think a compelling argument can be made that 0-based is better for offsets and 1-based is better for indexes, and that we should not think of both as the same thing. https://hisham.hm/2021/01/18/again-on-0-based-vs-1-based-ind...

adrian_b 11/9/2025|||
One-based is not better for iterating backwards.

Zero-based indexing is naturally coupled with using only half-open ranges.

When using zero-based indexing and half-open ranges, accessing an array forwards, backwards or circularly is equally easy.

In this case you can also do like in the language Icon, where non-negative indices access the array forwards, while negative indices access the array backwards (i.e. -1 is the index of the last element of the array, while 0 is the index of the first element).

In languages lacking the Icon feature, you just have to explicitly add the length of the array to the negative index.

There is absolutely no reason to distinguish offsets and indices. The less distinct kinds of things you need to keep in mind, the less chances for errors from using the wrong thing. Therefore one should not add extra kinds of things in a programming language, unless there is a real need for them.

There are things that are missing from most languages and which are needed, e.g. separate types for signed integers, unsigned integers, modular numbers, bit strings and binary polynomials (instead of using ambiguous unsigned integers for all the 4 latter types, which prevents the detection of dangerous errors, e.g. unsigned overflow), but distinguishing offsets from indices is not a useful thing.

Distinguishing offsets and indices would be useful only if the set of operations applicable to them would be different. However this is not true, because the main reason for using indices is to be able to apply arithmetic operations to them. Otherwise, you would not use numbers for indexing, but names, i.e. you would not use arrays, but structures (or hash tables, when the names used for access are not known at compile time).

ufo 11/9/2025||
The problem is that half-open ranges work best when you the start is closed and the ending is open. In forward iteration we use [0,n) but for backwards iteration we have to use (-1, n-1] or [0,n-1], both of which are kinda clunky.
adrian_b 11/9/2025||
One should always use a single kind of half-open range, i.e. with the start closed and the ending open.

The whole point here is to use a single kind of range, without exceptions, in order to avoid the errors caused by using the wrong type of range for the context.

For backwards iteration the right range is [-1,-1-n), i.e. none of those listed by you.

Like for any such range, the number of accessed elements is the difference of the range limits, i.e. n, which is how you check that you have written the correct limits. When the end of the range is less than the start, that means that the index must be decremented. In some programming languages specifying a range selects automatically incrementing or decrementing based on the relationship between the limits. In less clever languages, like C/C++, you have to select yourself between incrementing and decrementing (i.e. between "i=0;i<n;i++" and "i=-1;i>-1-n;i--").

It is easy to remember the backwards range, as it is obtained by the conversion rules: 0 => -1 (i.e. first element => last element) and n => -n (i.e. forwards => backwards).

To a negative index, the length of the array must be added, unless you use a programming language where that is done implicitly.

In the C language, instead of adding the length of the array, one can use a negative index into an array together with a pointer pointing to one element past the array, e.g. obtained as the address of the element indexed by the length of the array. Such a pointer is valid in C, even if accessing memory directly through it would generate an out-of-range error, like also taking the address of any element having an index greater than the length of the array. The validity of such a pointer is specified in the standard exactly for allowing the access of an array backwards, using negative indices.

ufo 11/10/2025|||
I'm following the convention that lists the smaller value to the left. I would write [-1,-1-n) as (-1-n, -1], which is a shifted version of (-1, n-1].

The supposed advantage of 0-based indexing with half-open ranges is that the programmer wouldn't have to add ±1 to the loop bounds as often as they would with 1-based indexing. But backwards iteration is an example where that's not the case. The open range calls for a bound of n-1 or -1-n, whereas with closed ranges it would be just n.

adrian_b 11/11/2025||
[-1,-1-n) and (-1-n, -1] are not the same thing, even if they contain the same elements.

They are the same thing as sets, when the order does not matter, but the ranges used in iterations are not sets, but sequences, where the order matters (unless the iteration is not a sequential iteration "for", but a "parallel for", where all the elements are processed in an arbitrary order and concurrently, in which case there exist neither forward iterations nor backward iterations).

Therefore (-1-n, -1] is actually the same as [0, n), where the array is accessed forwards, not backwards (the former range is used with a pointer to the first element past the end of the array, while the latter range is used with a pointer to the first element of the array).

The advantage of half-open ranges is not that you would always avoid adding ±1 but that you avoid the off-by-one programming errors that are very frequent when using closed ranges.

However, if that is what you wish, you could easily avoid any addition or subtraction of 1, by using pointers instead of indices. With half-open ranges, you use 2 pointers for accessing an array, a pointer to the first element and a pointer to the first element after the array. The C standard ensures that both these pointers are valid for accessing the array.

Then with these 2 pointers you can iterate either forwards

  for (p=p1; p!=p2;) *p++;
or backwards

  for (p=p2; p!=p1;) *--p;
There is no difference between the 2 directions and the overhead is minimum.
braincat31415 11/10/2025|||
What would you do if your array is so large that it requires an unsigned int64 index?
OptionOfT 11/10/2025|||
The current AMD64 specification only uses 48-bits of pointer space, coming from 40-bits. So we still have 16 bits remaining. I'm sure we can use 1 for a sign.
adrian_b 11/10/2025|||
In C/C++ there are no true unsigned integers (true unsigned integers do overflow, generating errors in such cases or they generate carry/borrow on certain operations).

The so-called unsigned integers of C/C++ are in fact modular integers, i.e. where the arithmetic operations wrap around and where you can interpret any 64-bit number greater than 2^63-1 as you please, as either a positive integer or as a negative integer. For instance you can interpret 2^63 as either -2^63 or as +2^63.

So using 64-bit "unsigned" integers for indices does not create any problems if you are careful how you interpret them.

However, as another poster has already said, in all popular ISAs the addressable space is actually smaller than 2^64 and in x86-64 the addresses are interpreted as signed integers, not as unsigned integers, so your problem can never appear.

Some operating systems use this interpretation of the addresses as signed integers in order to reserve the negative addresses for themselves and use only positive addresses for the non-privileged programs.

The reason why the addressable space is smaller than afforded by 64 bits is that covering the complete space with page translation tables would require too many table levels. x86-64 has increased the number of page table levels to 4, in order to enable a 48-bit address space, while some recent Intel/AMD CPUs have increased the number of page table levels to 5, in order to increase the virtual address size to 57 bits.

bazoom42 11/9/2025||||
And Dijkstras argument is actually quite weak if you read carefully. But he has a certain way of writing which make it seem almost like a mathematical proof. And then he sprinkles some “only smart people agree with me” nerd baiting.
adrian_b 11/9/2025||
This is a matter of opinion. I consider Dijkstra's arguments quite strong.

Some decades ago, I have disassembled and studied Microsoft's Fortran compiler.

The fact that Fortran uses 1-based indexing caused a lot of unnecessary complications in that compiler. After seeing firsthand the problems caused by 1-based indexing I have no doubt that Dijkstra was right. Yes, the compiler could handle perfectly fine 1-based indexing, but there really was no reason for all that effort, which should have been better spent on features providing a serious advantage for the programmer.

The use of 1-based indexing and/or closed intervals, instead of consistently using only 0-based indexing and half-open intervals, are likely to be the cause of most off-by-one errors.

analog31 11/10/2025|||
In my view, zero based is good for making hardware. Resetting a pointer to zero allows using the same circuit for each bit.

Granted, that's an argument for hardware, not for languages, and even the hardware angle is probably long obsolete.

nyrikki 11/9/2025|||
While I don’t disagree with his argument for preferred conventions in an era of accumulators/gp registers, I am surprised he didn’t call out why Fortran used 1,

The IBM 704's index registers were decrementing, subtracting their contents from an instruction's address field to form an effective address.

Type A instructions had a three bit tag, indicating which index registers to use.

With those three indexes you get Fortran’s efficient 7D column major arrays. This made data aggregation much more efficient and Cray/Cuda/modern column oriented DBs do similar.

But for Algol-like languages on PDP inspired hardware I do like his convention, if like the example you have a total ordering on the indexes.

But Fortran also changed the way it was taught, shifting from an offset from memory that was indexed down from an address, which makes sense when the number of bits in an address space changes based on machine configuration, to index values.

Technically Fortran, at least in word machines meets his convention.

       pointer + offset <= word < pointer + offset +1
It is just the offset is always negative.
adrian_b 11/9/2025||
FORTRAN was defined a few years before IBM 704 (in 1954).

The use of 1-based indexing was just inherited from the index notation used for vectors and matrices in most mathematical journals at that time.

When IBM 704 was designed (as the successor of IBM 701 and taking into account the experience from IBM NORC), it was designed to allow an efficient implementation of FORTRAN, not vice-versa.

The column-major ordering of FORTRAN allows more efficient implementations of the matrix-vector and matrix-matrix products (by reading the elements sequentially), when these operations are done correctly, i.e. not using the naive dot product definitions that are presented in most linear algebra manuals instead of the useful definitions of these operations (i.e. based on AXPY and on the tensor product of vectors).

cubefox 11/10/2025||
He ignores this basic argument:

Positions in sequences like arrays are referred to using ordinal numbers (first, second, third, ...). There is no ordinal "zeroth". Ordinal numbers start at 1. This is contrary to cardinal ("how many?") numbers, which start at 0. And talking of "natural" numbers is besides the point. Therefore, referring to the seventh element in a sequence with the name "6" rather than "7" is confusing and provokes off-by-one errors.

teddyh 11/10/2025||
Using the same argument, why not place the origin point of cartesian coordinates at (1, 1, 1)?
cubefox 11/10/2025||
Those use real numbers, which are different from ordinal (or cardinal) numbers. Ordinal numbers are positive whole numbers.
zkmon 11/9/2025||
Seeing book sections or chapters starting with zero, always confuses me. I know that this convention is probably inspired by the fact that the addresses of memory locations start with zero. But that case was due to that fact one of the combination of the voltages can be all zeros. So, it's actually the count of combinations, and I don't think it can be used for ordinal enumeration of worldly things such as book chapters, or while talking about the spans in space and time (decades, centuries, miles etc). There is no zeroth century, there is no zeroth mile and there is no zeroth chapter. In case the chapter numbers are not meant be ordinal, then I think it would be odd to call Chapter 3 as fourth chapter.
asimpletune 11/9/2025||
If you’re at a corner and someone asks for directions, you say “three blocks that way”. That means three blocks starting from here.

Then what do you call “here”?

The name for where you start from in this scenario is usually not required because it’s obvious what you mean and everyone understands the first block means you have to first walk a block, not that where you start is the first block.

So in that sense yes we have a zeroth chapter. That’s when you’re at the beginning of the first one but haven’t read all the way.

oh_my_goodness 11/9/2025|||
Folks ... cardinal and ordinal numbers both have "just so" stories to support them. We're unlikely to eliminate either one of them today.
zkmon 11/9/2025|||
"here" is definitely not a zeroth block. As soon you start walking, you are in the first block. However, if you are numbering the separations (cuts) between the blocks, you can number that "here" as zero.
asimpletune 11/9/2025||
Ok as soon as you start walking your are in the first block, I agree. So then where are you before that? What block were you at before you started moving, when you were giving directions?

What is the name of the block from which you left to enter the first block? Before you started walking I mean.

And mustn’t that block be before that other first? When we move from where we start we count up, so then mustn’t an earlier block be counting down? Counting down would mean a number smaller than one.

And are blocks not counted in units, as whole numbers?

So would it not be the case that one block less than 1 must be by necessity the zeroth block?

In other words if you agree that “as soon as you start walking, you are in the first block”, then you must also agree that before you left you began in the zeroth block.

How else could it be interpreted?

zkmon 11/9/2025||
Before starting to walk, you were at the start of the first block, not at zeroth block. There is no block prior to first block. Otherwise that block would be called as first block.

Think of jogging on a road. When you are at the beginning of the road, you are at the start of the first mile, not in the zeroth mile. It doesn't have one more mile prior to first mile.

asimpletune 11/9/2025||
O you’re right. How could I forget the first minute of each day is 12:01, or that a previously unknown computer exploit is called a 1-day exploit.

And everybody knows a pandemic starts with patient 1!

bazoom42 11/10/2025||
The patient-0 terminology arose from a misreading of the label patient-O, where O is the letter O.

When numbering discrete elements you usually start with 1, so first is 1, second is 2 etc.

Indexes in C are not ordinal numbers though, they should be thought of as offsets or distances from the first element. So [0] is 0 steps away from the first element, hence the first element. The confusion arise when you think these indices are actually ordinal numbers.

asimpletune 11/10/2025|||
I agree with all of this.

The original discussion was regarding there's no such thing as a zeroth X, and what I've been trying to say this whole time is sure there is, it's the beginning. Which is why you start counting time from 0.

Interesting about patient-O though. I didn't know that.

My previous comment may have seemed snarky, but that wasn't my intention. I tried to originally write something that didn't seem sarcastic but it was just long.

The best way to explain my point was to just to agree and then list the contradictions that arise, e.g. The day starts at 12:01 since there's no zeroth minute, etc... and that unfortunately has the effect of looking like snark.

bazoom42 11/10/2025||
OK but I’m not sure I get your point then. Are you saying Edwin Aldrin was the first man on the moon because Neil Armstrong was the zeroth?
asimpletune 11/10/2025||
Not at all. Neil and buzz were first and second astronauts on the moon.

If we ask who was on the moon before them then the answer is nobody.

I think that’s agreeable. So then what am I talking about? It’s just counting.

I’m going to explain this to whomever is interested, and anyone is free to tell me where I made a mistake, in which case I will thank them for the correction.

When we talk about counting we say we are talking about things like numbers. We also talk about things, because you count things. And so counting is numbers of things. Like the number of ways to combine two dice rolls is a problem for counting.

One property of counting is that the numbers and the thing counted are separate. In other words the thing being counted does not matter when we are counting, as long as they are countable. I think that much is clear. Numbers work the same regardless of the thing being counted.

So let’s then define how counting works. Let’s say the cardinality of a set determines the “nth-ness” of the number, and the kinds of things the set holds inside is how we determine the thing we’re counting. Together, the type of thing the set holds + it’s cardinality is how we say the nth-ness of the thing being counted.

Remember the thing and the number are separate from each other, and that the count ability is also crucial. It’s the cardinality that determines the nth-ness of the count.

So then let’s count astronauts using our rule and determine who is the nth astronaut. Neil is first because when he landed on a moon, the set of all moon landers had a cardinality of 1. And buzz is second because when he landed on the moon the size of the set of moon landers is 2. Size of a set and cardinality are the same.

A set can also be empty. This set has a cardinality of 0.

So what was the set of moon landers before Neil? It was empty. In other words, there was nobody on the moon. So if we apply our rule we say that nobody was the zeroth person on the moon.

You might say that doesn’t make sense because nobody isn’t a person, but the problem is that’s a concern for the thing and not the number. We said they are separate things.

In this case we are only really interested in the nth-ness of the number and the kind of thing the set holds.

While nobody is not a person, the empty set itself definitely exists and it definitely has a cardinality of 0.

So the zeroth person on the moon was nobody. The zeroth mile is no mile. The zeroth century is no century. Some of the these things might make sense to you and some might not. But the sense that they have or don’t have in those case stem from how we think about the thing and less about the number.

I’ll give my final example.

An experiment starts at time t0. The zeroth second. Each second that is completed grows the size of our set of seconds. Nonetheless when the experiment began the set was empty. That was the zeroth second.

It’s not an actual second, but that doesn’t matter you can still count it. No second doesn’t exist but the empty set of second does and it can be counted. And in fact it’s really hard to explain counting at all if you don’t have a concept of zeroth.

That is why a zero-day exploit is called what it is because not one full day has passed since its existence has been revealed. Would first day also work, yes that’s fine colloquially but zeroth day is definitely not wrong is what I’m saying.

That is why we start the day at 00:00 in military time. Because what the time of a day means is the size of the set of hours, minutes, second, etc… that have passed. But the count starts at the empty set.

Here’s a very funny and confusing example: The day you are born is not your first “birth day”, because a “birth day” means anniversary of your birth. However the day you are born is the empty set from which that count begins. Birth day in this sense is an overloaded term in English but in many languages it’s literally called birth anniversary.

Anyways, that’s what I have to say. Probably much more than anyone wanted or needed but I hope it was at least clear what I think. If I’m mistaken then let me know.

bazoom42 11/10/2025||
Clearly there is some contradiction if you claim the first chapter in a book is the “zeroth” chapter but the first man on the moon in the first man.
numice 11/10/2025|||
That's a neat way of thinking.
lionkor 11/9/2025|||
The first element in a collection at address 15 is at address 15. The offset of an element from the start is addr-start, so 15-15=0 for the first, 16-15=1 for the second, etc.

that's why we start from 0, not because of voltages, at least in compsci.

zkmon 11/9/2025||
This is all mostly about cuts and spans in a continuum. Cuts can be numbered starting with zero, but spans can't be. Book chapters are spans of content.
griffzhowl 11/9/2025|||
Usually the chapter 0 is preliminary or prerequisite material. It makes sense in an obvious and intuitive way if you want an ordinal "before the first", even if that sense isn't a rigorous mathematical one (although I think there's no problem with it).

I guess the practice was influenced by computer science - I don't know of an example that precedes it, but one fairly early one I've found is Bishop and Goldberg's Tensor Analysis on Manifolds from 1968, with a chapter 0 on set theory and topology. Back then the authors felt the need to justify their numbering in the preface:

"The initial chapter has been numbered 0 because it logically precedes the main topics"

Quite straightforward.

There's also the "zeroth law of thermodynamics", which was explicitly identified long after the first, second, and third laws, but was felt more primary or basic, hence the need for an "ordinal before the first"

zkmon 11/9/2025||
Hopefully they don't discover another more fundamental law, to be called as "minus oneth" law
griffzhowl 11/10/2025||
Indeed
danmaz74 11/9/2025|||
The reason is that, for an array (or vector), you find the memory position for the i-th element with the base address + i*word_length. And the first element is in the base address - so has index 0.
Jtsummers 11/9/2025||
It has memory offset 0, which we use as the array index for convenience so that there's no distinction between a memory offset-base and the corresponding array index-base. That's what happens when your arrays are barely different from pointers, as in C. If your arrays aren't just a stand-in for raw pointers, then there's little reason to require 0-based indexing. You can use more natural indexes based on your particular application, and many languages do allow arbitrary indices.
aaaronic 11/9/2025|||
Building floor numbers in at least a few countries I’m aware of start from zero or “G” ( or the local language equivalent for “ground“) with 1 being the first story above the ground.

I think you’re just biased to think that starting must “naturally” begin with 1.

Zero is just a good a place to start and some people do start counting from zero.

zkmon 11/9/2025|||
The floor number case arises so because traditionally it is the count of "built" floors. So, ground is technically not a floor in that sense. Also, if the floor indicates a separation (cut) between the living spaces, ground floor can be numbered as zero, just like the start point of a measuring tape is numbered as zero.
1718627440 11/10/2025|||
There are countries that don't? Do they just skip a number and go -2, -1, 1, 2, ...?
64718283661 11/9/2025|||
A zeroeth century sounds reasonable to me.
moron4hire 11/9/2025|||
Dijkstra wrote a rather famous screed against 1-based indexing, so it's more of an inside joke.

You're also wrong about there being no 0th mile. https://www.atlasobscura.com/places/u-s-route-1-mile-0-sign

hollerith 11/9/2025||
There is however the zeroth element of a vector in most programming languages.
zkmon 11/9/2025||
Zero is not an ordinal number. There can be a vector element indexed with zero, but it is not "zeroth" element. Book chapter numbers are ordinal numbers.
vouwfietsman 11/9/2025||
But what is there to gain with this distinction?

Just the convenience of having an ordinal number to say? Rather than saying "chapter 0, chapter 1, chapter 2" one can say "the fourth chapter"? Or is it the fact that the chapter with number 4 has 3 chapters preceding it?

On first glance I find this all rather meaningless pedantry.

oh_my_goodness 11/9/2025|||
If I use ordinal numbers to count, then counting tells me the number of objects. Sometimes I want to know the number of objects.

EDIT: Yeah, I don't know why book chapter labels shouldn't start with "0". It seems fine to me. They could use letters instead of numbers for all I care.

zkmon 11/9/2025||
If they use letters instead of numbers, note that letter "A" is the first alphabet, not zeroth alphabet.
oh_my_goodness 11/10/2025||
When I'm counting letters it's more convenient to go "one, two, three." When I'm finding the offset between letters it's more convenient to go "zero, one, two." Neither of these methods is going to displace the other.

Definitions are fine, and I agree that "A" is the first letter. But that's no use to people who need to think clearly about the offset between "A" and "C" right now. Should I tell them they're wrong, they have to count to three and then subtract one? Because the dictionary says so?

zkmon 11/10/2025||
Offset is an answer to the question "where does Nth memory location start from?". The answer is "after N-1 locations". It's the count of locations that need to be skipped by the reader, to reach the start of Nth memory location.

Book chapters and page numbers are not offsets.

vouwfietsman 11/10/2025||
> Book chapter numbers are ordinal numbers

> Book chapters and page numbers are not offsets.

I don't know but I feel like you are making a point out of something arbitrary. When I listen to an audio book, everyone always says: "Chapter 1", not "the first chapter" so why is this important?

I think extreme attention to to arbitrary meaningless details is how we ended up with most rules in language that we are starting to collectively detest.

commandersaki 11/9/2025||
I really enjoy having him recall the design of a computer with the first interrupt: https://www.cs.tufts.edu/comp/150FP/archive/edsger-dijkstra/...
tiu 11/9/2025||
For the mathematically inclined, EWD717 and EWD765 have two really cool problems.

A while back someone posed EWD765 for an alternate solution, I don't recall if any other solution was found. That was my introduction to these.

[717]: https://www.cs.utexas.edu/~EWD/ewd07xx/EWD717.PDF

[765]: https://www.cs.utexas.edu/~EWD/ewd07xx/EWD765.PDF

shagie 11/9/2025||
I'm amused at EWD498 - How do we tell truths that might hurt? https://www.cs.utexas.edu/~EWD/transcriptions/EWD04xx/EWD498...

    Besides a mathematical inclination, an exceptionally good mastery of one's native tongue is the most vital asset of a competent programmer.

    ...

    The use of anthropomorphic terminology when dealing with computing systems is a symptom of professional immaturity.

    ...

    Projects promoting programming in "natural language" are intrinsically doomed to fail.
I'd also recommend EWD1305 https://www.cs.utexas.edu/~EWD/transcriptions/EWD13xx/EWD130...

    Answers to questions from students of Software Engineering
    [The approximate reconstruction of the questions is left as an exercise to the reader.]

    ...

    No, I'm afraid that computer science has suffered from the popularity of the Internet. It has attracted an increasing —not to say: overwhelming!— number of students with very little scientific inclination and in research it has only strengthened the prevailing (and somewhat vulgar) obsession with speed and capacity.

    Yes, I share your concern: how to program well —though a teachable topic— is hardly taught. The situation is similar to that in mathematics, where the explicit curriculum is confined to mathematical results; how to do mathematics is something the student must absorb by osmosis, so to speak. One reason for preferring symbol-manipulating, calculating arguments is that their design is much better teachable than the design of verbal/pictorial arguments. Large-scale introduction of courses on such calculational methodology, however, would encounter unsurmountable political problems.
ryandv 11/9/2025|
Dijkstra was so based.
PaulRobinson 11/9/2025||
I once had one of his quote on the back of my business card when I was doing a lot of software dev consultancy: "Computer Science is no more about computers than astronomy is about telescopes".

I keep meaning to sit down with this site and make my way through it all. Might make more progress if I grab them into an eReader-friendly format and then peruse them more easily when travelling.

ajdoingnothing 11/9/2025||
Astronomy is not named "Telescope Science" though. ;-)
psychoslave 11/9/2025|||
In Europe Informatics is more common than CS.
drob518 11/9/2025||||
You’re only half serious, but this is actually a good point.
PaulRobinson 11/10/2025|||
That's his point: "Computer Science" is a poor name for that area of study.
GrumpyYoungMan 11/9/2025||
The problem with that quote is that all of us reading this are telescope operators, not astronomers. The quantity and quality of our telescope photos is what we are paid for so we have no choice but to know our chosen brand of telescope inside and out.
OakNinja 11/9/2025||
I love the timeless ”Threats to computer science” https://www.cs.utexas.edu/~EWD/transcriptions/EWD08xx/EWD898...

Also the burn in the beginning of EWD899 (not transcribed) is noteworthy:

A review of a paper in AI. I read "Default Reasoning as Likelihood Reasoning" by Elaine Rich. (My copy did not reveal where it had been published; the format suggests some conference proceedings. If that impression is correct, I am glad I did not attend the conference in question.

https://www.cs.utexas.edu/~EWD/ewd08xx/EWD899.PDF

quantum_state 11/9/2025|
Truly a treasure trove … unfortunately, much of the wisdom from people like Dijkstra seems to have been forgotten or ignored by the software engineering industry.
RoguePixelDC 11/9/2025|
Since I've been playing around with AI a lot lately, I'd suggest taking a few papers and uploading them for context...seeing good examples vastly improves their subsequent programming ability.
More comments...