432
votes

I'm going to ask what is probably quite a controversial question: "Should one of the most popular encodings, UTF-16, be considered harmful?"

Why do I ask this question?

How many programmers are aware of the fact that UTF-16 is actually a variable length encoding? By this I mean that there are code points that, represented as surrogate pairs, take more than one element.

I know; lots of applications, frameworks and APIs use UTF-16, such as Java's String, C#'s String, Win32 APIs, Qt GUI libraries, the ICU Unicode library, etc. However, with all of that, there are lots of basic bugs in the processing of characters out of BMP (characters that should be encoded using two UTF-16 elements).

For example, try to edit one of these characters:

  • 𝄞 (U+1D11E) MUSICAL SYMBOL G CLEF
  • 𝕥 (U+1D565) MATHEMATICAL DOUBLE-STRUCK SMALL T
  • 𝟶 (U+1D7F6) MATHEMATICAL MONOSPACE DIGIT ZERO
  • 𠂊 (U+2008A) Han Character

You may miss some, depending on what fonts you have installed. These characters are all outside of the BMP (Basic Multilingual Plane). If you cannot see these characters, you can also try looking at them in the Unicode Character reference.

For example, try to create file names in Windows that include these characters; try to delete these characters with a "backspace" to see how they behave in different applications that use UTF-16. I did some tests and the results are quite bad:

  • Opera has problem with editing them (delete required 2 presses on backspace)
  • Notepad can't deal with them correctly (delete required 2 presses on backspace)
  • File names editing in Window dialogs in broken (delete required 2 presses on backspace)
  • All QT3 applications can't deal with them - show two empty squares instead of one symbol.
  • Python encodes such characters incorrectly when used directly u'X'!=unicode('X','utf-16') on some platforms when X in character outside of BMP.
  • Python 2.5 unicodedata fails to get properties on such characters when python compiled with UTF-16 Unicode strings.
  • StackOverflow seems to remove these characters from the text if edited directly in as Unicode characters (these characters are shown using HTML Unicode escapes).
  • WinForms TextBox may generate invalid string when limited with MaxLength.

It seems that such bugs are extremely easy to find in many applications that use UTF-16.

So... Do you think that UTF-16 should be considered harmful?

37
  • 64
    Not really correct. I explain, if you write "שָׁ" the compound character that consists of "ש",‎ "ָ" and "ׁ", vovels, then removal of each one of them is logical, you remove one code-point when you press "backspace" and remove all character including vovels when press "del". But, you never produce illegal state of text -- illegal code points. Thus, the situation when you press backspace and get illegat text is incorrect.
    – Artyom
    Jun 27, 2009 at 12:43
  • 41
    CiscoIPPhone: If a bug is "reported several different times, by many different people", and then a couple years later a developer writes on a dev blog that "Believe it or not, the behavior is mostly intentional!", then (to put it mildly) I tend to think it's probably not the best design decision ever made. :-) Just because it's intentional doesn't mean it's not a bug.
    – Ken
    Mar 18, 2010 at 1:18
  • 145
    Great post. UTF-16 is indeed the "worst of both worlds": UTF8 is variable-length, covers all of Unicode, requires a transformation algorithm to and from raw codepoints, restricts to ASCII, and it has no endianness issues. UTF32 is fixed-length, requires no transformation, but takes up more space and has endianness issues. So far so good, you can use UTF32 internally and UTF8 for serialization. But UTF16 has no benefits: It's endian-dependent, it's variable length, it takes lots of space, it's not ASCII-compatible. The effort needed to deal with UTF16 properly could be spent better on UTF8.
    – Kerrek SB
    Jun 9, 2011 at 11:38
  • 26
    @Ian: UTF-8 DOES NOT have the same caveats as UTF-8. You cannot have surrogates in UTF-8. UTF-8 does not masquerade as something it’s not, but most programmers using UTF-16 are using it wrong. I know. I've watched them again and again and again and again.
    – tchrist
    Aug 15, 2011 at 19:44
  • 18
    Also, UTF-8 doesn't have the problem because everyone treats it as a variable width encoding. The reason UTF-16 has the problem is because everyone treats it like a fixed width encoding. Aug 18, 2011 at 20:22

20 Answers 20

339
votes

This is an old answer.
See UTF-8 Everywhere for the latest updates.

Opinion: Yes, UTF-16 should be considered harmful. The very reason it exists is because some time ago there used to be a misguided belief that widechar is going to be what UCS-4 now is.

Despite the "anglo-centrism" of UTF-8, it should be considered the only useful encoding for text. One can argue that source codes of programs, web pages and XML files, OS file names and other computer-to-computer text interfaces should never have existed. But when they do, text is not only for human readers.

On the other hand, UTF-8 overhead is a small price to pay while it has significant advantages. Advantages such as compatibility with unaware code that just passes strings with char*. This is a great thing. There're few useful characters which are SHORTER in UTF-16 than they are in UTF-8.

I believe that all other encodings will die eventually. This involves that MS-Windows, Java, ICU, python stop using it as their favorite. After long research and discussions, the development conventions at my company ban using UTF-16 anywhere except OS API calls, and this despite importance of performance in our applications and the fact that we use Windows. Conversion functions were developed to convert always-assumed-UTF8 std::strings to native UTF-16, which Windows itself does not support properly.

To people who say "use what needed where it is needed", I say: there's a huge advantage to using the same encoding everywhere, and I see no sufficient reason to do otherwise. In particular, I think adding wchar_t to C++ was a mistake, and so are the Unicode additions to C++0x. What must be demanded from STL implementations though is that every std::string or char* parameter would be considered unicode-compatible.

I am also against the "use what you want" approach. I see no reason for such liberty. There's enough confusion on the subject of text, resulting in all this broken software. Having above said, I am convinced that programmers must finally reach consensus on UTF-8 as one proper way. (I come from a non-ascii-speaking country and grew up on Windows, so I'd be last expected to attack UTF-16 based on religious grounds).

