func main() {
v := []rune(os.Args[1])
if len(v) > 12 {
v = v[:12]
}
fmt.Println(string(v))
}
Or more in the spirit of the C example in the post: func main() {
res := make([]rune, 12)
copy(res, []rune(os.Args[1]))
fmt.Println(string(res))
}
Note that res will stay on the stack, just like C.I expect the author is trying to say something about Go that I'm not quite getting. Perhaps that it is not an expression-based language, so to make code readable you need to make use of multiple statements. That's by design, but I understand it may be unappealing if you want to program in an expression-heavy style.
I assume "Go sucks because, look, this one weird case is a bit ugly." (that is, as rhetoric, not dialectic; it is not literally claiming "one case bad" -> "Go is bad" in the logical sense.) A weird case that I've programmed many thousands of lines of Go code in but never once encountered. Taking a slice out of a string blind like that is actually a bit rare; usually in some way it turns out you actually have length information somewhere in the environment. It's hardly like "slice index out of bounds" is some sort of terrible error... it is, at least, arguable that Python is in the wrong here for being so willing to return a string generated by [0:12] that is not 12 bytes/characters in length, which seems like a reasonable assumption to make of such an operation.
Now, if we want to talk about little examples like this, let's talk about sending on something like a channel in Python, to say nothing of Python's implementation of the "go" keyword... oh, yes, I see, suddenly this is an unfair way to compare languages.
Yes, it is.
A low-level feeling when manipulating arrays (or slice), and a poor support for generic functions ( that would be math.min in this example).
import Queue; q=Queue.Queue(); q.put(1)
> to say nothing of Python's implementation of the "go" keyword...Why would Python have a go keyword? Go doesn't have the "except" keyword that Python has, not sure what the point it?
That's not true, Python 3 uses codepoint-based indexing but it will break if combining characters are involved. For instance:
> python3 test.py देवनागरीदेवनागरी
देवनागरीदेवन
because there is no precombined version of the multi-codepoint grapheme clusters so some of these 10 user-visible characters takes more than a single you end up with 8 user-visible characters rather than the expected 10.edit: the original version used the input string "ǎěǐǒǔa̐e̐i̐o̐u̐ȃȇȋȏȗ" where clusters turn out to have precomposed versions after all. Replaced it by devanāgarī repeated once (in the devanāgarī script)
import sys
import regex
print(regex.match("\X{,12}", sys.argv[1]).group())
with the regex[1] package that should be in the stdlib Any Day Now™.Ruby's unicode_utils gem has a nice implementation of the standard grapheme cluster segmentation algorithm, and Python's wrapper around ICU works quite well. Go's concept of runes is certainly an improvement, but it doesn't handle combining characters out of the box...
The good news is Unicode 8 will make them way more frequent! (alternate emoji skin colors are specified via combining characters) much as Unicode 6 made astral characters way more "in your face" (by standardising emoji in the SMP)
sub MAIN($s) { say $s.substr(0,12) }
$ perl6 test.p6 ǎěǐǒǔa̐e̐i̐o̐u̐ȃȇȋȏȗ
ǎěǐǒǔa̐e̐i̐o̐u̐ȃȇCould you retry with the input "देवनागरीदेवनागरी"?
$ perl -CADS -E'say $ARGV[0] =~ /(\X{5})/' देवनागरीदेवनागरी
देवनागरी
Length of input string is: 10 graphemes, 16 codepoints, 48 octets (UTF-8).Length of output string is: 5 graphemes, 8 codepoints, 24 octets (UTF-8).
From the strncpy docs:
"No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case, destination shall not be considered a null terminated C string (reading it as such would overflow)."
And often times I'll be memset()'ing the destination to all NULLs when doing a string copy operation. I'm not real happy with string handling in C... as if that should be surprising to anyone.
Say, is there nice, small, suitable for embedded use string library anyone would care to recommend in C? I just want a nice string type that carries around its length and storage length, handles copies properly, and has the usual utilities. I suppose I could just write one...
Why does this deserve the attention of everyone here? The author did not compare languages, he compared his aptitude with these languages, and considered broken implementations to somehow be comparable.
A more meaningful comparison would be to implement simple, efficient, working solutions to these problems and comparing them. This, as it stands, does not lead to any useful discussion.
Seems silly to pick a language based off this single, silly criteria otherwise why not JavaScript or probably other languages that can make the code even smaller?
console.log(mystring.substring(0, 12));
So it just seems arbitrary and weak in my opinion.
Honestly though, the lack of generics for that Math.min function makes me happy I'm not programming in Go.
if a > b {
// use a
} else {
// use b
}> This treats things as byte-array instead of unicode, thus for unicode test it will end up printing just 車賈滑豈.
fn main()
{
if let Some(arg) = std::env::args().nth(1)
{
println!("{}", arg.chars().take(12).collect::<String>()); // chars() iteraters over codepoints
}
} fn main() {
if let Some(arg) = std::env::args().nth(1) {
println!("{}", {
match arg.char_indices().nth(12) {
Some((idx, _)) => &arg[..idx],
None => &*arg
}
});
}
}
With the `unicode-segmentation` crate[1], you can just swap `char_indices()` with `grapheme_indices(true)`. import System.Environment (getArgs)
main = do
[str] <- getArgs
putStrLn $ take 12 str import System.Environment (getArgs)
main = putStrLn =<< take 12 . head <$> getArgs
;-) printf("(%.12s)\n", argv[1]);The low contrast ratio and bright colors on this blog are a bit hard to read. I normally switch to readability mode in safari when I encounter this, but the sites layout prevents this from working.