Maybe not wrong, but it's the worst option. 5 is the number of code points, and 17 is the number of bytes. Both are reasonable answers. 7 is the number of code units for utf-16. Seems like the least useful option.
It makes just as much sense as 17 (for utf8) in a JavaScript context, where charCodeAt(i) returns a utf-16 code point, and strings at least behave as though the implementation uses an array of uint16_t for the storage. Utf 16 is definitely not my favorite representation, but given that context (which the language imposes) 7 is an important number to be able to know.
It’s not wrong that "🤦🏼♂️".length == 7 (2019)
151–160 of 315 posts
Re: It’s not wrong that "🤦🏼♂️".length == 7 (2019)
#152Earlier quoted context omitted.
I agree, "length" is an ambiguous function name. It should probably not exist and instead you have functions with units in the name: .sizeBytes, .widthCharacters, .widthResAdjPixels, and so on. Back when the world was ASCII you could get away with just .length because the numbers would always be the same, but with Unicode and all of the other complications of the modern world it isn't sufficient.
length is not ambiguous at all. Its the number of elements in the array. A string in python3 is an array of unicode code points, so the length of a string is the number of unicode code points. If you want the number of bytes, you need to encode the string in a unicode format (utf8, utf16 or utf32) to get a bytes object, which is an array of bytes. Then you can get the length of that. Remember, one of the big accompli…
Re: It’s not wrong that "🤦🏼♂️".length == 7 (2019)
#153I'm not a fan of "everything you know about X is wrong" articles. Very often they try to present some little tidbit of knowledge as a revelation and mislead the reader in the process. In this case, the tidbit is: "grapheme clusters exist and they are useful". The misleading part is that the article draws a false equivalence between what the author calls "UTF-32 code units" and UTF-16 code units. UTF-32 code units are…
> UTF-16 code units, on the other hand, are an implementation detail of UTF-16. Would that it were only so. Instead, UTF-16 ruined Unicode for everyone with the abomination that is surrogates , and almost nothing that deals with UTF-16 actually asserts well-formedness, and ill-formed UTF-16 cannot be represented in UTF-8 or UTF-32. UTF-32 and UTF-8 code units are truly implementation details of their encodings, as ot…
Re: It’s not wrong that "🤦🏼♂️".length == 7 (2019)
#154Earlier quoted context omitted.
According to the article, Rust does the same thing - " ".len() == 17.
" ".chars().count() == 5 Rust gives you the freedom to specify what you mean.
I don't remember, but I think the size hint is set on the Chars iterator, so it can see it has 17 bytes of data, it knows that can't encode more than 17 Unicode scalar values, nor can it encode fewer than five. But since we ask for an exact count that hint is unused, the actual decoding will take place.
Re: It’s not wrong that "🤦🏼♂️".length == 7 (2019)
#155> Python 3’s approach is unambiguously the worst one, though. Did I miss the part where he explains this take? It's made up of 5 valid unicode code units. For a language where you're not supposed to need to know the byte size semantics, the correct length should be 5. What am I missing? The close second being 17, because length in bytes. Is another fine way to represent this data, e.g. what a successful write of some…
It is wrong that "{emoji}".length == 7 -- but it's wrong because there's no such thing as the 'length' of a string out of context. A string should be viewed as an opaque data type with views into it depending on what you're trying to do. You can have its length in the context of storage/retrieval/transmission (UTF-8 byte count), its length in the context of parsing (code points), its length in the context of editing…
1. UTF-8 byte length
2. Code point count
3. Extended grapheme cluster count
#3 makes sense for users but it doesn’t make sense for programs which often need to work at the code point level.
I expect programming language string length to obey the law:
len(a ++ b) = len(a) + len(b)
For example, if I concatenate a two strings, one containing an “e” and one containing a combining acute accent, then I expect the length to be longer than a string containing a precomposed ‘é’ character. It’s in fact useful if strings that look the same but have different code points have different lengths, because it tells you that they’re not the same (and maybe you forgot to normalize something etc).Code point length is the most useful for people who are actually writing string algorithms based upon Unicode.
UTF-8 length is useful for people who are treating strings as opaque byte sequences, but in that case they should be using a bytes/buffer object and not a string object, except in very low-level languages that don’t want to pay an encoding/decoding cost.
Extended grapheme cluster count is useful for people who are constructing certain kinds of user interfaces, where the number of characters is limited for a policy rather than memory or width reason.
i.e. when length limits are imposed by human policy, grapheme cluster count is the way to go. Length limits for memory reasons should rather be in UTF-8 bytes. If you need a limit for visual width reasons then you need to go measure the string in pixels, otherwise I’m going to put a U+FDFD in there and ruin your day.
UTF-16 length can GTFO.
Re: It’s not wrong that "🤦🏼♂️".length == 7 (2019)
#156Python 3's approach is the most correct: Unicode defines text as a sequence of code points. UTF-whatever is an implementation detail.
Treating Unicode strings as a sequence of code points is a completely valid thing to do, but is usually not what you actually care about when dealing with text. Really, are code points any less of an implementation detail?
If you have to care about the visual representation of text then you probably need to be familiar with other concepts as well.
Re: It’s not wrong that "🤦🏼♂️".length == 7 (2019)
#157Am I wrong for assuming the .length should return a length in bytes? If you want to use 32bit units, then multiply your output by 4. If you want to do Unicode string manipulation and length counting, then use specific functions for that - but the base internal .length function should just output bytes.
The most obvious use case for length is iterating over the string and indexing it. In JS (or Go, Rust, Python) indexing and iteration is not byte based. As has been said elsewhere, length depends on the context/way you use it.
You can't just "iterate over a string" because that's not a thing. You can get an iterator over the bytes in the string, with "foo".bytes() or you can get an iterator over the Unicode scalar values in the string with "foo".chars(), or you can iterate over a UTF-16 encoding of the string with "foo".encode_utf16()
You can index into Rust's strings, but you need to specify slice indexes, you can't just treat this like it's a array because that's not what it is. If you wanted a slice of bytes you can have one cheaply, it's as_bytes() which is a [u8] and you can index directly into that slice as with any array of bytes, but you can't mutate that and those aren't characters, they're just bytes.
Re: It’s not wrong that "🤦🏼♂️".length == 7 (2019)
#158Earlier quoted context omitted.
" ".chars().count() == 5 Rust gives you the freedom to specify what you mean.
Sure, however that's actually decoding the string into Unicode scalar values, and then counting them whereas the length of the string is a direct property of the string reference (it's a fat pointer [address + length]) I don't remember, but I think the size hint is set on the Chars iterator, so it can see it has 17 bytes of data, it knows that can't encode more than 17 Unicode scalar values, nor can it encode fewer t…
Rust doesn't take sides here. It exposes all the different ways you might want to calculate the "length" of a string, and lets you pick which one you mean. The non-zero-cost choices involve a multi-step specification (like `.chars().count()`), which states explicitly the calculation involved.
Re: It’s not wrong that "🤦🏼♂️".length == 7 (2019)
#159Re: It’s not wrong that "🤦🏼♂️".length == 7 (2019)
#160Earlier quoted context omitted.
>then multiply your output by 4. That is not how UTF-32 works. >but the base internal .length function should just output bytes. Do you think the length of an `int64_t[3]` array should be 3 or 24?
> Do you think the length of an `int64_t[3]` array should be 3 or 24? There should be functions to do both: sizeof(int64_t[3]) * sizeof(int64_t) for example to get bytes. In this example, the base function should do bytes, and there should be a unicode function to count it in other ways. I could be sizing to fit in a database, or send over the wire, or I might want visible space on the screen, or I might want to know…
That's not what that does, the answer to the code you wrote is 192 because you're multiplying the same size factor twice.