I'd like to share more information on how I do text on Windows, and what I recommend to everyone else for compile-time checked unicode correctness, ease of use and better multi-platformness of the code. The suggestion substantially differs from what is usually recommended as the proper way of using Unicode on windows. Yet, in depth research of these recommendations resulted in the same conclusion. So here goes:

  • Do not use wchar_t or std::wstring in any place other than adjacent point to APIs accepting UTF-16.
  • Don't use _T("") or L"" UTF-16 literals (These should IMO be taken out of the standard, as a part of UTF-16 deprecation).
  • Don't use types, functions or their derivatives that are sensitive to the _UNICODE constant, such as LPTSTR or CreateWindow().
  • Yet, _UNICODE always defined, to avoid passing char* strings to WinAPI getting silently compiled
  • std::strings and char* anywhere in program are considered UTF-8 (if not said otherwise)
  • All my strings are std::string, though you can pass char* or string literal to convert(const std::string &).
  • only use Win32 functions that accept widechars (LPWSTR). Never those which accept LPTSTR or LPSTR. Pass parameters this way:

    ::SetWindowTextW(Utils::convert(someStdString or "string litteral").c_str())
    

    (The policy uses conversion functions below.)

  • With MFC strings:

    CString someoneElse; // something that arrived from MFC. Converted as soon as possible, before passing any further away from the API call:
    
    std::string s = str(boost::format("Hello %s\n") % Convert(someoneElse));
    AfxMessageBox(MfcUtils::Convert(s), _T("Error"), MB_OK);
    
  • Working with files, filenames and fstream on Windows:

    • Never pass std::string or const char* filename arguments to fstream family. MSVC STL does not support UTF-8 arguments, but has a non-standard extension which should be used as follows:
    • Convert std::string arguments to std::wstring with Utils::Convert:

      std::ifstream ifs(Utils::Convert("hello"),
                        std::ios_base::in |
                        std::ios_base::binary);
      

      We'll have to manually remove the convert, when MSVC's attitude to fstream changes.

    • This code is not multi-platform and may have to be changed manually in the future
    • See fstream unicode research/discussion case 4215 for more info.
    • Never produce text output files with non-UTF8 content
    • Avoid using fopen() for RAII/OOD reasons. If necessary, use _wfopen() and WinAPI conventions above.

