If you traveled to Japan in the 1980s, 90s, or 2000s, you would have seen a lot of phone booths around with a big ISDN sign lit up. For their time, these payphones looked positively futuristic. Here we can see one “in the wild”.

The interesting thing about these phones is the little flap on the lower right side of the face panel. Here it is again, closed and open:


The reason for this is that Japan’s national phone carrier, NTT, had a vision for the future in which people who were out on the road with their mobile computing devices would stop off at a payphone and plug in to make “data” calls. ISDN was an international standard for a natively digital phone system, which offered 64 kbps line speeds. Here’s someone making a data call now:

However, to make a data call, the person/device you were calling also had to support ISDN. So the ISDN payphones also supported plugging in a traditional analog modem, which at the time probably supported 9.6 kbps:

The Legacy of ISDN Phone Booths
Back before 1992, these ISDN phone booths were really the only form of mobile networking that was available. The Internet was still in its infancy (web browsing had not been invented yet), and very few companies were connected to it. If a company did have a network, it tended to be private network running a proprietary mail system only accessible via modem. If you were a traveling engineer or salesman, you realistically had no access to your home network from a client site unless they were willing to let you plug your modem in, something that was not possible with many PABX systems. This lack of mobile connectivity rendered the concept of laptop computers and PDAs (personal digital assistants) irrelevant to a large majority of potential users. In Japan, however, this access to public data ports created a larger market for these devices which the Japanese electronics manufacturers were able to capitalize on. This was just one of many factors that helped the Japanese electronics boom of the 1980s and 90s.
After digital mobile phones appeared in 1992, the ISDN phonebooths basically became dinosaurs overnight. However, they were backed by a huge public infrastructure in the form of a digital network spanning the country. This underlying ISDN infrastructure formed the backbone for a Japan-specific mobile technology called PHS, which I will get into in a later post. (Many European countries had also adopted ISDN, but not for their payphone networks, and so the PHS technology was really only feasible in Japan.) This was the beginning of the Galapagos effect in mobile technology – the phenomenon where Japanese mobile phone technology became completely disconnected from western technology through the 1990s and 2000s. Although public payphones in Japan still use ISDN, models sporting data call ports have all but disappeared from the streets of Japan.
Just to wrap up, I thought it is interesting that when you plugged a regular modem into an ISDN phone system, you essentially had a digital signal (the actual computer data) carried within an analog signal (the phone line coming out of the modem) carried within another digital signal (the digital ISDN line). Now, if you really wanted to get all Inception with your phone calls, you could run an IP telephony app like Skype on this computer and make 4 layer-deep a/d/a/d voice calls. And if you were making that voice call to an old school answering machine where you used an audio beeper to send commands to the answering machine, you could get another layer on top to get a nested d/a/d/a/d communication channel. These days, we can just skip it all and go direct to digital.
Related Posts
Real-World Code Complexity
What do I mean by real-world code complexity? Well, I don’t mean cyclomatic/algorithmic complexity or even obfuscated C style complexity. What I mean by real-world complexity is the series of changes that a code base will necessarily go through its existence that will make every function grow by a factor of between 2x and 10x lines of code without actually doing anything it didn’t do before. It’s generally the kind of complexity that we can never account for in the design stage because there is simply no way to determine that it exists until we are there coding the details. Here is a non-exhaustive list of some examples:
Symptoms and Solutions
In general, a symptom that you have incurred this kind of technical debt is that you have functions that nobody wants to work on. You look at it, and despite the use of modern structured programming principles, it still looks and feels like spaghetti code. At this point, most people would say that the solution is to rewrite the code using a better design. However, I think first we should look at why our modern language and programming structures are unable to cope with this kind of imminently foreseeable and virtually inevitable evolution of a project. I feel that in some cases, our modern coding practices are purely designed around the idea of creating clean brand-new code, but are completely ill-suited to the evolution of code as it ages. The following are links to some articles I’m posting about specific issues. I’m going to add to these over time.
while and the for loop. Unfortunately, I think it’s fair to say that they also contribute to the kind of complexity in code that can be a source of technical debt. I’m going to look at one of the problems with these loop constructs.
While Loops
The while loop is probably the most primitive of loops possible. If we come across a while loop while reading code, all we know is how the loop will end. However, we don’t generally know what is going to cause that condition to occur. Of course, there are some things for which while loops are naturally suited. Probably the best example is the main processing loop such as for message and event based applications. For example, in the following code it is pretty clear how the loop will end.
while (app.IsRunning()) {
event e;
app.GetEvent(e);
app.ProcessEvent(e);
}
For Loops
In contrast, the for loop in C and most other languages is an excellent construct in terms of readability. It tells you right from the outset exactly what you’re getting, both in terms of the termination condition and ensuring that the necessary changes are going to happen to get there. Take the following example. Even without comments, it’s pretty clear what you’re going to get. Although we could perform the same thing using a while loop, the for loop is infinitely more readable:
for (int retry = 0; retry < 5; retry++) {
...
}
One task that for loops are particularly suited to is looping over the elements in a collection. Let's take a look at an example of looping over some kind of vector using regular old for syntax:
vector vec;
for (int index = 0; index < vec.size(); index++) {
ProcessElement(vec[index]);
}
As before, it's pretty clear what's going on even without comments. Now, let's consider a fairly normal sequence of changes. First, we get some additional condition where we don't want to process certain elements. This means we have to use the continue statement. The syntax here is pretty clear. Continue means continue on with the loop.
vector vec;
for (int index = 0; index < vec.size(); index++) {
// Don't process if paused
if (vec[index].state == PAUSED) continue;
// Don't process if underlying connection closing
if (vec[index].con_state == CLOSING) continue;
ProcessElement(vec[index]);
}
This is still fairly easy to follow. But what happens now if we discover we also need to delete elements from within the loop? Well, now we have a problem because we'll end up skipping an element when our index is incremented by the for loop. In this particular case, we could probably just pre-decrement the index before looping, but that's not going to work in the general case. Instead, we have to convert our for loop to a while loop:
vector vec;
int index = 0;
while (index < vec.size()) {
// Don't process if paused
if (vec[index].state == PAUSED) continue;
// Don't process if underlying connection closing
if (vec[index].con_state == CLOSING) continue;
ProcessElement(vec[index]);
// Increment loop variable:
index++;
}
Here, if you are an experienced programmer (or even an inexperienced programmer), you should be able to see the problem that we have. Our two conditions at the start of the loop are broken. The problem is that the continue statement in the for loop means something slightly different from the while loop. Yes, they both mean to continue, but one means to continue after advancing to the next element, the other means repeat the loop without changing anything. Our continue no longer continues anything. Before I go into this further, let's see the correctly converted while loop:
vector vec;
int index = 0;
while (index < vec.size()) {
// Don't process if paused
if (vec[index].state == PAUSED) {
index++;
continue;
}
// Don't process if underlying connection closing
if (vec[index].con_state == CLOSING) {
index++;
continue;
}
ProcessElement(vec[index]);
// Increment loop variable:
index++;
}
And then once we add our delete condition:
vector vec;
int index = 0;
while (index < vec.size()) {
// Don't process if paused
if (vec[index].state == PAUSED) {
index++;
continue;
}
// Don't process if underlying connection closing
if (vec[index].con_state == CLOSING) {
index++;
continue;
}
// Delete zombies:
if (vec[index].state == ZOMBIE) {
vec.erase(index);
continue;
};
ProcessElement(vec[index]);
// Increment loop variable:
index++;
}
Is this a big issue? Well, it obviously is an issue if we're forced to convert a for loop to a while loop for any reason. From personal experience, infinitely repeating loops under only certain conditions often arise from this kind of error. Our code only hangs if it happens to meet the conditions for skipping the processing, which can sometimes mean only under certain very specific and hard-to-reproduce conditions. However, I think the bigger problem comes in terms of readability and maintenance. The first issue is that the first line of the while loop doesn't really tell us the full story about how our loop is going to end. Without the variable increment statement, it could potentially run forever.
For the second issue, let's say you are a maintenance programmer and you have to add some conditions to this kind of construct. You've gone down and added your special processing case, and now you need to bail out of the loop early and move onto the next element. It's no longer simply a matter of writing continue at the end of your case. First, you have to find out if you are in a for or a while loop. And if you are in a while loop, where do you find the code that moves onto the next element? In an ideal world, it would be clearly detailed at the bottom of the loop. But most world's aren't ideal, and your probably going to scroll down to the bottom of the loop and be left wondering exactly which parts of that code are needed for advancing the loop, and which parts are just part of the main loop body processing.
Can We Do Better
I think the heart of the problem is the use of the same keyword to mean two different things. What we really need is two different keywords. My proposal would be next and repeat. This makes things a whole lot easier for maintenance. next means advance to the next element in the collection. repeat means loop without advancing the loop variable. Using this would give us:
vector vec;
for (int index = 0; index < vec.size(); index++) {
// Don't process if paused
if (vec[index].state == PAUSED) next;
// Don't process if underlying connection closing
if (vec[index].con_state == CLOSING) next;
// Delete zombies:
if (vec[index].state == ZOMBIE) {
vec.erase(index);
repeat;
};
ProcessElement(vec[index]);
}
Related Posts
]]>
The Bool Asymmetry
One of the main problems with boolean types is the asymmetry between writing and reading code. Writing code using bools is extremely easy. Reading and modifying existing code that uses bools, on the other hand, is where the trouble begins. Let’s take a quick example. Suppose we have some kind of function that parses text data from a buffer:
void ProcessBuffer(void *buffer)
But later we need to add support for Unicode. So we modify our function to handle the Unicode. If we were Windows programmers this would mean UTF16. The easiest way to go is to add a bool with a default parameter. This way, we don’t need to change any existing code.
void ProcessBuffer(void *buffer, bool is_unicode = false)
But then we need to add support for UTF8 because our code is starting to get UTF8 input in some file formats:
void ProcessBuffer(void *buffer, bool is_unicode = false, bool is_utf8 = false)
Then the situation arises where we need to process big endian UTF16 as well as little endian:
void ProcessBuffer(void *buffer, bool is_unicode = false, bool is_utf8 = false,
bool is_utf16be = false)
And later the function is called in cases where we have to deal with Unicode normalization, and even later we discover that we need to be able to handle two different normalization forms, giving us:
void ProcessBuffer(void *buffer, bool is_unicode = false, bool is_utf8 = false,
bool is_utf16be = false, bool normalize = false,
bool normalize_D = false)
The above sequence of events is not particularly far fetched. I could almost guarantee that every experienced programmer has come across a situation where adding a bool to a function is the easiest solution. So what’s the problem? Well, when we are writing code that calls this function, it’s not too big a deal. Our IDE will pop up the parameter list when we are writing code to call the function, and as long as we have named the parameters appropriately, it should be pretty easy to get the value right. However, what happens if we come along at a later stage and need to read this code? Well, then we are faced with something like this:
// Process the buffer as utf-8
ProcessBuffer(buffer, true, false, false, true, false);
Can you spot the bug in this code? The problems for a person reading the code should be abundantly clear. There are quite a few problems here, and no amount of static analysis is going to help us out. Probably the worst problem with this code is the misleading comment. Rather than helping us understand the code, it actually gives us false confidence about the meaning of the boolean value.
Enums FTW
A better option in terms of readability is using an enum. If we had started off the same example except using enums, we would probably end up with something like the following sequence of changes:
enum {
eLegacyEncoding = 1,
eUnicode = 2
} encoding_t;
void ProcessBuffer(void *buffer, encoding_t encoding = eLegacyEncoding)
enum {
eLegacyEncoding = 1,
eUnicode = 2, // Keep for backwards compatibility or refactor out
eUTF16 = 2,
eUTF8 = 3
} encoding_t;
void ProcessBuffer(void *buffer, encoding_t encoding = eLegacyEncoding)
enum {
eLegacyEncoding = 1,
eUnicode = 2, // Keep for backwards compatibility or refactor out
eUTF16 = 2, // Keep for backwards compatibility or refactor out
eUTF16LE = 2,
eUTF8 = 3,
eUTF16BE = 4,
} encoding_t;
void ProcessBuffer(void *buffer, encoding_t encoding = eLegacyEncoding)
enum {
eLegacyEncoding = 1,
eUnicode = 2, // Keep for backwards compatibility or refactor out
eUTF16 = 2, // Keep for backwards compatibility or refactor out
eUTF16LE = 2,
eUTF8 = 3,
eUTF16BE = 4,
} encoding_t;
enum {
eDoNotNormalize = 1,
eNormalizeC = 2,
eNormalizeD = 3
} normalization_t;
void ProcessBuffer(void *buffer, encoding_t encoding = eLegacyEncoding,
normalization_t norm = eDoNotNormalize)
And now, spotting the bug is so much easier:
// Process the buffer as utf-8
ProcessBuffer(buffer, eUTF16, eNormalizeC);
In fact, the readability is improved so much that the preceding comment becomes superfluous.
Return Values
Above we saw the problem as applicable to function arguments. For return values, things are a little bit different. For functions that are boolean in nature, using a bool return type is fine. For example:
bool IsQueueEmpty()
When viewed in context, readability is preserved
// Close once the queue is empty:
if (IsQueueEmpty()) {
Close();
}
Where problems tend to arise is when a function needs to be modified to return just a little bit extra information. The temptation to simply change a void return type into bool is strong, but the cost is reduced readability. Take a look at the following prototype. What do you think the return value represents?
bool GetMessage(msg_t *message)
The answer is that everyone will interpret this differently. For me, I would assume that a return value of false indicates no message to get, while true would indicate a message was returned. However, it could just as easily be that a return value of false means error and true means no error (but not necessarily that a message was returned). And if you’re a Win32 programmer, you might guess that a return value of false indicates that a quit message was received, whereas true indicates either a non-quit message or an error. (This is how the Win32 GetMessage function actually works.) It could mean anything. Unfortunately, when we’re writing a function like this, the intended meaning seems clear because the problem we are trying to solve is fresh in our minds. It’s only after you have to come back to some code that you haven’t touched for a while that the opacity of the function meaning becomes clear.
Why We Don’t
One of the reasons people opt for the boolean over the enum or named constant route is that it is just so easy. Writing enums involves added boilerplate, and fills up your namespace with types that are only applicable in very specific contexts. Your function prototype/interface changes from a single line to multiple lines of code. Nevertheless, if you are interested in the future readability of your code, I think the tradeoffs are worth it.
The Guidelines
After hitting the same problems of readability in my own code many, many times, I now have a set of guidelines I try to follow. The increased readability of old code really makes it worthwhile. The basic rule:
However, the following important exceptions apply:
Examples in the Wild
To close with, I want to share an example of a bug that a co-worker recently found in an open source project. Can you spot the error? Without access to the function prototypes, the bug is completely invisible.
if (mysql->options.connect_timeout >= 0 &&
vio_wait_or_timeout(net->vio, FALSE, mysql->options.connect_timeout * 1000) < 1)
{
my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
ER(CR_SERVER_LOST_EXTENDED),
"handshake: waiting for inital communication packet",
errno);
goto error;
}
if ((pkt_length=net_safe_read(mysql)) == packet_error)
{
if (mysql->net.last_errno == CR_SERVER_LOST)
my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
ER(CR_SERVER_LOST_EXTENDED),
"handshake: reading inital communication packet",
errno);
goto error;
}
Now suppose that we replace the boolean FALSE on the second line with a descriptive enum label such as IO_WRITE. See the bug now?
]]>
ASCII
ASCII is important because it basically defined the subset of punctuation marks and symbols that would be used in every programming language and operating system that followed. Just to make things absolutely clear, ASCII is a 7-bit encoding. There is no such thing as 8-bit ASCII. If you ever hear anyone talking about 8-bit ASCII, what they actually mean is an 8-bit encoding that uses the printable ASCII characters (32 to 126) plus maybe 2 or 3 of the control codes (LF, CR, TAB). Now, you might not realize it, but ASCII was actually designed to be a family of 7-bit encodings with some characters designated “national variants” which would be defined differently in different countries. For example, the British variant of ASCII replaces the hash (#) symbol with the pound (£) sign, while the Norwegian version replaces square brackets ([]) with Æ and Å and braces ({}) with æ and å. While this is not a problem for telegraph, it creates obvious problems for programming. C, for instance, makes extensive use of square brackets and braces. The result is trigraphs in C, where the sequences ??( and ??) can be used instead of square brackets, and ??< and ??> can be used instead of braces. (See ISO/IEC 646 and trigraphs for more information.) Given this mess, it wasn’t long before the national variants of ASCII disappeared and were replaced by 8-bit encodings. When people talk about ASCII these days, they are almost always referring to the original US variant of ASCII which was the basis for C and most other modern programming languages.
ASCII-based 8-bit Encodings
Switching from a 7-bit encoding to an 8-bit encoding gives us an extra 128 code points, and this fixes a lot of problems. Most importantly, it means that all of the national variant characters can be moved out of the lower 128 codes. Now, we have a truly common basic set of 128 characters that OS and language creators can freely use as standard characters without having to worry about trigraphs or other cludges. Secondly, we can now support languages such as Greek and Cyrillic (Russian) which require many more additional characters than could fit in the limited number of national variant characters in ASCII.
UNIX, Terminals, and C1
UNIX is essentially a terminal-based system. For the youth out there who don’t know what a dumb terminal is, it’s a piece of equipment with a character-based screen (typically around 80×25 characters) and a keyboard which gets connected to the UNIX server by a serial line. If you send text to the serial port of the terminal, it is the terminal that decides which actual character to print on the screen. Similarly, when you press a key on the keyboard, it is the terminal that decides which code to send to the UNIX server. On top of this, this same communication channel needs to be used for sending control sequences, such as for moving the cursor, clearing the screen, and these sequences are all sent in-line intermixed with the character codes. This means that we can’t assign characters to every code point. We need control codes, and these control codes cannot overlap the characters in the character encoding.
Now, the block of control codes 0 to 31 (known as the C0 block) as well as code 127 in ASCII are already allocated to control codes. Their meanings might not necessarily match the ASCII definitions, but that is irrelevant. They cannot be used for encoding printable characters and many have well-defined functions. Next we have the printable ASCII range of 32 to 126. Virtually all of these have some special significance (be it as command names, directory separators, shell escape characters, programming language symbols, etc.), and cannot be changed. Codes 128 and above, however, are a free-for-all. Terminals can use them as control codes, printable characters, or basically anything and it doesn’t matter to the UNIX server. As long as all of the different terminals connected to a server agree on the meanings of the printable characters, everything will work fine. We can even connect terminals that use different control characters, as long as those blocks of control characters do not overlap the printable characters.
For reasons of consistency and interoperability, a recommendation was developed that codes 128 to 159 should be reserved for a second control block (called the C1 block), and only codes 160 to 255 be used for printable characters, and this formed the basis for most pre-Unicode UNIX encodings. However, it is not a hard and fast rule, and UNIX itself does not treat the C1 block any differently from the rest of the upper 128 codes.
This makes UNIX basically language agnostic. Let’s say we have a UNIX system and we have two files with names consisting of the character codes 68 196 and 68 228. When we connect a Greek language terminal to the system and list the files, we will see “DΔ” and “Dδ”. When we connect a French terminal to the system, we will see “DÄ” and “Dä”, and when we connect a Thai terminal we will see “Dฤ” and “Dไ”. The fact that the three different terminals show 3 different things doesn’t matter. A Thai user can still open one of the files by typing “vi Dฤ” on their keyboard, the same as the Greek can by typing “vi DΔ”. As far as the OS is concerned, as long as the underlying codes are the same, everything works fine. We might note here that “δ” is the lower case letter for “Δ” in Greek, whereas “ฤ” and “ไ” are completely different unrelated letters in Thai. This doesn’t matter to UNIX because the OS doesn’t try to do anything fancy like case-insensitive file names. The same applies to file content. If you print a file to the screen, the codes gets passed directly to the terminal, and it is the terminal that does the rendering. The OS doesn’t need to get involved.
In fact, on a UNIX system we can simultaneously use as many different encodings as we like. We could create separate subdirectories for different languages, and as long as the users accessing those subdirectories used terminals set up for the same encoding, everything will work fine. Thus UNIX itself does not need an “encoding” setting. It simply doesn’t care. In Thailand, we connect Thai language terminals to our server. In Greece we connect Greek language terminals.
However, any command or system service that is going to output human-readable error messages needs to know which language to output. Similarly, any add-on programs, particularly those that might perform some kind of collation or text processing, want to know what language they should use. But again, this does not need to be a system-wide setting, and only need apply to a particular user’s session. The system thus uses an environment variable (LOCALE) which specifies both the language and character encoding.
DOS/Windows
DOS (and later Windows 95/98/Me), on the other hand, is a different kettle of fish. First, there is the matter of control codes. Since the screen is addressed directly through the video adapter, we don’t need any control codes. The original DOS encoding (code page 437) assigned printable characters to all of the ASCII control codes (0 to 31 and 127) as well as to all of the codes above 128, but is still considered ASCII-based because it maintains all of the ASCII printable characters (32 to 126). Now it turns out that this is a step too far. While the line feed character might be meaningless if we are directly addressing the screen, it is certainly helpful for indicating new lines in text files. We also run into problems communicating say with an ASCII serial printer which uses the ASCII control block for printer control sequences. For compatibility with any kind of hardware device, we really can’t assign printable characters to the C0 control block, and Windows 95 thus used encodings that do not use C0. However, Windows 95 has no need for terminal control codes, and the C1 control block (128 to 159) is thus assigned to printable characters.
The other issue which is particularly relevant for Windows 95/98/Me is that it uses case-insensitive file names, and for this to work, the OS needs to know the encoding. For example, the codes 196 and 228 are the same letter – lower case delta (“δ”) upper case delta (“Δ”) in Windows-1253, but different letters (“ฤ”) and (“ไ”) in Windows-874. Windows thus requires a system-wide encoding setting. This is not such a big problem for single-user systems, but when we start networking computers together in a business setting, things go awry. For example, on a Thai language computer, we can have two files named “Dฤ” and “Dไ”. However, if we try to copy these over the network onto a Greek-based computer, we get a problem. As far as the Greek computer is concerned, the two files have the same file name, and one file will mash the other file. We cannot have a single file server that stores files from all of our different international offices. It isn’t going to work. Similarly, we can’t create a web server that supports multiple different sites that use different languages. It should come as no surprise then that Microsoft was one of the big backers of Unicode and produced one of the first Unicode-based OSes.
Programming With 8-Bit Encodings
At this point, programming is actually pretty easy. In most cases, you don’t even need to write encoding-aware software. A C compiler, for example, doesn’t need encoding-awareness. All localized characters (codes 128 and higher) can only appear in comments or string/char literals. Comments are ignored and literals are simply copied into the data as-is. Things like regular expressions (and so vi/sed/awk/etc.) similar don’t need to know the encoding. All characters are byte-based, so as long as the person using these programs inputs the correct expressions for their language, they will work fine. (For example, a Norwegian person wanting to match all upper case letters is going to have to use the regexp /[A-ZÆØÅ]/ instead of /[A-Z]/, but the actual regular expression parser does not need to be changed). The basic assumption is that we have the same encoding end-to-end, so tools don’t have to do any conversion, they just spit out whatever input they get in.
If we do want to do language-dependent operations such as collation or upper/lowercase conversion, the set of functions needed to achieve this is minimal. Collation is not even truly an encoding issue, since sort orders can vary between languages even if they use the same encoding. In C, this is handled using a few simple functions. The locale setting (in <locale.h>) defines both the language and encoding. <ctype.h> is the only encoding library we need, with functions for determining the type of a character (isnum(), isupper(), islower(), isalpha(), etc.) and converting upper to lower case (toupper()/tolower()). Collation is language as well as encoding dependent, and is supported by strcoll() and strxfrm() in <string.h>. This is all we need. Here is some example code you can run to see it in action.
#include <locale.h>
#include <ctype.h>
#include <stdio.h>
int main() {
// West Europe: 198 = Æ, 230 = æ (upper case and lower case letters)
setlocale(LC_CTYPE, ".1252"); // On UNIX, use ".iso-8859-1"
printf("%d %d\n", (isupper(198) ? 1 : 0), (isupper(230) ? 1 : 0));
printf("%d %d\n", (islower(198) ? 1 : 0), (islower(230) ? 1 : 0));
printf("%d %d\n", (isalpha(198) ? 1 : 0), (isalpha(230) ? 1 : 0));
// Thai: 198 = ฦ, 230 = ๆ (letters, but neither upper or lower case)
setlocale(LC_CTYPE, ".874"); // On UNIX, use ".iso-8859-11"
printf("%d %d\n", (isupper(198) ? 1 : 0), (isupper(230) ? 1 : 0));
printf("%d %d\n", (islower(198) ? 1 : 0), (islower(230) ? 1 : 0));
printf("%d %d\n", (isalpha(198) ? 1 : 0), (isalpha(230) ? 1 : 0));
return 0;
};
Multibyte Encodings
All of the encodings we’ve discussed up to now have been single byte encodings, with one byte = one character. However, for the East Asian languages of China, Japan, and Korea (often abbreviated CJK), one byte simply isn’t big enough to hold all of the possible combinations. The only choice is to use multiple bytes to represent a single character. Since all of these encodings still use single bytes for ASCII, they are all variable-length encodings. For compatibility with ASCII-based systems, the characters are generally arranged into pages of 94×94 (2 bytes) or 94x94x94 (3 bytes) characters which can either be overlaid on the character codes 33 to 126 (for transfer across 7-bit communication channels – an idea that is only really used in practice for SMTP-based email) or the character codes 161 to 254 (for 8-bit encoding). The preferred encoding for these character sets on UNIX is a system called EUC (extended unix code). The basic idea is that all non-ASCII letters are encoded as multi-byte sequences with all bytes in the 128 and higher code range. This means that we can suddenly start naming files in Japanese and Chinese without making any changes to the underlying OS, and in fact a lot of parsers and compilers are still going to work fine without making any specific changes to support multi-byte characters. We can still run an encoding-agnostic C compiler, since the multi-byte sequences only occur in comments and literals.
However, there are issues. We can’t just write char mychar = '字'; since this will appear to the compiler as 2 characters. We also have substring searching issues which mess with things like regular expressions. Consider the string “月月”. This consists of the 4 bytes 183 238 183 238. Let’s try searching for the character “詞”. We shouldn’t get a match, except that the encoding of “詞” is 238 183. For a lot of things, this isn’t going to be an issue, because the kinds of keywords we want to search for with reg exps in programs tend to be ASCII, but it does close the option. Finally, we have an issue that is virtually never addressed by any standard library, which is the problem of display width. Most CJK characters take up the same space as two ASCII characters when output to a fixed-width display such as a UNIX terminal, Windows command prompt, or fixed-width printer. For example, if we want to print a nicely formatted table of text data from a DB and we only allocate 20 characters worth of space for a large text column, there is nothing in the C standard library or in our database string functions that can extract the first 20 ASCII-characters wide worth of data. mblen() can tell us that a character uses 4 bytes of data, but there is no corresponding function to tell us if that character uses 2 ASCII character cells or only 1.
In the world of DOS and Windows 95, however, things are much worse. As an example, let’s look at Japanese. NEC licensed MS-DOS from Microsoft and modified it to create a version of DOS called DOS/V which worked with the Japanese multibyte encoding called Shift JIS. (They needed to modify the source code to work with the specialized hardware for displaying Japanese characters, something I’ve covered before.) The reason for choosing Shift JIS is that it plays nice with terminal-style fixed-width font row/column displays. Single byte Shift JIS characters always take up a single character cell on the screen, and double-byte Shift JIS characters always take up two character cells. We can thus always represent an 80-column row using char[80] without messing about with variable-width buffers. However, in order to achieve this magic, two-byte sequences in Shift JIS limit the first character to the range 128 to 255, but allow the second character to extend into the ASCII range with codes from 64 to 126 + 128 to 252. (There is a gap at 127 for the ASCII DEL control code). Probably the biggest compatibility-killer in this range is the code 92 – the backslash. There are 42 different characters which have this code as the second character. Why is this a problem? Well, try this innocuous example:
printf("十");
What happens when you try to compile this without rewriting your C compiler? You get an error. The C compiler sees something equivalent to:
printf("X\");
The second byte is interpreted as a backslash that escapes the closing quotation mark, and we have a string that is not closed. While we are going to get a compilation in this example, for many other cases the code compiles and runs but with occasional garbling of text. If you tried connecting a Shift JIS terminal up to a UNIX box, you’re going to have the same problem. If any file name or string contains this character, the shell is going to perform escape processing and mangle the string. We can’t even escape the problem character, because our escape will only apply to the first byte of the multi-byte. The Chinese encodings used in Windows (Big5 in Taiwan and GBK in mainland China) function basically the same way as Shift JIS, using characters 64 to 126 + 128 to 254 for the second byte. Even today, descendents of these encodings are used in Japanese and Chinese versions of Windows 7 and 8 as well as in loads of industrial and embedded computing equipment.
Prior to Unicode, the C and C++ standard libraries do not have any functions for handling CJK encodings. There is the mblen() function which tells us how many bytes a character takes, but we can’t do anything with a character once we extract it. We can’t use the <ctype.h> functions and we can’t even use the strstr() function in <string.h> or the string::find() function in <string> because of the possibility of false matches. Microsoft Visual C does provide an <mbstring.h> library that you can use, but you lose compatibility with UNIX. Your best option is to provide your own library.
At this point, I want to briefly summarize the encoding world before Unicode. Firstly, just about every application runs off the idea of a single encoding end-to-end. On UNIX, in particular, many protocols are encoding agnostic. They simply take encoded data and pass it directly through. FTP is a great example. It has no concept of encoding or any way of specifying encodings. Whatever raw character data it receives it sends on through untouched. It’s up to the sys admin to make sure everyone using it sticks to the same encoding. We can even have Windows boxes talking in Windows-specific encodings that can use a UNIX FTP server (with the specific exceptions of Chinese and Japanese), and in fact this is something that still occurs today.
On Windows 95/98/Me, things get messed up if we mix encodings, so we really have to stick strictly to the single encoding deal. For programmers, if you want your program to work on CJK systems, you have to use the non-standard <mbstring.h> library in MSVC or some equivalent third-party library.
Let’s have a look at a typical scenario where we have a dev on a Windows box using a UNIX server to host an app. We create some html files on a Windows box and give them international (Greek/Thai/whatever) names. When we upload the files to a UNIX box via FTP, the files retain their Windows encoded names. To access them via http, you again specify the Windows encoding of the names (using %xx notation for chars above 128) and the browser fetches the files. At no stage does it matter what language or encoding the owner of the UNIX box is using. The same applies to things like includes or local file access from script/cgi. Since the html/source files were edited on Windows, they get saved in that same Windows encoding. However, scripts run into problems if they perform any collation/upper/lowercase conversions, since the LOCALE environment setting from the UNIX box isn’t going to match the content of the files, so we have to set the LOCALE setting manually in our script. Similarly, we have to specify the file encoding in the <meta http-equiv="Content-Type" content="text/html; charset=xxx"> tag to override the default value of the http server. Finally, if we are going to use a database, we similarly have to make sure that we explicitly set the correct encoding (i.e. the Windows encoding) instead of using the default value from the UNIX box. Although I used Windows as an example, the client can be Mac/Linux/anything. We just need to make sure that the encoding is always set to the encoding of the developer client, not the encoding of the server.
At this point, things actually work pretty well. There are only 2 issues. One is the complete lack of support for CJK, and the other is the inability, for example, to mix Greek letters with Western European script.
Unicode
The very first thing we need to understand is that UTF-8 did not exist and was not envisioned when Unicode first came into use, and Unicode referred basically to what we now call UTF-16. The way Unicode was envisioned is best exemplified by the operation of Windows NT. Windows NT was the first major OS based on Unicode, and was coupled with NTFS, the first major filesystem to support Unicode. However, NT still had the concept of a default non-Unicode encoding, the same as DOS and Windows 95. This is necessary so that we can interchange floppy disks (which use the FAT) filesystem, text files (which use the default encoding for whatever language of system we are on), programs, etc. with the non-Unicode Windows 95 operating systems. This non-Unicode encoding is called the ANSI code page on Windows. The Win32 API thus comes with two complete sets of API, the ANSI API which accept string arguments of type char* encoded in the default non-Unicode encoding, and the Unicode (or wide char) API which accept string arguments of type wchar_t*. Devs can now use the Unicode API and never have to worry about variable-length encodings ever again, or they can use the ANSI API for backward compatibility with old pre-Unicode libraries and Windows 95.
On UNIX, things were slightly different, and this is reflected in the C/C++ standard libraries. On UNIX, the expectation was that people would continue to use non-Unicode encodings in conjunction with the LOCALE environment variable, but programmers would be given the option of an automatic conversion to Unicode mode of file operation, that would allow them to code using Unicode while the underlying OS and file content would continue to use non-Unicode encodings. At this point, we need to understand the concept of “file orientation” that was introduced into C. When we open a file in C (using fopen()), the file does not have an orientation. If we call a non-Unicode file function such as fgets(), the file gets set to non-Unicode orientation, and we simply get passed the data from the file. However, if we call a Unicode file function such as fgetws(), the file is put into Unicode orientation. This does not mean that the file on the disk is treated as containing Unicode. Instead, the C standard library assumes that the file is encoded in the non-Unicode encoding as specified by LOCALE and performs implicit automatic conversion of the file content from that non-Unicode encoding into Unicode in the form of wchar_t*. This was supposed to solve the problems we saw above with regards to multi-byte encodings. We just search/replace all char* with wchar_t* and file calls with the corresponding “w” version, and suddenly all of our parsers, regular expression libraries, etc. will work fine with CJK encodings. It is this basic idea of how Unicode would work that permeates the C and C++ standard libraries.
On Windows NT, however, we have a problem. The C standard library still assumes that files are saved in a non-Unicode filesystem. It only offers automatic conversion and unicode support for file content, but offers no support for unicode filenames. There is no variant of the fopen() function which accepts a wchar_t* for the filename. On Windows NT with NTFS, we can easily name files not only with characters that do not exist in the user’s default ANSI codepage encoding, but also with characters that do not exist in any pre-Unicode encoding. The C standard library is fundamentally broken in this respect. If you use the Microsoft C compiler, there is a non-standard function _wfopen() which you can use, and this give you the best hope of compatibility with UNIX. The C++ API are similarly broken, even as far along as C++11. fstream::open() and friends only accept char* for the filename. If you are using MS C++, there are non-standard overloads that accept wchar_t*.
Because of this underlying concept used by the C standard library, it offers zero support for reading or writing Unicode strings in file content. If you use the Unicode wfstream which accepts wchar_t* for arguments, it performs automatic conversion to and from the LOCALE encoding. You can read and write wchar_t* strings as binary data, but you lose access to things like fgets() and fprintf().
At this point, we again have two disruptive events that change things all over again. First, we might try to understand why wchar_t is 32 bits on UNIX but 16 bits on Windows. When Unicode was being developed, there were actually 2 competing standardization attempts. Unicode was working on a 16-bit universal encoding and ISO was working on a 32-bit universal encoding (called UCS). As we can see from the above, the UNIX vision of a universal encoding did not actually involve saving that encoding onto disks as content or as filenames, but merely as a useful tool for uniform handling of those pesky CJK encodings. They had thus put their eggs in the ISO basket and chose the 32-bit wchar_t. Windows needed an encoding to save to disk (and also the ISO standard was bogged down in politics and going nowhere), so they chose the 16-bit wchar_t and Unicode. Once NT was released with Unicode, it was clear that they had won, and ISO adopted Unicode as the basic plane of UCS. However, they wanted more characters than Unicode could fit, and so we ended up with a 32-bit Unicode standard with UTF-16 as a variable-length 16-bit encoding.
The second disruptive event was the development of UTF-8, yet another variable-length encoding. An interesting thing about UTF-8 is that it was strongly resisted by Japanese developers. They had spent years of tearing their hair out because the variable-length Japanese encodings had not been compatible with most of the libraries and software developed in Western countries, and they were concerned that another variable-length encoding would suffer the same problems. However, both UTF-8 and UTF-16 have a nice property that prevents many of these problems. That is, the first char (UTF-8) or wchar_t (UTF-16) of any character can never appear in the second or subsequent char/wchar_t in any other character. This solves the problem of false-matches that the CJK encodings suffered from in regular expressions and strstr()-style string searching.
Once UTF-8 was released, UNIX had a clear path towards total Unicode compatibility. Simply adopt UTF-8 as your standard encoding and all your problems go away. While some versions of UNIX had backward compatibility issues to consider, Linux did not, and UTF-8 is the basic standard encoding used in Linux and it’s derivatives. Since UTF-8 can be encoded in a char*, it even works fine with the broken C standard libraries. UTF-8 plugs into the C standard library on what was meant to be the non-Unicode side since it is stored in char* and specified as an encoding using LOCALE. However, Linux/Windows interoperation is worse than ever.
Basic Programming With Unicode
On Linux, life is easy. Use UTF-8 for everything. In C/C++, if you want to avoid dealing with the variable-length nature of UTF-8, use the Unicode oriented file functions/classes which will perform automatic conversion between UTF-8 (char*) and UTF-32 (wchar_t*). Everything works well because UTF-8 is able to be manipulated through the functions that were intended for non-Unicode encodings. The C/C++ standard library makes it very difficult to use UTF-16 or UTF-32 directly in files, so using UTF-8 for encoding text files makes a lot of sense.
On Windows, things are harder. Although the non-Unicode Windows 95/98/Me are long dead, their legacy lives on in the form of ANSI code pages and ANSI functions. You should basically treat the ANSI code page/ANSI API as deprecated, only existing for backward compatibility. Newer APIs like the .NET Framework are all based on the Unicode APIs. The big problem in Windows is the C/C++ standard libraries. If you want to avoid using ANSI codepages, you either have to avoid all of the standard library file functions, or else you have to use MSVC for Windows compilation and use the Microsoft-specific extensions.
Windows also has a problem when it comes to UTF-8 encoded text files. There is no really reliable way to detect UTF-8 from other encodings. While specific applications can designate UTF-8 as their standard, a general purpose editor like Notepad is going to struggle. Windows thus makes use of the BOM code (U+FEFF) at the start of Unicode (non-ANSI) files. If you are reading text files in Windows, you should check for the existence of the BOM (which will tell you that the files is UTF-8 (byte sequence 0xef, 0xbb, 0xbf) or UTF-16 (byte sequence 0xff, 0xfe)), and if you are writing files in a non-ANSI encoding, you should prepend them with the BOM so that they will open correctly in generic text editors. However, a lot of UNIX apps will fall apart if they see the BOM, so you’re kind of damned if you do, damned if you don’t.
File I/O using the C standard libraries is not possible on Windows unless you restrict yourself to filenames in the ASCII range. Not a problem for outputting log files, but a big problem if you are letting users choose their own filenames. For console apps, you cannot read Unicode arguments using the standard int main(int argc, char* argv[]) function. The only alternative is to use wmain(int argc, wchar_t* argv[]). Although this is Microsoft only, you have to use it. Let’s take a look at an example. If you are on a Windows box with NTFS, you can easily open up Explorer, create a random text file somewhere, and change the name to “Dฤ.txt”. That second character is a Thai character, and unless you are on a Thai version of Windows, it is not accessible via the C/C++ standard libraries. The following code will not work:
#include <fstream>
#include <stdio.h>
int main(int argc, char* argv[]) {
std::wfstream reader;
reader.open(argv[1], std::ios::in);
...
};
If we try passing “Dฤ.txt” to our program as the first argument, it will receive the string “D?.txt”. Changing the locale with setlocale() does not help, since it does not change the encoding that is passed to our program, it only changes how our program interprets the data it receives. We have to use Microsoft-only wmain and open:
#include <fstream>
#include <stdio.h>
int main(int argc, wchar_t* argv[]) {
std::wfstream reader;
reader.open(argv[1], std::ios::in); // Microsoft-only overload
...
};
Implicit Conversion
Let’s say you have some kind of ANSI driver on Windows, say an ODBC driver. You might be tempted to think that you can simply stuff UTF-8 strings into char*, and as long as we configure our ODBC driver to talk in UTF-8, we’ve created a path for using UTF-8 in Windows. Worse, if you actually try doing this on a Western European Windows (Windows-1252 encoding), it is going to work. However, this will fall apart on many other versions of Windows. The key here is that Windows uses Unicode internally, so your char* string will get converted to wchar_t* as it passes through Windows, then get converted back to char* when it finally gets passed to the ODBC driver. Because the Windows-1252 encoding has clearly defined char <-> wchar_t mappings for every character in the 128 to 255 code range, all of our UTF-8 characters will survive the conversion/back-conversion process unscathed.
As an example, let’s say we have the UTF-8 encoded value of “Ê”. This is 195 138. What Windows sees is two valid Windows-1252 characters “Ê”, which it converts to Unicode then back to Windows-1252 as “Ê” again. If the ODBC driver views this string as UTF-8, it sees “Ê” and everything works.
Now, take the same example but on Japanese Windows. In Shift JIS, 195 is “テ”. However, 138 does not map to a character. It maps to the first byte of a multi-byte character. The ANSI to Unicode conversion is going to dump this character because it is not a valid character, and the conversion back to ANSI will leave us with the single byte string 195. The data that ends up in our ODBC is now broken.
This above pattern is one that I have seen a lot. The big problem is that it works fine on Western European and US (i.e. Windows-1252) code page Windows, and it works fine with every single Unicode character. However, when the dev ships their client off to a Japanese customer, Chinese customer, or Russian customer, they start getting random errors because certain character codes simply cannot survive the traversal across the implicit conversion.
Dealing With Databases
As I mentioned above, using an ANSI ODBC driver on Windows is asking for trouble. This is something that used to be a big problem for mysql, in particular. However, there is a work-around that you can use. If you want to pass UTF-8 or any other encoding to the database without Windows performing any automatic conversions, you can use hexadecimal literals. For example, insert into MyTable (Col1, Col2) values (0xE697A5E69CACE8AA9E, 0xE69687E5AD97); will insert a row with UTF-8 values “日本語” and “文字” for Col1 and Col2. The hex strings following the 0x need to be the hex representation of the binary representation of the string encoded in the encoding of the database column (not the encoding of Windows and not the encoding in the set names xxx mysql command.
Unicode-Based Languages
One of the things you sometimes see on programming forums is people asking for Unicode based languages. Why can’t the language just treat all strings as Unicode? After all, even on Windows these days it’s quite easy to save files in UTF-8, and if UTF-8 is part of the spec of our language, then any IDE produced should just default to UTF-8 and everything is solved, right? Well, not quite. One area where this remains an issue is writing code on Windows and uploading via FTP to run on a UNIX box, the kind of thing you might do as a web developer. Let’s say a client provides us with an include file called “café.inc”, which we save in our NTFS filesystem. In a code file somewhere we write include "café.inc". We run this for testing on our local Windows box and everything works, so we then upload it to our Linux test server. If we used a tool like FTP to upload the file, chances are it’s not going to work. FTP is not aware of encodings, and it’s not going to translate the filename into UTF-8. The final step we need is a specially modified version of FTP that can transform filenames into UTF-8. Surprisingly, a lot of FTP/SFTP/FTPS clients on Windows do not support this (including the FTP client that is included with Windows!). One client that does support it is Filezilla, but you have to go into the advanced properties and select Force UTF-8.
Probably the best solution to overcome problems with encodings for programmers is to simply not include any non-ASCII letters in your source files or filenames. This solves every single problem. If you have text data (or localization data), stick it all in a database with a front-end such as html where you have total control over the encoding. The funny thing is that this takes us full-circle back to the 1970s when ASCII was the only game in town. Technology really does have a hard time escaping its roots.
At this stage, I feel like I’ve rambled on forever. This was supposed to be a short article, and its grown into a monster. I hope I have covered everything, but would love comments if I’ve made errors or neglected anything. As a topic for you to think about, what would you do if you called the wisdigit() function on a character code outside of the ASCII digit range (48 to 57) and got a true value? This is something I might write about another time.
Related Posts
Dial/Letter-Printing Telegraphs
The most complex and user-friendly system was the dial telegraph, self-rotating telegraph, and letter-printing telegraph, which all used essentially the same underlying mechanism. In this system, a wheel with each of the letters/symbols to transmit rotated on the sending side, alternately switching the signal between 0 and 1 with each letter that passed. This signal was used on the receiving side to advance an identical wheel, thus keeping the two synchronized. The operator on the sending side would momentarily stop the wheel at the letter they wanted to send. The signal stopped alternating while the wheel was held, and thus the receiving station also stopped rotating. An operator could read off the dial, or in the case of the letter-printing system, the cessation of motion would trigger the printing mechanism to stamp the letter on a piece of paper. Details on how this kind of device are given here in a run down of the mechanisms in the House printing-telegraph from the 1830s.
Note that this is not really a character encoding like we would think of today, since there is no fixed representation of any letter. For example, if we wanted to encode D as the first letter of the transmission, we would send 1010000000, since we need to rotate the dial around from the starting position. However, if the D came after a B, then we only need to send “10000000”, since we start at the B. In the example linked above, there are 28 letters on the wheel, and so we need to send on average 14 bits per character, plus we need to keep the signal paused while the letter is printed. Despite this system being highly machine-compatible, it is thus not very efficient. It also suffers from robustness issues. Any noise on the line that results in a bit being lost means that the sender and receiver are put out-of-sync, and the rest of the message becomes scrambled. This is not a problem for the other two systems.
Needle-Pointing Telegraphs
The next type of system was the Wheatstone needle-pointing system. This was based on having several needles which could be tilted left or right. The signals for each needle were transmitted in parallel. Thus a 2-needle system requires 2 lines for transmission. Represented in more modern terms, we could say that it was a ternary system allowing three values to be transmitted: negative voltage, no connection, and positive voltage (giving logic values of -1, 0, and 1). The original telegraph patented by Wheatstone employed 5 needles, but actually required 6 signal wires for communication, and used a circuit-like signaling system unlike anything we would use for communications today. (I’ve run through the details on how the device worked here.) Although we would expect a 6-wire ternary system to give 3^6 = 729 different code combinations (or 728 different non-null combinations), the arrangement employed by Wheatstone was only capable of 30 different code combinations. Unlike the letter-printing telegraph above, this system was not particularly automation-compatible, and could not be attached to a printing apparatus. The need for multiple wires to send a message was also inefficient, especially on low volume transmission paths, and eventually the system devolved into a single needle system where the two codes of left and right were treated as dots and dashes in Morse code. This gives us Morse code but with slightly different signaling.
Morse Telegraph
Finally, we have the most well-known system, Morse code. Interestingly, the physical device design of the system originally proposed by Morse was much more complicated than the code key/buzzing register that finally emerged. (This patent shows the details of the mechanical encoder originally envisioned by Morse.) As most people know, the code consisted of dots and dashes. The code is extremely flexible in terms of usage without advanced technology. All you need is a single line alternating between 0 and 1 and a buzzer and code key. With that, it can be used with just about any means of communication. However, Morse code is not particularly machine-compatible. Although we can easily represent the code in binary by treating a dot as “1” and a dash as “111”and the space between dots and dashes as “0” (which gives approximately the correct timing of hand-coded Morse code), there is no easy way to mechanically take a Morse code signal off a wire and convert it into binary code, especially in the 1800s. One of the salient features of Morse code is that it is a variable length encoding, varying in length from the letter E (dot = “1”) to the number 0 (dash-dash-dash-dash-dash = “1110111011101110111”). More frequently used letters have shorter codes, making it very efficient in terms of line usage, much better than the letter-printing telegraph above.
And the Winner Is…?
You might think that from among the various different types of telegraphic encodings, the one that was technologically superior would win out and become the de facto standard. However, life is more complicated than that. Initially, dial type telegraphs dominated in Europe where the dial-type telegraph was patented by the German Siemens. In England where Wheatstone first patented his needle telegraphs, needle telegraphs ruled. In America, Morse was the first person to patent a telegraph, and Morse code ruled. However, Morse was not the only game in town. Morse code was efficient but required trained operators, making it ideal for telegraph companies. The letter-printing telegraph, however, was much more user friendly, and was often used in private telegraph networks, such as for communication between bank branches where line congestion was not an issue. Ultimately, though, Morse code was the most efficient encoding for the equipment of the time, and was used extensively throughout the world even into the 1900s.
Multiplexing and Automation – Drivers For New Encodings
Not unlike the Internet of today, use of the telegraphic networks grew rapidly and congestion became an issue. The expensive solution to congestion is to simply build more lines. The inventor solution to congestion, however, is to multiplex a single line (that is, to allow multiple transmissions to run simultaneously down a single wire). A lot of different schemes were proposed through the 1850s, 1860s, and 1870s, and these were predominantly time-division systems. Frequency-division systems came later, and are part of the story of the invention of the telephone (and so I’m not going to discuss them here).
Time-Division Multiplexing
Now, time-division multiplexing is quite easy to understand. Let’s say you have a wire you want to share among 4 pairs of people for telephone communication. What you do is attach time-synchronized multiplexers on the ends of the wire. First, the first pair of people are connected, then after some fixed time the first pair are disconnected and the second pair are connected, and so on. Each pair thus gets to use the line for a quarter of the time. Now, a key factor here is the frequency of the switching. Let’s say you assign each pair 1 second. That means that their line is repeatedly connected for 1 second and disconnected for 3 seconds. It’s going to take a lot of effort for the people to use the line. In fact it’s going to be a nightmare. For a computer, however, this is not a problem. This kind of synchronous time-division multiplexing is thus suitable for digital communication but not for analog communication.
Asynchronous Time-Division Multiplexing
Now, let’s speed up the multiplexers and assign each pair 0.000025s. Now you’re free to talk asynchronously of the multiplexing rate. This is great for analog communication, and is how telephones work. This is also great for our telegraphic encodings, where the timing is basically determined by the analog operator. Here is an example of an interesting quadruplex system of this kind that used tuning forks to synchronize the multiplexers on either side of the transmission line. (The multiplexer ran at 72 Hz – sufficient to multiplex human-keyed Morse code which maxes out at around 12 Hz.). The problem, of course, is that you need to have some kind of buffer or latch circuit to hold the previous value of a virtual circuit while the other circuits are using the line. Without this, the system isn’t going to work very well. Worse still, the signaling used by Morse code is not compatible with the most basic buffer arrangement, and so the early attempts at this kind of multiplexing were not particularly successful.
Synchronous Time-Division Multiplexing
Where things get interesting, however, is synchronous multiplexing systems. Here is an example of a system for multiplexing 4 Morse code circuits onto a single wire. This system attempts to send one single character per multiplexing timeslot. It employs a keyboard which has a binary representation of the Morse code alphabet, and requires the operator to press the keys in synchronization with the multiplexing speed. It’s interesting because it is so close to being a digital communication system but doesn’t quite make it. While the transmitter sent out the binary representation of the Morse characters, they were received in an analog manner. Here, we can see the problem with Morse. The binary representation of Morse required 15 bits for the longest letter, and thus 15 bits were sent on each multiplexer cycle. This was not only wasteful of bandwidth, but it also meant that automation of the receiver would require decoding of 15-bit long binary numbers, something far beyond the capabilities of the largely mechanical devices of the time.
Baudot
The big breakthrough into the digital age was made by the Frenchman Baudot with a device he patented in 1882. It is an extremely interesting device, and I have detailed how it worked here. Baudot is most famous for the code that his device used, the Baudot code. This is a 5-bit fixed length binary encoding. Like the device in the previous section, Baudot employed a synchronous multiplexing system. However, because the code was only 5 bits long, it was within the realm of being decoded by a purely mechanical system, and the system he used was quite ingenious. Once the Baudot device had demonstrated the utility of fixed length binary encodings, there was no going back.
Control Codes 1 – Shift States
Baudot’s original code was limited to 32 characters. However, this was soon near-doubled by the addition of shift codes – codes that switched the character set. They were called shift codes because they literally shifted the printing mechanism between two parallel type wheels. Looking at Baudot’s original device, we can see that he already had all the mechanisms necessary for compare-and-actuate style operation. Using two special codes to shift the type wheel was a fairly trivial addition. With 2 codes allocated to shifting in each 32 code set, the resulting encoding offered 60 printable character codes.
Control Codes 2 – Page Printing
Despite the level of automation achieved by Baudot, his device still printed a single long strip of paper. The next development was to produce a more typewriter style of output. This was achieved by Murray, who created his own 5-bit code which also added the carriage return (CR) and line feed (LF) control codes. Now operators could type on something that looked like a typewriter, and get printed output the same as would be produced by a typewriter. This was the teletype. The Baudot device had shown the need for punched tape instead of having operators working synchronized with the machine, and so Murray also added the DEL character – which indicated a character that had been erased by punching out all of the holes in the paper tape.
Control Code Chaos
After this point, quite a number of different 5-bit encodings were used by different manufacturers with different equipment. A large part of the difference was the different control codes. These included things such as BEL (ring the bell on the receiver), WRU (who are you – for querying the remote device), as well as codes that would activate or deactivate the motor on the receiver, etc. depending on the application.
7-bit ASCII
Eventually, the 1960s arrived and it was time for a new standard. More modern electronics had removed the technological barriers that had kept 5-bit codes in use. Plus, computers had arrived and a shifted encoding like Baudot or Murray was not particularly computer-friendly. ASCII was thus intended to provide a standardized unified encoding for both telegraphy and computers. Seven bits means 128 codes. A big 32 code block was assigned for control codes to accommodate the various control codes sought by the different stakeholders. The special values 0 and 127 were assigned NUL and DEL for compatibility with punched tape. On top of this, international language support was added through the use of the BS (backspace) control character and special crafted punctuation marks. (For example, an o with an umlaut (ö) could be printed by printing o, then BS, then double-quotation (“)). ASCII was thus primarily a telegraphy code which could also be used for computing.
ASCII’s competitor was EBCDIC, which was developed by IBM around the same time. EBCDIC was only designed for computers, and was not a telegraphic encoding. Given that EBCDIC was specialized for computers where ASCII was more for telegraphy, you might expect EBCDIC to win this battle. However, the telegraphy market was huge whereas the computer market was tiny. Printers and teletypewriters that talked ASCII were everywhere. On top of this, ASCII was a standard developed through consultation with many manufacturers, whereas EBCDIC was IBM’s proprietary encoding designed to solve their specific needs. As we all know, ASCII won. (If you are interested in all of the gritty detail of the 5-bit encodings and the development of 7-bit ASCII, there is a detailed explanation here.) There are also several books on the topic:
Related Posts
The answer is simple. Run a string along the ends of a series of electromagnets, and arrange pulleys connected to these magnets so that each successive magnet pulls twice the length of string when activated. Here is the schematic from the original patent:

The operation is fairly straightforward. The five electromagnets are arranged at the bottom, with bit 0 at the left and bit 4 at the right. The wheels above the string are attached to the magnets, and pull the string down when the magnet is activated. The wheels below the string are fixed. In the diagram, the magnet for bit 3 (second from the right) shows the state of the string in the activated state with dotted lines. Each magnet pulls down the string by double the amount of the previous magnet.
One interesting point is that the electromagnets of the 1870s still weren’t particularly powerful or capable (these days you can get more powerful magnets as toys), and the consequences of that manifest in the design of this device. If we assume that magnet for bit 0 moves through a distance of 1/16 of an inch (approx 1.6 mm), then it means that the magnet for bit 3 needs to move through a distance of 1/2 inch (approx. 12.7 mm). But at this point, we have hit the limit of the distance over which our weak magnets can perform. The magnet for bit 4 thus doubles the distance not through doubling the length of motion, but by employing two wheels which deflect the string by the same amount in two locations. This 5-bit D/A converter is thus on the cutting edge of what could be achieved in the 1870s.
I don’t know what kind of data rate was possible with this device, but it clearly isn’t going to be enough to create a 19th-century version of the Sound Blaster. In fact, the reason this D/A converter was invented was for handling the 5-bit encoding of the world’s first binary electronic communication system, the 5-bit Baudot telegraph.
If you feel like making your own, the parts are all available on Amazon:
Related Posts
The device is inherently capable of multiplexing, but the original form shown in the patent is only a simplex device. The code is sent down the line in serial format, which is achieved using a rotating distributor. Multiplexing could thus be trivially achieved by adding segments to the distributor. Baudot originally used a keyboard connected directly to the distributor for transmission, meaning that the keyboard operator had to type in sync with the rotation of the distributor. The keyboard had 5 keys, meaning that the operator had to learn the binary codes for each letter, but this was later replaced by a punched paper tape system, which made the whole thing a lot easier to use. Here is a schematic that shows conceptually how the distributors performs serializing/deserializing.

In this figure, the side on the left shows the keys at the transmitter, and the side on the right shows the receiver which activates the receiving electromagnets E1 to E5. The reason why only half of the distributors are used is that the other half was used for synchronization, as will be described later. Now, the actual arrangement used in the device is slightly more complex than the above conceptual drawing. Here is the schematic of the actual device.

The first thing to note is that we have switches for choosing receiver/transmitter (highlighted in green). In this case, the station on the left is the transmitter and the station on the right is the receiver. Now let’s follow the power through the system from the left hand side transmitter. There are three batteries at the bottom (blue). The battery P4 powers the local apparatus, while the batteries P2 and P3 used for transmitting positive and negative signals down the line. (The transmission line signaling was +/-). The keyboard (orange) has five keys, each of which activates two different circuits. The left side of each key sends a polarized signal (positive for logical 1 and negative for logical 0) from the P2 and P3 batteries through the red distributor onto the telegraph wire. The right side connects the local battery P4 through the same distributor and to the local printer (represented by the electromagnets E1 to E5 in the purple area). The signaling here is positive for logical 1 and not connected (or high Z) for logical 0. This produces a local copy of the transmission.
At the receiver, the line runs through the red distributor to a polarized relay (cyan). This accomplishes two things. First, it converts the polarized signal (+/-) from the line back into the signal (+/high Z) used by the printer. Second, it acts as an amplifier, taking the weak signal from the telegraph line and relaying it into a strong signal using the P4 local battery. This then runs back through the distributor and into the purple magnets E1 to E5 which drive the printer.
Here I just want to discuss the line signaling for a minute. The signaling that is used in earlier Morse code style telegraph (positive voltage = logical 1, not connected = logical 0) is not particularly suited to the asynchronous multiplexing schemes that were first attempted in conjunction with Morse code. The reason is that there is no distinction between logical 0 (not connected) and the timing window when other virtual circuits are connected to the main line (again, not connected). A simple way to overcome this, however, is to use polarized signaling (positive voltage = 1, negative voltage = 0, and not connected = ignore) combined with a flip-flop – which in modern electronics is a type of circuit that can be switched between two logical values, but retains its value when not being switched. This is relatively easy to implement using electromechanical devices by using an electromagnet with a polarized armature without any springs that flips and flops between two stable positions. (Note: I have no idea if this was the basis for the name “flip-flop”, but it certainly fits.)
The point is that the entire input side of Baudot’s apparatus is remarkably similar to this kind of arrangement, consisting of polarized communication via a polarized flip-flopping relay. However, the device in this patent uses a synchronous multiplexing arrangement which renders all of this unnecessary, and the polarized relay in the device contains a spring such that it no longer acts as a flip-flop.
Next, let’s look at the distributor in more detail.

As you can see, the rotating arm has two sets of brushes. The first set (green) connect the main line contact H with the 5 bits of the polarized signal, labeled G1 to G5. On the receiver, these run off to the polarized relay and return a non-polarized signal to the contacts K1 to K5. The second brush (cyan) then connects these non-polarized signals with the contacts I1 to I5 that run to the electromagnets in the orange part of the disk. The knob at the top can be turned to move only the orange part of the arrangement, which is used for fine-tuning the timing. The pieces marked v outside of the orange circle are the conductors that run to the printer.
Next we have the printer. Here is a side view of it.

First, notice the shaft marked B which runs through the center of the apparatus. This is the main timing wheel. Everything colored red sits on this shaft and rotates together. The shaft is also connected directly to the distributor arm (which would be on the left of the diagram). The direction of rotation is indicated by the arrow. Now, let’s focus first on the transfer and decode registers. This cross-section view shows 1 bit out of the 5 bits that make up the registers. Here I’ve color-coded the separate stages of the device:

On the left (orange) we have the electromagnet which is driven from the distributor. In the middle (green) we have the latching transfer register, and on the right (cyan), we have the decode register. Now, focusing on the transfer register, let’s have a look at the logical 0 and logical 1 positions.


What we have here is an analog version of a latch, one which actually uses a latch. The bits start in the logical 0 position, and are held there by the spring latch, h2. The input from the electromagnet knocks the bit out of the spring latch and into the logical 1 position, where it remains. The unit also has an output and a reset function. Looking back at the full stage, notice the curved cams in the wheel (shaded a darker shade of green).

Once per revolution of the master timing shaft B, the first cam catches the lever only if it is a 1 bit. The lever is pushed to the right, which is the output function that transfers the latched value into the decode register to the right. The next cam is the reset cam, which pushes the lever back up into the logical 0 position where it is again retained by the spring marked h2.
Looking at the decode register, we again have two bit positions as follows:


This time, notice how the bottoms of the register pin fits into one of two grooves on a flanged wheel. This wheel is the decoder wheel, which we’ll cover later, and the flange in the middle between the bit positions locks the value of the bit. There is a break in the flange at which point we have a reset cam (the darker blue triangle) which resets the pins back to logical 0. The flange remains broken after this, and is aligned with the transfer cam from the transfer registers. Once the value has been transferred from the transfer register, the flange begins again, locking the values in place.
Now, I’ve got to say that I love this because it means that this device effectively ran in pipelined operation, much like modern CPUs. In this 2-stage pipeline, the first stage gets a full clock cycle to de-serialize the input from the line, and the second stage gets a full clock cycle to perform decoding and printing.
This description has only shown the operation of a single bit, so here is a view from the top which shows how all five bits were arranged with the three stages colored as before.

Decoding
The next trick is decoding the input 5-bit values into actual letters. In the modern world, we could probably treat the codes as binary numbers with values of 0 to 31 and use table lookups or the like. However, in the age before computers there was no reason to treat the codes as numbers at all. They were simply a sequence of 5 values which formed a code. (Although it didn’t take long for someone to realize the usefulness of treating the code as binary numbers.) Decoding is thus achieved by comparing the decode register against every possible combination until a match is found. The mechanism for achieving this sounds like something out of a tech-company interview, but was quite ingenious for the time. Put as a tech question, what is the smallest binary string that contains all possible 5-bit binary numbers as sub-strings? Here is the circumference of Baudot’s decoder ring which contains the answer:

The top row corresponds to bit 0 of the decode register, and has gaps (white squares) that correspond to 0 bits. The bottom row corresponds to bit 1 and has gaps that correspond to 1 bits. In answer to the above question, we need 36 bits for the decoder string. The 37th position onwards has no gaps, meaning that it will not match either 1 or 0 bits. To see how it worked, let’s take a look at the view from the back.

From this view, the decoder wheel rotates clockwise. The five cyan levers are the pins of the decode register. The purple lever to the left is attached to a spring (not shown here) such that it pushes the tops of the 5 register pins towards the right. This pushes the fingers underneath onto the decoder wheel. Once the fingers line up with holes in the decoder disc, the levers all tilt to the right and activate the printing mechanism. Note that there is no need for the rotation to stop during the printing. The printing occurs in one continuous action. I’ll get into the printing mechanism later, but I just wanted to comment on the analogy of the mechanism up to now to a computer.
Let’s call the transfer register TX, the decode register DX, and use the pneumonics CLR (clear), OR (logical or), and CAP (compare and print) for the operation of the decoder wheel. The rotation of the wheel thus continuously runs the program:
CLR DX
OR TX,DX
CLR TX
CAP #16
CAP #8
CAP #4
CAP #18
CAP #9
CAP #20
CAP #10
CAP #21
CAP #26
CAP #13
CAP #22
CAP #11
CAP #5
CAP #2
CAP #17
CAP #24
CAP #12
CAP #6
CAP #19
CAP #25
CAP #28
CAP #30
CAP #31
CAP #15
CAP #23
CAP #27
CAP #29
CAP #14
CAP #7
CAP #3
CAP #1
CAP #0
It’s a long way from being a Turing machine, but it is still an interesting approach to digital communication. Now, on to the printing mechanism. Here’s the same view as above, but with more components added.

The orange component at the top is attached to the purple lever from the previous diagram. When we get a code match, it rotates to the right, pushing the push rod down onto the green lever at the bottom. The left arm of this green lever has a catch that holds the red arm in place. When this is released, the spring on the right side throws the arm into the notch in the big rotating wheel. This drives the red arm, which performs the printing (which happens in the next layer up) by swinging the paper against the wheel. The blue ratchet is used to advance the paper. The cam marked V on the big wheel then resets everything at the end of the cycle.
Adding on another layer of components, we can see the full paper path and the type wheel.

This original model does not use any shift states. However, soon after Baudot began using his device, he added the first shift codes to it. Instead of having a single type wheel, he switched to having two type wheels in parallel, and two of the character codes were decoded not as printable characters, but as command codes that actually shifted the printing mechanism between the 2 parallel type wheels. This gives a total of 60 printable characters. As a challenge, you might try to imagine how these shift codes could be incorporated into the mechanical design.
Related Posts

Now, if you try to run through the circuit diagram and work it out for yourself, you might run into some problems. The diagram differs slightly from the description in the body of the patent. Since a number of different inventors were scrambling to lay claim to the idea of acoustic multiplexing, I would guess that this is a result of rushing the patent down to the patent office. Anyway, I’ll run through the circuit and describe the basics.
First, we have two stations, one on the left and one on the right. Furthermore, there are two lines between the stations. The bottom line marked B carries a control signal, and the main line marked LINE carries the multiplexed communication signal. The two tuning forks at the bottom marked L (on left side) and A (on right side) are part of the control circuit, which could also be described as the master timing circuit.
Now, let’s focus on the “master clock” of the system. This is the tuning fork at the bottom of the right side station, and is shown magnified below.

The red line shows what was quite a revolution at the time (and just to be clear, this patent was not the one that invented it). It is an electromechanical clock device, the forerunner to the crystal oscillators used in modern electronics. At this point, it is important to note the vibration mode of a tuning fork is such that the forks alternately move away from each other and then move towards each other. When the tuning fork is at rest, the circuit is closed and the magnets are energized. This pulls the forks away from each other. The tip of the upper fork E then pushes outwards on F, breaking the connection at F. This cuts the circuit and de-energizes the magnets. The forks are now freed to oscillate back inwards at the resonant frequency of the fork. This again closes the switch, activates the magnets, and the oscillation continues sustained by the battery.
This master clock generates two clock signals which are sent to different parts of the circuit. They are kept electrically isolated by being connected to separate switches at the ends of the two different forks. The clock signal from the lower fork is sent out over the control line as the synchronization signal to the remote station, whereas the clock signal from the upper fork connects to the multiplexing apparatus above. Now, in this next figure I’ve highlighted the control signal circuit.

There are two points to note. The first is the extraneous battery at the bottom left. This battery would either need to be removed or reversed for the system to actually work. The second point is that the schematics marked R and S in the figure represent telegraphic keys that have a normally closed configuration. That is, the connection through the keys is closed when the keys are not pressed, and gets broken by pressing the keys. These keys are not considered part of the multiplexing arrangement, but form an out-of-band communication channel. The short breaks in the synchronization signal from sending Morse code down the same line has no effect on the synchronization because the tuning forks are able to remain in sync for 20 to 30 seconds even after the synchronization signal has been removed.
Starting from the right, we can see that the line from the battery passes across the E’ and F’ contacts at the lower fork of the master clock, through the normally closed telegraph key S and then across the control line B to the remote station. The line then passes through the electromagnets on the tuning fork L, causing the tuning fork to vibrate in sympathy and synchronously with the master clock A. This is the key to the timing system, and creates a slave clock at the remote system that is synchronized with the master clock. The line then runs through more telegraphic equipment and back to earth (once we remove the extraneous battery).
The tuning fork L is connected similarly to A, with the upper fork used as the timing signal for the multiplexing circuit at the remote station. The bottom fork of L (with the contacts marker M’ and N’ is not used in the diagram, but could be used in repeater stations to daisy chain the signal on to a subsequent telegraph line segment.
Next, we’ll look at the multiplexer.

The first thing to note is that the left and right side multiplexing circuits are symmetrical (despite how the schematic may appear), so I’ll only detail one side. The red line shows the circuit from the timing master, which runs through the P and Q tuning fork clock drive magnets. Notice how the P fork looks similar to the L timing master while the Q fork is shorter and fatter? This is because the P fork has the same resonant frequency as the timing master, while the Q fork has a resonant frequency double that of the timing master. This is because the Q fork divides the main line into 2 virtual circuits, and the P fork subsequently divides these 2 virtual circuits into 4 virtual circuits.
The forks of the Q tuning fork can be thought of as having 3 states. In the rest state or central state when the forks are not flexing inwards or outwards, the green line is connected through to the purple main telegraph line, and the orange and cyan lines are disconnected. When the forks are flexing outwards, the top fork switch is engaged and the main line gets connected to the cyan line, and when the forks are flexing inwards, the bottom fork switch is engaged and the orange line gets connected to the main line.
The same configuration on the right hand side means that we get 4 complete virtual circuits operating over the same line. This basically completes the apparatus, and we have a quadruplex communication system.
Although it turns out that adjusting the placement of all those switches at the ends of the tuning forks and getting all of the magnets wound and placed symmetrically so that everything works as intended is problematic, it is not insurmountable. The real issue is continuity. Each virtual circuit is only connected (at most) 1/4 of the time, and the output is disconnected for the rest of the time. To achieve this we really need a more machine-friendly signaling system.
Related Posts

It looks like a bit of a mess. So here’s a color-coded version for describing the operation.

The most important part is the distributor on the right, which is colored orange. The red needle carries the signal to and from the telegraph wire, and rotates clockwise around the dial. Notice how the dial is divided into 4 large segments and 1 small segment. The 4 large segments correspond to 4 multiplexed circuits (called virtual circuits), and the small segment is a synchronization segment. Just outside of the orange circle, you can see lines corresponding to each of the segments. These are contacts that are used for receiving. Within the orange area there are 15 contacts in each virtual circuit, and these are used for transmitting.
First, let’s look at how the synchronization worked. The pink circle is a toothed gear that is driven clockwise by a motor underneath (not shown in the diagram). The red needle has a pin sticking out from its bottom which engages with this gear, and drives the red needle around. However, the red needle can also be lifted up out of the gear so that it comes to a halt. In the state shown here, the red needle is sitting on top of the green arm, which disconnects it from the drive motor. This is the idle state.
In this state, the telegraph signal from J goes into the red needle, then into the contact between the green arm and orange circle, through to the green electromagnet marked H, and then back out to the telegraph signal at I. When a synchronization signal is received from the telegraph line, it activates the electromagnet, which pulls back the green arm, and drops the red needle onto the spinning pink gear. The red needle can then perform one full rotation until it beaches itself on the green arm once again. Anyone who knows RS-232C should be able to see the similarities. (For those who don’t know, RS-232C was the predominant serial communication protocol on computers until it was replaced by USB. It consisted of a start bit, followed by 8 to 10 bits clocked based on the timing when the start bit was received. This meant that a separate clock signal was not needed.) The synchronization signal here corresponds to the start bit in RS-232C.
Here is a side-on view of the distributor, which might or might not make things clearer.

Since it is a patent, it also has an alternate design for the distributor which accomplishes the same thing.

Now, because of the style of synchronization used, the motors can have some slight difference in rotation speed without breaking the multiplexing function. In this case, a speed difference of a few percent would not be a problem. However, it’s not at all clear from the patent if the inventor was actually able to achieve even this degree of consistency from his motors. There is a motor design included in the patent, which I’ll get into later.
Getting back to the multiplexer, let’s take a look at the method of transmission. The basic premise is that one letter is sent with each transmission window (i.e. with each revolution of the distributor). Since Morse code consists of dots and dashes, a system of producing transitions at the correct timings was needed. In the orange part of the distributor ring, there were 15 sequential contacts, which are sent in turn as the distributor rotates. Setting up the correct sequence on the contacts can allow us to send Morse code. The 15 contacts were thus connected to 15 lines that ran underneath the keyboard, with each key press connecting the wires as appropriate to transmit the correct letter. This can be seen below:

The reason why 15 wires were needed is because the longest letter at the time (the full stop, which in American Morse code is dot-dot-dash-dash-dot-dot) required 15 bits to encode (as 101011101110101). (In the later international Morse code, the longest was the 5 dash number zero, which would require 19 bits 1110111011101110111.) But this also reveals the weakness of Morse code for this system. For letters with short codes, a lot of transmission time is wasted sending nothing, and much of the gain of using multiplexing is thus lost. Clearly, Morse code is a bad match for this kind of multiplexing, and this was one of the forces that helped with the push towards fixed-length binary encodings such as the Baudot code.
Now, the receiving system is fairly simple. Let’s take a look at the apparatus again.

The cyan N block at the bottom is a selector which selects which of the 4 channels to receive. That signal is then sent to the printer, M, which prints out the Morse code as Morse code. (There was still no way to automatically convert Morse code into letter printing at the time, another problem which helped with the shift towards binary codes.)
Now, on to the motor. This one is kind of interesting because it is a cross between a steam-engine style reciprocating piston arrangement and a modern DC motor arrangement. Here is a top view.

The 3 magnets are V1, V2, and V3. These pull down armatures, which are pivoted in the middle, and push up towards the wheel Z. This upward motion acts against a cam on the bottom of the wheel Z, thus mechanically creating rotational motion. The electromagnets engaged one at a time as the contact marked a3 came into contact with the corresponding brush. Here is a side view that might make things more clear.

The cam is marked S and shown on the left side of the wheel. When the cam is above the armature at R, the magnet engages and pushes R into S. S is wedge-shaped, and causes the wheel to rotate. Obviously, this is a design that is not used anymore.
Related Posts