this one one of those things that people point to when comparing languages, but in reality rarely matters. with Go, you just get the number of bytes, which the the correct default thing to do:
if the language default was anything other than this, THAT WOULD BE WRONG and unexpected. I would prefer the default to be the dumb, fast thing. then if I want the slow, fancy thing, I can import some first or third party package.
I think to some extent it depends on the language. In the article they talk about Swift's implementation, which by default does the slow, fancy thing (but makes it easy to do the dumb, fast thing). String manipulation in Swift is almost certainly going to be used for a GUI for end users of many possible languages / locales, so it makes sense to spend the extra cycles to get the fancy version by default. If it isn't the default then you'll end up with half the apps on the App Store displaying broken text on line breaks, ellipses, wrapping, etc. on their hand-rolled UI stack.
For anyone wondering what Go does, it looks like Python2's way[1]; strings are byte sequences with no guarantees of UTF{anything} correctness. Go's source code is specified to be UTF8 so string literals in source code will become valid UTF8 encoded strings, but any string from any library call or code you didn't write might contain invalid Unicode text, or mixed encodings, or anything.
That feels a bit "pit of despair" design[2], the default thing is unhelpful and doing more than that requires the programmer to climb up out of it.
The sad thing is returning unicode code points is probably not going properly do what you wanted to do either... sliding down the slippery slope, you'd end up needing a text layout renderer and a language model to do what you thought you wanted to do. (and then there'll be a thousand bugs and edge cases that your libraries didn't handle properly)
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 than five. But since we ask for an exact count that hint is unused, the actual decoding will take place.
Yes, your point? That is the same thing which happens in Swift if you request the length of a string and it gives you the number of glyphs (1, in this case).
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.
Asking str.len() is a single very cheap operation, it's not only O(1) in the sense you'd learn in an algorithms course, it's really actually very cheap to do, it's fine if an algorithm relies heavily on str.len()
In contrast chars().count() creates an iterator and runs the iterator to completion counting steps, that's O(N) for a string of length N, and is in practice very expensive, you should definitely cache this value if you will need it repeatedly. It is possible the compiler can see what you're doing and cache it, but I am very far from certain so you should do so explicitly.
This is important in contrast to say, C, where strlen(str) is O(N) because it doesn't have fat pointers and so it has no idea how long the string is in any sense.
Yeah but unfortunately it provides `.len()` directly. It's documented to make clear that it's the bytecount and not the characters, and that humans usually work with characters, but given that this isn't even a trait implementation I think `.as_bytes().len()` or something would have been better.
This is only if you want strings to be sequences of bytes. If you want strings to be sequences of code points, it is more sensible to define string length as the length of the sequence. I prefer the latter (for coded text) because it is closer to the meaning of the string. Sequence of code points is always sequence of code points, but a sequence of bytes may not correctly encode a sequence of code points, and bytes in encoding are not in one-to-one correspondence with code points in string. So I see no reason to care about individual bytes per se in the string's code.
Because whenever you want to store or transmit a string only the byte count matters (the size of the string). All the fancy unicode stuff on top of bytes is for the display layers to handle. The default should be grounded to the reality of the programmer.
Storing and transmitting is always going to work with low-level storage units like bytes, so your string will need to be converted to that first. But string manipulation is extremely common in programming, and I would think graphemes are the most useful unit here - i.e. as a programmer my preference would be for swift's behaviour.
Human interaction is a more grounded reality for programmers vs. the dumb land of pure bytes, so even at that conceptual level the default should be smart
And bytes is the only thing that matter for a specific type of string, conveniently named, sequence of bytes
https://godocs.io/builtin#len
if the language default was anything other than this, THAT WOULD BE WRONG and unexpected. I would prefer the default to be the dumb, fast thing. then if I want the slow, fancy thing, I can import some first or third party package.