I always felt like NUL-termination, newline-separation, and (eventually) UTF-8 were all sort of complementary ideas: they all take as an axiom that strings are fundamentally streams, not random-access buffers; and they all separate the space of single-byte coding units, by simple one-bitwise-instruction-differentiable means, into multiple lexical token types.<p>Taking all three together, you end up with the conception of a &quot;string&quot; as a serialized bitstring encoding a sequence of four <i>lexical</i> types: a NUL type (like the EOF &quot;character&quot; in a STL stream), an ASCII control-code type (or a set of individual control codes as types, if you like), a set of UTF-8 &quot;beginning of rune&quot; types for each possible rune length, a &quot;byte continuing rune&quot; type, and an ASCII-printable type. (You then feed this stream into another lexer to put the rune-segment-tokens together into rune-tokens.)<p>In the end, it&#x27;s not a surprise that all of these components were effectively from a single coherent design, thought up by Ken Thompson. It&#x27;s a bit annoying that each part ended up introduced as part of a separate project, though: NULs with Unix, gets() with C, and runes with Plan 9.<p>One of the pleasant things about Go&#x27;s string support, I think, it that was an opportunity for Ken to express the entirety of his string semantics as a single ADT type. That part of the compiler is quite lovely.