// For interface to win32 API functions
std::string convert(const std::wstring& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

std::wstring convert(const std::string& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

// Interface to MFC
std::string convert(const CString &mfcString)
{
#ifdef UNICODE
    return Utils::convert(std::wstring(mfcString.GetString()));
#else
    return mfcString.GetString();   // This branch is deprecated.
#endif
}

CString convert(const std::string &s)
{
#ifdef UNICODE
    return CString(Utils::convert(s).c_str());
#else
    Exceptions::Assert(false, "Unicode policy violation. See W569"); // This branch is deprecated as it does not support unicode
    return s.c_str();   
#endif
}
52
  • 39
    I can't agree. The advantages of utf16 over utf8 for many Asian languages completely dominate the points you make. It is naive to hope that the Japanese, Thai, Chinese, etc. are going to give up this encoding. The problematic clashes between charsets are when the charsets mostly seem similar, except with differences. I suggest standardising on: fixed 7bit: iso-irv-170; 8bit variable: utf8; 16bit variable: utf16; 32bit fixed: ucs4.
    – Charles Stewart
    Dec 9, 2009 at 15:24
  • 82
    @Charles: thanks for your input. True, some BMP characters are longer in UTF-8 than in UTF-16. But, let's face it: the problem is not in bytes that BMP Chinese characters take, but the software design complexity that arises. If a Chinese programmer has to design for variable-length characters anyway, it seems like UTF-8 is still a small price to pay compared to other variables in the system. He might use UTF-16 as a compression algorithm if space is so important, but even then it will be no match for LZ, and after LZ or other generic compression both take about the same size and entropy.
    – Pavel Radzivilovsky
    Dec 9, 2009 at 18:04
  • 32
    What I basically say is that simplification offered by having One encoding that is also compatible with existing char* programs, and is also the most popular today for everything is unimaginable. It is almost like in good old "plaintext" days. Want to open a file with a name? No need to care what kind of unicode you are doing, etc etc. I suggest we, developers, confine UTF-16 to very special cases of severe optimization where a tiny bit of performance is worth man-months of work.
    – Pavel Radzivilovsky
    Dec 9, 2009 at 18:08
  • 17
    Linux has had a specific requirement when choosing to use UTF-8 internally: compatibility with Unix. Windows didn't need that, and thus when the developers implemented Unicode, they added UCS-2 versions of almost all functions handling text and made the multibyte ones simply convert to UCS-2 and call the other ones. THey later replaces UCS-2 with UTF-16. Linux on the other hand kept to 8-bit encodings and thus used UTF-8, as it's the proper choice in that case. Mar 17, 2010 at 17:56
  • 34
    @Pavel Radzivilovsky: BTW, your writings about "I believe that all other encodings will die eventually. This involves that MS-Windows, Java, ICU, python stop using it as their favorite." and "In particular, I think adding wchar_t to C++ was a mistake, and so are the unicode additions to C++Ox." are either quite naive or very very arrogant. And this is coming from someone coding at home with a Linux and who is happy with the UTF-8 chars. To put it bluntly: It won't happen.
    – paercebal
    Sep 4, 2010 at 12:28
156
votes

Unicode codepoints are not characters! Sometimes they are not even glyphs (visual forms).

Some examples:

  • Roman numeral codepoints like "ⅲ". (A single character that looks like "iii".)
  • Accented characters like "á", which can be represented as either a single combined character "\u00e1" or a character and separated diacritic "\u0061\u0301".
  • Characters like Greek lowercase sigma, which have different forms for middle ("σ") and end ("ς") of word positions, but which should be considered synonyms for search.
  • Unicode discretionary hyphen U+00AD, which might or might not be visually displayed, depending on context, and which is ignored for semantic search.

The only ways to get Unicode editing right is to use a library written by an expert, or become an expert and write one yourself. If you are just counting codepoints, you are living in a state of sin.

9
  • 19
    This. Very much this. UTF-16 can cause problems, but even using UTF-32 throughout can (and will) still give you issues.
    – bcat
    Dec 24, 2010 at 0:48
  • 11
    What is a character? You can define a code point as a character and get by pretty much just fine. If you mean a user-visible glyph, that’s something else.
    – tchrist
    Aug 11, 2011 at 14:54
  • 7
    @tchrist sure for allocating space that definition is fine, but for anything else? Not so much. If you handle a combining character as a sole character (ie for a delete or "take first N characters" operation) you'll get strange and wrong behavior. If a code point has only meaning when combined with at least another you can't handle it on its own in any sensible manner.
    – Voo
    Aug 15, 2011 at 15:28
  • 6
    @Pacerier, this is late to the party, but I have to comment on that. Some languages have very large sets of potential combinations of diacritics (c.f. Vietnamese, i.e. mệt đừ). Having combinations rather than one character per diacritic is very helpful.
    – asthasr
    Apr 20, 2012 at 21:23
  • 21
    a small note on terminology: codepoints do correspond to unicode characters; what Daniel is talking about here are user-perceived characters, which correspond to unicode grapheme clusters
    – Christoph
    Apr 21, 2012 at 11:58
54
votes

There is a simple rule of thumb on what Unicode Transformation Form (UTF) to use: - utf-8 for storage and comunication - utf-16 for data processing - you might go with utf-32 if most of the platform API you use is utf-32 (common in the UNIX world).

Most systems today use utf-16 (Windows, Mac OS, Java, .NET, ICU, Qt). Also see this document: http://unicode.org/notes/tn12/

Back to "UTF-16 as harmful", I would say: definitely not.

People who are afraid of surrogates (thinking that they transform Unicode into a variable-length encoding) don't understand the other (way bigger) complexities that make mapping between characters and a Unicode code point very complex: combining characters, ligatures, variation selectors, control characters, etc.

Just read this series here http://www.siao2.com/2009/06/29/9800913.aspx and see how UTF-16 becomes an easy problem.

9
  • 26
    Please add some examples where UTF-32 is common in the UNIX world! Jan 13, 2011 at 13:39
  • 48
    No, you do not want to use UTF-16 for data processing. It's a pain in the ass. It has all the disadvantages of UTF-8 but none of its advantages. Both UTF-8 and UTF-32 are clearly superior to the vicious hack previously known as Mrs UTF-16, whose maiden name was UCS-2.
    – tchrist
    Aug 11, 2011 at 14:18
  • 34
    I yesterday just found a bug in the Java core String class’s equalsIgnoreCase method (also others in the string class) that would never have been there had Java used either UTF-8 or UTF-32. There are millions of these sleeping bombshells in any code that uses UTF-16, and I am sick and tired of them. UTF-16 is a vicious pox that plagues our software with insidious bugs forever and ever. It is clearly harmful, and should be deprecated and banned.
    – tchrist
    Aug 11, 2011 at 14:53
  • 7
    @tchrist Wow so a non-surrogate aware function (because it was written when there were none and is sadly documented in such a way that makes it probably impossible to adapt - it specifies .toUpperCase(char)) will result in the wrong behavior? You're aware that a UTF-32 function with an outdated code point map wouldn't handle this any better? Also the whole Java API handles surrogates not especially well and the more intricate points about Unicode not at all - and with the later the used encoding wouldn't matter at all.
    – Voo
    Aug 15, 2011 at 15:32
  • 8
    -1: An unconditional .Substring(1) in .NET is a trivial example of something that break support for all of non-BMP Unicode. Everything that uses UTF-16 has this problem; it's too easy to treat it as a fixed-width encoding, and you see problems too rarely. That makes it an actively harmful encoding if you want to support Unicode. Dec 4, 2012 at 15:24
43
votes

Yes, absolutely.

Why? It has to do with exercising code.

If you look at these codepoint usage statistics on a large corpus by Tom Christiansen you'll see that trans-8bit BMP codepoints are used several orders if magnitude more than non-BMP codepoints:

 2663710 U+002013 ‹–›  GC=Pd    EN DASH
 1065594 U+0000A0 ‹ ›  GC=Zs    NO-BREAK SPACE
 1009762 U+0000B1 ‹±›  GC=Sm    PLUS-MINUS SIGN
  784139 U+002212 ‹−›  GC=Sm    MINUS SIGN
  602377 U+002003 ‹ ›  GC=Zs    EM SPACE

 544 U+01D49E ‹𝒞›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL C
 450 U+01D4AF ‹𝒯›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL T
 385 U+01D4AE ‹𝒮›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL S
 292 U+01D49F ‹𝒟›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL D
 285 U+01D4B3 ‹𝒳›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL X

Take the TDD dictum: "Untested code is broken code", and rephrase it as "unexercised code is broken code", and think how often programmers have to deal with non-BMP codepoints.

Bugs related to not dealing with UTF-16 as a variable-width encoding are much more likely to go unnoticed than the equivalent bugs in UTF-8. Some programming languages still don't guarantee to give you UTF-16 instead of UCS-2, and some so-called high-level programming languages offer access to code units instead of code-points (even C is supposed to give you access to codepoints if you use wchar_t, regardless of what some platforms may do).

6
  • 16
    "Bugs related to not dealing with UTF-16 as a variable-width encoding are much more likely to go unnoticed than the equivalent bugs in UTF-8." This is the core of the issue, and hence, the correct answer. Aug 19, 2011 at 13:01
  • 3
    Precisely. If your UTF-8 handling is borked, it'll be immediately obvious. If your UTF-8 handling is borked, you'll only notice if you put in uncommon Han characters or math symbols. Aug 1, 2012 at 7:26
  • 1
    Very true, but on the other hand, what are unit tests for if you should depend on luck to find bugs on less frequent cases?
    – musiphil
    Jun 18, 2014 at 21:09
  • @musiphil: so, when was the last time you created a unit test for non-BMP characters?
    – ninjalj
    Jun 19, 2014 at 21:14
  • 1
    To elaborate on my earlier statement: even with UTF-8, you cannot be assured that you have covered all cases after only seeing some working examples. Same with UTF-16: you need to test whether your code works both with non-surrogates and with surrogates. (Someone could even argue that UTF-8 has at least four major cases while UTF-16 has only two.)
    – musiphil
    Jun 19, 2014 at 22:00
40
votes

I would suggest that thinking UTF-16 might be considered harmful says that you need to gain a greater understanding of unicode.

Since I've been downvoted for presenting my opinion on a subjective question, let me elaborate. What exactly is it that bothers you about UTF-16? Would you prefer if everything was encoded in UTF-8? UTF-7? Or how about UCS-4? Of course certain applications are not designed to handle everysingle character code out there - but they are necessary, especially in today's global information domain, for communication between international boundaries.

But really, if you feel UTF-16 should be considered harmful because it's confusing or can be improperly implemented (unicode certainly can be), then what method of character encoding would be considered non-harmful?

EDIT: To clarify: Why consider improper implementations of a standard a reflection of the quality of the standard itself? As others have subsequently noted, merely because an application uses a tool inappropriately, does not mean that the tool itself is defective. If that were the case, we could probably say things like "var keyword considered harmful", or "threading considered harmful". I think the question confuses the quality and nature of the standard with the difficulties many programmers have in implementing and using it properly, which I feel stem more from their lack of understanding how unicode works, rather than unicode itself.

15
  • 33
    -1: How about addressing some of Artyom's objections, rather than just patronising him?
    – RichieHindle
    Jun 26, 2009 at 16:12
  • 8
    BTW: When I started writing this article I almost wanted to write "Does Joel on Softeare article of Unicode should be considered harmful" because there are many mistakes. For example: utf-8 encoding takes up to 4 characters and not 6. Also it does not distinguish between UCS-2 and UTF-16 that are really different -- and actually cause the problems I talk about.
    – Artyom
    Jun 26, 2009 at 16:12
  • 32
    Also, it should be noted that when Joel wrote that article, the UTF-8 standard WAS 6 bytes, not 4. RFC 3629 changed the standard to 4 bytes several months AFTER he wrote the article. Like most anything on the internet, it pays to read from more than one source, and to be aware of the age of your sources. The link wasn't intended to be the "end all be all", but rather a starting point.
    – patjbs
    Jun 26, 2009 at 16:42
  • 7
    I would pic: utf-8 or utf-32 that are: variable length encoding in almost all cases (including BMP) or fixed length encoding always.
    – Artyom
    Jul 12, 2009 at 6:50
  • 18
    @iconiK: Don’t be silly. UTF-16 is absolutely not the de facto standard for processing text. Show me a programming lanuage more suited to text processing that Perl, which has always (well, for more than a decade) used abstract characters with an underlying UTF-8 representation internally. Because of this, every Perl program automatically handles all Unicode without the user having to constantly monkey around with idiotic surrogates. The length of a string is its count in code points, not code units. Anything else is sheer stupidity putting the backwards into backwards compatibility.
    – tchrist
    Aug 11, 2011 at 14:50
37
votes

There is nothing wrong with Utf-16 encoding. But languages that treat the 16-bit units as characters should probably be considered badly designed. Having a type named 'char' which does not always represent a character is pretty confusing. Since most developers will expect a char type to represent a code point or character, much code will probably break when exposed to characters beyound BMP.

Note however that even using utf-32 does not mean that each 32-bit code point will always represent a character. Due to combining characters, an actual character may consist of several code points. Unicode is never trivial.

BTW. There is probably the same class of bugs with platforms and applications which expect characters to be 8-bit, which are fed Utf-8.

5
  • 12
    In Java's case, if you look at their timeline (java.com/en/javahistory/timeline.jsp), you see that the primarily development of String happened while Unicode was 16 bits (it changed in 1996). They had to bolt on the ability to handle non BMP code points, thus the confusion. Jun 26, 2009 at 17:40
  • 10
    @Kathy: Not really an excuse for C#, though. Generally, I agree, that there should be a CodePoint type, holding a single code point (21 bits), a CodeUnit type, holding a single code unit (16 bits for UTF-16) and a Character type would ideally have to support a complete grapheme. But that makes it functionally equivalent to a String ...
    – Joey
    Apr 2, 2010 at 13:43
  • 1
    This answer is almost two years old, but I can't help but comment on it. "Having a type named 'char' which does not always represent a character is pretty confusing." And yet people use it all the time in C and the like to represent integer data that can be stored in a single byte.
    – JAB
    Jun 6, 2011 at 15:53
  • And I've seen a lot of C code that doesn't handle character encoding correctly.
    – dan04
    Aug 18, 2011 at 23:06
  • 1
    C# has a different excuse: it was designed for Windows, and Windows was built on UCS-2 (it's very annoying that even today Windows APIs cannot support UTF-8). Plus, I think Microsoft wanted Java compatibility (.NET 1.0 had a Java compatibility library, but they dropped Java support very quickly--I'm guessing this is due to Sun's lawsuit against MS?)
    – Qwertie
    May 1, 2012 at 0:05
20
votes

My personal choice is to always use UTF-8. It's the standard on Linux for nearly everything. It's backwards compatible with many legacy apps. There is a very minimal overhead in terms of extra space used for non-latin characters vs the other UTF formats, and there is a significant savings in space for latin characters. On the web, latin languages reign supreme, and I think they will for the foreseeable future. And to address one of the main arguments in the original post: nearly every programmer is aware that UTF-8 will sometimes have multi-byte characters in it. Not everyone deals with this correctly, but they are usually aware, which is more than can be said for UTF-16. But, of course, you need to choose the one most appropriate for your application. That's why there's more than one in the first place.

8
  • 3
    UTF-16 is simpler for anything inside BMP, that's why it is used so widely. But I'm a fan of UTF-8 too, it also has no problems with byte order, which works to its advantage.
    – Malcolm
    Jun 26, 2009 at 16:57
  • 2
    Theoretically, yes. In practice there are such things as, say, UTF-16BE, which means UTF-16 in big endian without BOM. This is not some thing I made up, this is an actual encoding allowed in ID3v2.4 tags (ID3v2 tags suck, but are, unfortunately, widely used). And in such cases you have to define endianness externally, because the text itself doesn't contain BOM. UTF-8 is always written one way and it doesn't have such a problem.
    – Malcolm
    Apr 2, 2010 at 15:33
  • 23
    No, UTF-16 is not simpler. It is harder. It misleads and deceives you into thinking it is fixed width. All such code is broken and all the moreso because you don’t notice until it’s too late. CASE IN POINT: I just found yet another stupid UTF-16 bug in the Java core libraries yesterday, this time in String.equalsIgnoreCase, which was left in UCS-2 braindeath buggery, and so fails on 16/17 valid Unicode code points. How long has that code been around? No excuse for it to be buggy. UTF-16 leads to sheer stupidity and an accident waiting to happen. Run screaming from UTF-16.
    – tchrist
    Aug 11, 2011 at 14:42
  • 3
    @tchrist One must be a very ignorant developer to not know that UTF-16 is not fixed length. If you start with Wikipedia, you will read the following at the very top: "It produces a variable-length result of either one or two 16-bit code units per code point". Unicode FAQ says the same: unicode.org/faq//utf_bom.html#utf16-1. I don't know, how UTF-16 can deceive anybody if it is written everywhere that it is variable length. As for the method, it was never designed for UTF-16 and shouldn't be considered Unicode, as simple as that.
    – Malcolm
    Aug 13, 2011 at 10:30
  • 2
    @tchrist Do you have a source for your statistics? Though if good programmers a scarce, I think this is good, because we become more valuable. :) As for the Java APIs, char-based parts may eventually get deprecated, but this is not a guarantee that they won't be used. And they definitely won't be removed for compability reasons.
    – Malcolm
    Aug 16, 2011 at 8:29
18
votes

Well, there is an encoding that uses fixed-size symbols. I certainly mean UTF-32. But 4 bytes for each symbol is too much of wasted space, why would we use it in everyday situations?

To my mind, most problems appear from the fact that some software fell behind the Unicode standard, but were not quick to correct the situation. Opera, Windows, Python, Qt - all of them appeared before UTF-16 became widely known or even came into existence. I can confirm, though, that in Opera, Windows Explorer, and Notepad there are no problems with characters outside BMP anymore (at least on my PC). But anyway, if programs don't recognise surrogate pairs, then they don't use UTF-16. Whatever problems arise from dealing with such programs, they have nothing to do with UTF-16 itself.

However, I think that the problems of legacy software with only BMP support are somewhat exaggerated. Characters outside BMP are encountered only in very specific cases and areas. According to the Unicode official FAQ, "even in East Asian text, the incidence of surrogate pairs should be well less than 1% of all text storage on average". Of course, characters outside BMP shouldn't be neglected because a program is not Unicode-conformant otherwise, but most programs are not intended for working with texts containing such characters. That's why if they don't support it, it is unpleasant, but not a catastrophy.

Now let's consider the alternative. If UTF-16 didn't exist, then we wouldn't have an encoding which is well-suited for non-ASCII text, and all the software created for UCS-2 would have to be completely redesigned to remain Unicode-compliant. The latter most likely would only slow Unicode adoption. Also we wouldn't have been able to maintain compability with text in UCS-2 like UTF-8 does in relation to ASCII.

Now, putting aside all the legacy issues, what are the arguments against the encoding itself? I really doubt that developers nowadays don't know that UTF-16 is variable length, it is written everywhere strarting with Wikipedia. UTF-16 is much less difficult to parse than UTF-8, if someone pointed out complexity as a possible problem. Also it is wrong to think that it is easy to mess up with determining the string length only in UTF-16. If you use UTF-8 or UTF-32, you still should be aware that one Unicode code point doesn't necessarily mean one character. Other than that, I don't think that there's anything substantial against the encoding.

Therefore I don't think the encoding itself should be considered harmful. UTF-16 is a compromise between simplicity and compactness, and there's no harm in using what is needed where it is needed. In some cases you need to remain compatible with ASCII and you need UTF-8, in some cases you want to work with work with Han ideographs and conserve space using UTF-16, in some cases you need universal representations of characters usign a fixed-length encoding. Use what's more appropriate, just do it properly.

31
  • 21
    That's a rather blinkered, Anglo-centric view, Malcolm. Almost on a par with "ASCII is good enough for the USA - the rest of the world should fit in with us". Jun 26, 2009 at 16:22
  • 28
    Actually I'm from Russia and encounter cyrillics all the time (including my own programs), so I don't think that I have Anglo-centric view. :) Mentioning ASCII is not quite appropirate, because it's not Unicode and doesn't support specific characters. UTF-8, UTF-16, UTF-32 support the very same international character sets, they are just intended for use in their specific areas. And this is exactly my point: if you use mostly English, use UTF-8, if you use mostly cyrillics, use UTF-16, if you use ancient languages, use UTF-32. Quite simple.
    – Malcolm
    Jun 26, 2009 at 16:36
  • 16
    "Not true, Asian scripts like Japanese, Chinese or Arabic belong to BMP also. BMP itself is actually very large and certainly large enough to include all the scripts used nowadays" This is all so wrong. BMP contains 0xFFFF characters (65536). Chinese alone has more than that. Chinese standards (GB 18030) has more than that. Unicode 5.1 already allocated more than 100,000 characters.
    – Mihai Nita
    Jul 24, 2009 at 8:11
  • 12
    @Marcolm: "BMP itself is actually very large and certainly large enough to include all the scripts used nowadays" Not true. At this point Unicode already allocated about 100K characters, way more than BMP can accomodate. There are big chunks of Chinese characters outside BMP. And some of them are required by GB-18030 (mandatory Chinese standard). Other are required by (non-mandatory) Japanese and Korean standards. So if you try to sell anything in those markets, you need beyond BMP support.
    – Mihai Nita
    Sep 25, 2009 at 21:41
  • 8
    Anything that uses UTF-16 but can only handle narrow BMP characters is not actually using UTF-16. It is buggy and broken. The premise of the OP is sound: UTF-16 is harmful, because it leads naïve people into writing broken code. Either you can handle Unicode text, or you can’t. If you cannot, then you are picking a subset, which is just as stupid as ASCII-only text processing.
    – tchrist
    Aug 11, 2011 at 14:46
16
votes

Years of Windows internationalization work especially in East Asian languages might have corrupted me, but I lean toward UTF-16 for internal-to-the-program representations of strings, and UTF-8 for network or file storage of plaintext-like documents. UTF-16 can usually be processed faster on Windows, though, so that's the primary benefit of using UTF-16 in Windows.

Making the leap to UTF-16 dramatically improved the adequacy of average products handling international text. There are only a few narrow cases when the surrogate pairs need to be considered (deletions, insertions, and line breaking, basically) and the average-case is mostly straight pass-through. And unlike earlier encodings like JIS variants, UTF-16 limits surrogate pairs to a very narrow range, so the check is really quick and works forward and backward.

Granted, it's roughly as quick in correctly-encoded UTF-8, too. But there's also many broken UTF-8 applications that incorrectly encode surrogate pairs as two UTF-8 sequences. So UTF-8 doesn't guarantee salvation either.

IE handles surrogate pairs reasonably well since 2000 or so, even though it typically is converting them from UTF-8 pages to an internal UTF-16 representation; I'm fairly sure Firefox has got it right too, so I don't really care what Opera does.

UTF-32 (aka UCS4) is pointless for most applications since it's so space-demanding, so it's pretty much a nonstarter.

9
  • 6
    I didn't quite get your comment on UTF-8 and surrogate pairs. Surrogate pairs is only a concept that is meaningful in the UTF-16 encoding, right? Perhaps code that converts directly from UTF-16 encoding to UTF-8 encoding might get this wrong, and in that case, the problem is incorrectly reading the UTF-16, not writing the UTF-8. Is that right? Jun 27, 2009 at 23:54
  • 11
    What Jason's talking about is software that deliberately implements UTF-8 that way: create a surrogate pair, then UTF-8 encode each half separately. The correct name for that encoding is CESU-8, but Oracle (e.g.) misrepresents it as UTF-8. Java employs a similar scheme for object serialization, but it's clearly documented as "Modified UTF-8" and only for internal use. (Now, if we could just get people to READ that documentation and stop using DataInputStream#readUTF() and DataOutputStream#writeUTF() inappropriately...)
    – Alan Moore
    Jun 28, 2009 at 14:35
  • AFAIK, UTF-32 is still variable length encoding, and not equal to UCS4 which is specific range of code point.
    – Eonil
    Nov 15, 2013 at 21:41
  • @Eonil, UTF-32 will only ever be distinguishable from UCS4 if we have a Unicode standard that features something like a UCS5 or larger.
    – JasonTrue
    Nov 15, 2013 at 21:49
  • @JasonTrue Still, only the results are equal coincidently, not guaranteed by design. Same thing was happen in 32-bit memory addressing, Y2K, UTF16/UCS2. Or do we have any guarantee of that equality? If we have, I would gladly use that. But I don't want to write a possible breakable code. I am writing a character level code, and lack of a guaranteed way to transcode between UTF <-> code point is bugging me a lot.
    – Eonil
    Nov 15, 2013 at 22:02
16
votes

UTF-8 is definitely the way to go, possibly accompanied by UTF-32 for internal use in algorithms that need high performance random access (but that ignores combining chars).

Both UTF-16 and UTF-32 (as well as their LE/BE variants) suffer of endianess issues, so they should never be used externally.

1
  • 9
    Constant time random access is possible with UTF-8 too, just use code units rather than code points. Maybe you need real random code point access, but I've never seen a use case, and you're just as likely to want random grapheme cluster access instead.
    – Rhamphoryncus
    Aug 6, 2010 at 7:32
15
votes

UTF-16? definitely harmful. Just my grain of salt here, but there are exactly three acceptable encodings for text in a program:

  • ASCII: when dealing with low level things (eg: microcontrollers) that can't afford anything better
  • UTF8: storage in fixed-width media such as files
  • integer codepoints ("CP"?): an array of the largest integers that are convenient for your programming language and platform (decays to ASCII in the limit of low resorces). Should be int32 on older computers and int64 on anything with 64-bit addressing.

  • Obviously interfaces to legacy code use what encoding is needed to make the old code work right.

8
  • 4
    @simon buchan, the U+10ffff max will go out the window when (not if) they run out of codepoints. That said, useing int32 on a p64 system for speed is probably safe, since i doubt they'll exceed U+ffffffff before you're forced to rewrite your code for 128 bit systems around 2050. (That is the point of "use the largest int that is convenient" as opposed to "largest available" (which would probably be int256 or bignums or something).)
    – David X
    Jun 10, 2010 at 2:59
  • 1
    @David: Unicode 5.2 encodes 107,361 codepoints. There are 867,169 unused codepoints. "when" is just silly. A Unicode codepoint is defined as a number from 0 to 0x10FFFF, a property which UTF-16 depends upon. (Also 2050 seems much to low an estimate for 128 bit systems when a 64-bit system can hold the entirety of the Internet in it's address space.)
    – Simon Buchan
    Jun 11, 2010 at 6:07
  • 3
    @David: Your "when" was referring to running out of Unicode codepoints, not a 128-bit switch which, yes, will be in the next few centuries. Unlike memory, there is no exponential growth of characters, so the Unicode Consortium has specifically guaranteed they will never allocate a codepoint above U+10FFFF. This really is one of those situations when 21 bits is enough for anybody.
    – Simon Buchan
    Jun 13, 2010 at 2:53
  • 10
    @Simon Buchan: At least until first contact. :)
    – dalle
    Oct 18, 2010 at 17:38
  • 3
    Unicode used to guarantee that there would be no code points above U+FFFF too. Oct 4, 2013 at 18:47
13
votes

Unicode defines code points up to 0x10FFFF (1,114,112 codes), all applications running in multilingual environment dealing with strings/file names etc. should handle that correctly.

Utf-16: covers only 1,112,064 codes. Although those at the end of Unicode are from planes 15-16 (Private Use Area). It can not grow any further in the future except breaking Utf-16 concept.

Utf-8: covers theoretically 2,216,757,376 codes. Current range of Unicode codes can be represented by maximally 4 byte sequence. It does not suffer with byte order problem, it is "compatible" with ascii.

Utf-32: covers theoretically 2^32=4,294,967,296 codes. Currently it is not variable length encoded and probably will not be in the future.

Those facts are self explanatory. I do not understand advocating general use of Utf-16. It is variable length encoded (can not be accessed by index), it has problems to cover whole Unicode range even at present, byte order must be handled, etc. I do not see any advantage except that it is natively used in Windows and some other places. Even though when writing multi-platform code it is probably better to use Utf-8 natively and make conversions only at the end points in platform dependent way (as already suggested). When direct access by index is necessary and memory is not a problem, Utf-32 should be used.

The main problem is that many programmers dealing with Windows Unicode = Utf-16 do not even know or ignore the fact that it is variable length encoded.

The way it is usually in *nix platform is pretty good, c strings (char *) interpreted as Utf-8 encoded, wide c strings (wchar_t *) interpreted as Utf-32.

8
  • 7
    Note: UTF-16 does covers All Unicode as Unicode Consortium decided that 10FFFF is the TOP range of Unicode and defined UTF-8 maximal 4 bytes length and explicitly excluded range 0xD800-0xDFFF from valid code points range and this range is used for creation of surrogate pairs. So any valid Unicode text can be represented with each of one of these encodings. Also about growing to future. It doesn't seems that 1 Million code points would not be enough in any far future.
    – Artyom
    Jan 21, 2011 at 15:06
  • 7
    @Kerrek: Incorrect: UCS-2 is not a valid Unicode encoding. All UTF-* encodings by definition can represent any Unicode code point that is legal for interchange. UCS-2 can represent far fewer than that, plus a few more. Repeat: UCS-2 is not a valid Unicode encoding, any moreso than ASCII is.
    – tchrist
    Aug 11, 2011 at 14:33
  • 1
    "I do not understand advocating general use of Utf-8. It is variable length encoded (can not be accessed by index)"
    – Ian Boyd
    Aug 11, 2011 at 15:35
  • 9
    @Ian Boyd, the need to access a string’s individual character in a random access pattern is incredibly overstated. It is about as common as wanting to compute the diagonal of a matrix of characters, which is super rare. Strings are virtually always processed sequentially, and since accessing UTF-8 char N+1 given that you are at UTF-8 char N is O(1), there is no issue. There is surpassingly little need to make random access of strings. Whether you think it is worth the storage space to go to UTF-32 instead of UTF-8 is your own opinion, but for me, it is altogether a non-issue.
    – tchrist
    Aug 11, 2011 at 20:38
  • 2
    @tchrist, I will grant you strings are virtually always processed sequentially if you include reverse iteration as "sequential" and stretch that a little further comparison of the trailing end of a string to a known string. Two very common scenarios are truncating whitespace from the end of strings and checking the file extension at the end of a path.
    – Andy Dent
    May 13, 2012 at 14:16
11
votes

Add this to the list:

The presented scenario is simple (even more simple as I will present it here than it was originally!): 1.A WinForms TextBox sits on a Form, empty. It has a MaxLength set to 20.

2.The user types into the TextBox, or maybe pastes text into it.

3.No matter what you type or paste into the TextBox, you are limited to 20, though it will sympathetically beep at text beyond the 20 (YMMV here; I changed my sound scheme to give me that effect!).

4.The small packet of text is then sent somewhere else, to start an exciting adventure.

Now this is an easy scenario, and anyone can write this up, in their spare time. I just wrote it up myself in multiple programming languages using WinForms, because I was bored and had never tried it before. And with text in multiple actual languages because I am wired that way and have more keyboard layouts than possibly anyone in the entire freaking universe.

I even named the form Magic Carpet Ride, to help ameliorate the boredom.

This did not work, for what it's worth.

So instead, I entered the following 20 characters into my Magic Carpet Ride form:

0123401234012340123𠀀

Uh oh.

That last character is U+20000, the first Extension B ideograph of Unicode (aka U+d840 U+dc00, to its close friends who he is not ashamed to be disrobed, as it were, in front of)....

enter image description here

And now we have a ball game.

Because when TextBox.MaxLength talks about

Gets or sets the maximum number of characters that can be manually entered into the text box.

what it really means is

Gets or sets the maximum number of UTF-16 LE code units that can be manually entered into the text box and will mercilessly truncate the living crap out of any string that tries to play cutesy games with the linguistic character notion that only someone as obsessed as that Kaplan fellow will find offensive (geez he needs to get out more!).

I'll try and see about getting the document updated....
Regular readers who remember my UCS-2 to UTF-16 series will note my unhappiness with the simplistic notion of TextBox.MaxLength and how it should handle at a minimum this case where its draconian behavior creates an illegal sequence, one that other parts of the .Net Framework may throw a

  • System.Text.EncoderFallbackException: Unable to translate Unicode character \uD850 at index 0 to specified code page.*

exception if you pass this string elsewhere in the .Net Framework (as my colleague Dan Thompson was doing).

Now okay, perhaps the full UCS-2 to UTF-16 series is out of the reach of many.
But isn't it reasonable to expect that TextBox.Text will not produce a System.String that won't cause another piece of the .Net Framework to throw? I mean, it isn't like there is a chance in the form of some event on the control that tells you of the upcoming truncation where you can easily add the smarter validation -- validation that the control itself does not mind doing. I would go so far as to say that this punk control is breaking a safety contract that could even lead to security problems if you can class causing unexpected exceptions to terminate an application as a crude sort of denial of service. Why should any WinForms process or method or algorithm or technique produce invalid results?

Source : Michael S. Kaplan MSDN Blog

1
  • Thanks, very good link! I've added it to the issues list in the question.
    – Artyom
    Dec 21, 2010 at 6:28
9
votes

I wouldn't necessarily say that UTF-16 is harmful. It's not elegant, but it serves its purpose of backwards compatibility with UCS-2, just like GB18030 does with GB2312, and UTF-8 does with ASCII.

But making a fundamental change to the structure of Unicode in midstream, after Microsoft and Sun had built huge APIs around 16-bit characters, was harmful. The failure to spread awareness of the change was more harmful.

3
  • 8
    UTF-8 is a superset of ASCII, but UTF-16 is NOT a superset of UCS-2. Although almost a superset, a correct encoding of UCS-2 into UTF-8 results in the abomination known as CESU-8; UCS-2 doesn't have surrogates, just ordinary code points, so they must be translated as such. The real advantage of UTF-16 is that it's easier to upgrade a UCS-2 codebase than a complete rewrite for UTF-8. Funny, huh?
    – Rhamphoryncus
    Aug 6, 2010 at 7:28
  • 1
    Sure, technically UTF-16 isn't a superset of UCS-2, but when were U+D800 to U+DFFF ever used for anything except UTF-16 surrogates?
    – dan04
    Aug 17, 2010 at 18:51
  • 2
    Doesn't matter. Any processing other than blindly passing through the bytestream requires you to decode the surrogate pairs, which you can't do if you're treating it as UCS-2.
    – Rhamphoryncus
    Aug 29, 2010 at 13:02
6
votes

UTF-16 is the best compromise between handling and space and that's why most major platforms (Win32, Java, .NET) use it for internal representation of strings.

13
  • 31
    -1 because UTF-8 is likely to be smaller or not significantly different. For certain Asian scripts UTF-8 is three bytes per glyph while UTF-16 is only two, but this is balanced by UTF-8 being only one byte for ASCII (which does often appear even within asian languages in product names, commands and such things). Further, in the said languages, a glyph conveys more information than a latin character so it is justified for it to take more space.
    – Tronic
    Mar 18, 2010 at 2:47
  • 32
    I would not call combining the worst sides of both options a good compromise.
    – Tronic
    Mar 23, 2010 at 15:36
  • 18
    It's not easier than UTF-8. It's variable-length too.
    – luiscubal
    Mar 25, 2010 at 17:50
  • 36
    Leaving debates about the benefits of UTF-16 aside: What you cited is not the reason for Windows, Java or .NET using UTF-16. Windows and Java date back to a time where Unicode was a 16-bit encoding. UCS-2 was a reasonable choice back then. When Unicode became a 21-bit encoding migrating to UTF-16 was the best choice existing platforms had. That had nothing to do with ease of handling or space compromises. It's just a matter of legacy.
    – Joey
    Apr 2, 2010 at 14:13
  • 10
    .NET inherits the Windows legacy here.
    – Joey
    Apr 2, 2010 at 16:19
6
votes

I've never understood the point of UTF-16. If you want the most space-efficient representation, use UTF-8. If you want to be able to treat text as fixed-length, use UTF-32. If you want neither, use UTF-16. Worse yet, since all of the common (basic multilingual plane) characters in UTF-16 fit in a single code point, bugs that assume that UTF-16 is fixed-length will be subtle and hard to find, whereas if you try to do this with UTF-8, your code will fail fast and loudly as soon as you try to internationalize.

6
votes

Since I cannot yet comment, I post this as an answer, since it seems I cannot otherwise contact the authors of utf8everywhere.org. It's a shame I don't automatically get the comment privilege, since I have enough reputation on other stackexchanges.

This is meant as a comment to the Opinion: Yes, UTF-16 should be considered harmful answer.

One little correction:

To prevent one from accidentally passing a UTF-8 char* into ANSI-string versions of Windows-API functions, one should define UNICODE, not _UNICODE. _UNICODE maps functions like _tcslen to wcslen, not MessageBox to MessageBoxW. Instead, the UNICODE define takes care of the latter. For proof, this is from MS Visual Studio 2005's WinUser.h header:

#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

At the very minimum, this error should be corrected on utf8everywhere.org.

A suggestion:

Perhaps the guide should contain an example of explicit use of the Wide-string version of a data structure, to make it less easy to miss/forget it. Using Wide-string versions of data structures on top of using Wide-string versions of functions makes it even less likely that one accidentally calls an ANSI-string version of such a function.

Example of the example:

WIN32_FIND_DATAW data; // Note the W at the end.
HANDLE hSearch = FindFirstFileW(widen("*.txt").c_str(), &data);
if (hSearch != INVALID_HANDLE_VALUE)
{
    FindClose(hSearch);
    MessageBoxW(nullptr, data.cFileName, nullptr, MB_OK);
}
5
  • Agreed; thanks! We will update the document. The document still needs more development and adding information about databases. We are happy to receive contributions of wordings. Feb 14, 2014 at 12:41
  • @PavelRadzivilovsky _UNICODE is still there :(
    – cubuspl42
    Apr 18, 2014 at 12:19
  • thanks for reminding. cubus, Jelle, Would you like a user to our SVN? Apr 25, 2014 at 13:15
  • @Pavel Sure, would appreciate it! Apr 25, 2014 at 13:45
  • @JelleGeerts: I apologize for this delay. You could always contact us by our emails (linked from the manifesto) or Facebook. We are easy to find. Although I believe we fixed the issue you brought here (and I credited you there), the whole UTF-8 vs UTF-16 debates are still relevant. If you have more to contribute feel free to contact us through those private channels. Jun 24, 2015 at 19:03
5
votes

Someone said UCS4 and UTF-32 were same. No so, but I know what you mean. One of them is an encoding of the other, though. I wish they'd thought to specify endianness from the first so we wouldn't have the endianess battle fought out here too. Couldn't they have seen that coming? At least UTF-8 is the same everywhere (unless someone is following the original spec with 6-bytes).

If you use UTF-16 you have to include handling for multibyte chars. You can't go to the Nth character by indexing 2N into a byte array. You have to walk it, or have character indices. Otherwise you've written a bug.

The current draft spec of C++ says that UTF-32 and UTF-16 can have little-endian, big-endian, and unspecified variants. Really? If Unicode had specified that everyone had to do little-endian from the beginning then it would have all been simpler. (I would have been fine with big-endian as well.) Instead, some people implemented it one way, some the other, and now we're stuck with silliness for nothing. Sometimes it's embarrassing to be a software engineer.

4
  • Unspecified endianess is supposed to include BOM as the first character, used for determining which way the string should be read. UCS-4 and UTF-32 indeed are the same nowadays, i.e. a numeric UCS value between 0 and 0x10FFFF stored in a 32 bit integer.
    – Tronic
    Oct 20, 2010 at 23:34
  • 5
    @Tronic: Technically, this is not true. Although UCS-4 can store any 32-bit integer, UTF-32 is forbidden from storing the non-character code points that are illegal for interchange, such as 0xFFFF, 0xFFFE, and the all the surrogates. UTF is a transport encoding, not an internal one.
    – tchrist
    Aug 11, 2011 at 14:30
  • Endianness issues are unavoidable as long as different processors continue to use different byte orders. However, it might have been nice if there were a "preferred" byte order for file storage of UTF-16.
    – Qwertie
    May 1, 2012 at 0:16
  • Even though UTF-32 is fixed-width for code points, it is not fixed-width for characters. (Heard of something called "combining characters"?) So you can't go to the N'th character simply by indexing 4N into the byte array.
    – musiphil
    Jun 19, 2014 at 5:05
2
votes

I don't think it's harmful if the developer is careful enough.
And they should accept this trade off if they know well too.

As a Japanese software developer, I find UCS-2 large enough and limiting the space apparently simplifies the logic and reduces runtime memory, so using utf-16 under UCS-2 limitation is good enough.

There are filesystem or other application which assumes codepoints and bytes to be proportional, so that raw codepoint number can be guaranteed to be fit to some fixed size storage.

One example is NTFS and VFAT specifying UCS-2 as their filename storage encoding.

If those example really wants to extend to support UCS-4, I could agree using utf-8 for everything anyway, but fixed length has good points like:

  1. can guarantee the size by length (data size and codepoint length is proportional)
  2. can use the encoding number for hash lookup
  3. non-compressed data is reasonably sized (compared to utf-32/UCS-4)

In the future when memory/processing power is cheap even in any embeded devices, we may accept the device being a bit slow for extra cache misses or page faults and extra memory usage, but this wont happen in the near future I guess...

1
  • 3
    For those reading this comment, its worth noting that UCS-2 is not the same thing as UTF-16. Please look up the differences to understand. Dec 19, 2012 at 19:39
1
vote

"Should one of the most popular encodings, UTF-16, be considered harmful?"

Quite possibly, but the alternatives should not necessarily be viewed as being much better.

The fundamental issue is that there are many different concepts about: glyphs, characters, codepoints and byte sequences. The mapping between each of these is non-trivial, even with the aid of a normalization library. (For example, some characters in European languages that are written with a Latin-based script are not written with a single Unicode codepoint. And that's at the simpler end of the complexity!) What this means is that to get everything correct is quite amazingly difficult; bizarre bugs are to be expected (and instead of just moaning about them here, tell the maintainers of the software concerned).

The only way in which UTF-16 can be considered to be harmful as opposed to, say, UTF-8 is that it has a different way of encoding code points outside the BMP (as a pair of surrogates). If code is wishing to access or iterate by code point, that means it needs to be aware of the difference. OTOH, it does mean that a substantial body of existing code that assumes "characters" can always be fit into a two-byte quantity — a fairly common, if wrong, assumption — can at least continue to work without rebuilding it all. In other words, at least you get to see those characters that aren't being handled right!

I'd turn your question on its head and say that the whole damn shebang of Unicode should be considered harmful and everyone ought to use an 8-bit encoding, except I've seen (over the past 20 years) where that leads: horrible confusion over the various ISO 8859 encodings, plus the whole set of ones used for Cyrillic, and the EBCDIC suite, and… well, Unicode for all its faults beats that. If only it wasn't such a nasty compromise between different countries' misunderstandings.

2
  • Knowing our luck, in a few years we'll find ourselves running out of space in UTF-16. Meh. Aug 21, 2011 at 15:57
  • 3
    The fundamental issue is that text is deceptively hard. No approach to representing that information in a digital way can be uncomplicated. It's the same reason that dates are hard, calendars are hard, time is hard, personal names are hard, postal addresses are hard: whenever digital machines intersect with human cultural constructs, complexity erupts. It’s a fact of life. Humans do not function on digital logic. May 7, 2012 at 1:16

Not the answer you're looking for? Browse other questions tagged or ask your own question.