There is a place for history in everything familiar

Last month I researched two historical questions. I originally posted the results as threads on Twitter, but now I am duplicating them as an article.

Why vim uses hjkl

Question: Why does vim use hjkl and not arrows for navigation?

Typical explanation: To ensure that the fingers do not leave the home row.

Historical explanation: Bill Joy developed vi on the ADM-3A video terminal, which lacked individual arrow keys. If you look at the ADM keyboard, there are arrows on the hjkl keys. Joy used the same logic for vi, and later for Vim.

ADM keyboard
ADM keyboard

An even more historical explanation: Actually, it’s strange that on ADM hjkl was used for arrows. Why exactly these letters?

There is a great reason for this. Look at the 1967 version of the ASCII character table:

7 bits are allocated for each character. The first 32 are “control characters”, important for communication, but not really symbols. Computer keyboards, modeled after QWERTY typewriters, needed a way to use these characters while maintaining the same key layout. The problem was solved by adding an additional “control” key that switched input from physical characters to control ones. Pressing this key cleared the sixth and seventh most significant bits of the selected additional character. For example, if you wanted to send “backspace”, you had to hold down ctrl + H (or ^ H). This would convert 100 1000 to 1000 1000. Similarly, to add a line separator, you had to press ^ J.

If you flip through manual for ADM, you can see that “backspace” in ADM was used to mean “shift cursor left” without deleting the current character. Since ^ H and ^ J were already used as “left” and “down”, it made sense to turn ^ K and ^ L into “up” and “right”. So ADM users were already using hjkl to navigate, and Bill Joy just followed this lead in developing vi.

Why months start at zero in JavaScript

Question: JavaScript’s date API counts months as 0-11, not 1-12. Why?

Typical explanation: It’s easier to index arrays this way. We want the names of the months, not the numbers. So you can create an array containing the names and use date.GetMonth () to get the information.

Historical explanation: This is a way to maintain compatibility with Java, which in turn needs to be compatible with C.

An even more historical explanation: Then why is C done like this? And why everything related to dates in C is numbered from zero, Besides days?

For the first time the structure of fields tm_date was officially established in the ANSI C89 standard, which remains virtually unchanged to this day. The language standard came out seventeen years after C and formalized much of what was already standard on various Unix systems. If you look into Unix history, it will be found that in earliest example <ctime.c> C does not use a separate data structure, the date information is stored in an array.

#define SEC   0
#define MIN   1
#define HOUR  2
#define MDAY  3
#define MON   4
#define YEAR  5
#define WDAY  6
#define YDAY  7
#define ISDAY 8

ctime stores time as seconds-minutes-hours (SMH), although it displays them as HMS. This kind of weirdness starts to make sense when you start figuring out how the code was used. Unix 5 only used this data to show the time to users:

int *t;
    register char *cp, *ncp;
    register int *tp;

cp = cbuf;
for (ncp = &quot;Day Mon 00 00:00:00 1900\n&quot;; *cp++ = *ncp++;);
ncp = &amp;&quot;SunMonTueWedThuFriSat&quot;[3*t[6]];
cp = cbuf;
*cp++ = *ncp++;
*cp++ = *ncp++;
*cp++ = *ncp++;
tp = &amp;t[4];
ncp = &amp;&quot;JanFebMarAprMayJunJulAugSepOctNovDec&quot;[(*tp)*3]; // (a)
*cp++ = *ncp++;
*cp++ = *ncp++;
*cp++ = *ncp++;
cp = numb(cp, *--tp); // (b)
cp = numb(cp, *--tp+100); // (c)
cp = numb(cp, *--tp+100);
cp = numb(cp, *--tp+100);
cp =+ 2;
cp = numb(cp, t[YEAR]);


I have commented on a couple of interesting lines. First, we use the saved month in (a). Instead of storing the names of all the months in an array, the developers wrote the three-letter abbreviations of each month on one line, and then used the month number to compute the pointer to get the three bytes needed. Then, in (b) they get the day and time in HMS in (c), decrementing the pointer address three times. Storing time in SMH allows you to get rid of the extra explicit jump (since they iterate over values ​​in reverse order). The developers took advantage of the fact that since fields are stored as array elements, they are located in one place in mind

All this tells us that they have optimized every little thing… Which makes sense, since the first versions of Unix were built on PDP-7 computers. A decent 1970s computer could only have a couple of kilobytes of memory. And if we tried to store the names of the months in memory, it is possible that they would take up almost 10% of all RAM!

Developers needed to be careful to use as little memory and CPU as possible, and address arithmetic helped save money on both – and arithmetic is easier if the months are numbered from zero instead of one. However, the day of the month was never used for anything other than displaying to user (b), so it was stored directly in representable form.

This story also explains a slight inconsistency in the structure: MDAY (day of the month) starts at one, and YDAY (day of the year) starts at zero. However, this makes sense for the compute versus display dilemma: the day of the year was never shown to the user. It was only used to calculate the daylight saving time (Sunday local time).


Both explanations are incomplete. You can dig even deeper than “just” two levels of history down. Regarding the question about hjkl, it would be reasonable to ask why the ASCII table is arranged in this way. With the tm_date story, you can take apart earlier versions of Unix, see what happened there, or talk to the creators directly. And even these are not the only options. There is always where to dive further, overcoming the layers of history one by one.

But two are enough for this article. At two levels, one can see a general pattern in the study of history, notice the difference between answers and interpretations. When asked why something looks the way it looks, most people will give a rationalized post-facto answer. Most likely, thoughts about why this is “better” will come to them based on the present. However, if you look a little into the past, you will find that more often than not everything just “happened historically.” And if you look even further, you can find out what kind of “forces” led to this state of affairs.

This difference between the first and second layers of the story leads to a very annoying trap. People look to the top and assume that’s all – which makes the story seem out of place. And even when we understand that the historical background is greater than originally thought, the excavation of each new layer requires significantly more work than the previous one. You can find out that Bill Joy used the ADM-3A from the first line of Google. It took me two hours to find out the deeper reasons.

But it was worth it. As you delve deeper into the second level, you can discover a lot more about the context and the reasons why things are the way they are. And of course, it cannot be denied that there is a piece of the puzzle in this process, and therefore the pleasure of discovering an explanation of the mystery. The lost knowledge is regained.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *