5 ms·
It's more than that though. There is just no standard library to be spoken of. I mean things like the most basic string processing methods, etc., are left to th
by sam0x17 4y ago
It's more than that though. There is just no standard library to be spoken of. I mean things like the most basic string processing methods, etc., are left to the programmer to sort out themself. Every time I've done contracting work on Go projects, I'm shocked by the things I have to implement from scratch (not that it isn't fun) that we take for granted in every other modern compiled languge I've tried (Rust, Crystal, Nim). I know this is more of an environment thing than a language thing, but in practice, language and environment are so intertwined it's pointless to not consider them together.
- gabereiser 4y agoThis isn’t true. Go has a basic standard package list. https://pkg.go.dev/std https://pkg.go.dev/std
- sam0x17 4y agoYes, and it's missing tons of things we take for granted in other langauges. If you look at the "strings" section it's so short. There aren't even convenience things like string reverse.
- benhoyt 4y agoOdd, I find the standard library very full-fledged and useful, including the strings package. I've almost never needed to reverse a string, except in interviews. :-) The stdlib has a full (and good) HTTP server with HTTP/2 and TLS support, HTML templating, excellent I/O support, compression, even image encoding/decoding and drawing. That said, the container types are pretty sparse, but that may change a bit now that generics are here. What, apart from string reverse, do you miss for real projects?
- sam0x17 4y agoThe fact that it's a bunch of top level functions also makes me think of PHP from the early 00s, only I was able to do more with things then tbh. Just feels super archaic.
- sam0x17 4y agoThe main thing that irked me though is I had to spend a whole day doing a simple "take this complex object and use it as a hash key" in an idiomatic way other than just cheating and using the stringified version of the object as the key.
- TheDong 4y agoNot that person, but I'll call out a few issues I've had with the go stdlib: First, it has a lot of useless packages you typically wouldn't use, like "log" and "flag" (which work, but are way worse than third party alternatives like logrus and pflag), but also like "syscall" (as it says 'deprecated, use 'golang.org/x/sys' instead), "image/draw" (nope, you wanted 'golang.org/x/image/draw' usually), "path" for working with paths (you wanted "filepath"), "net/rpc" and "rpc/jsonrpc", "plugin" (almost always a bad idea), a chunk of "strings" (use "golang.org/x/text" for proper unicode support) and so on. Some of those are marked deprecated, most of them are not, and are just waiting for someone to accidentally use them. That's issues I have with the stdlib and not stuff I'm missing though... Though I guess I really do miss a good logging library, or at least interface for external packages to implement so I can plug in logging libraries without rewriting the world. One thing I do find missing frequently is a reasonable set type with the ability to do things like basic set operations (intersect, diff, etc). I constantly have to write ad-hoc for loops in go to do set operations, and it's verbose, non-obvious what the code does, and easy to get wrong. But honestly, the main thing I'm missing isn't actually a package, but more about error handling for the stdlib as a whole, which is more a language issue. I really wish I could know what possible errors stdlib functions returned without, fairly often, having to read huge chunks of stdlib code to determine that. Perhaps 40% of the stdlib documents the error type it returns in a message (like 'os.Chdir' always returns '*os.PathError'), but for the rest, good luck. Want to figure out what errors you might have to check for 'tar.Writer.Close()'? Well, the docs says "returns an error", the interface is "error", you have to read hundreds of lines of code to figure out the possible concrete types it could be. Maybe 15% of the time, you end up having to string-match on error messages because the error var or type is unexported.
- morelisp 4y ago> interface for external packages to implement so I can plug in logging libraries without rewriting the world. Well, it's structural, so you don't need other packages to implement an interface rather you need them to accept an interface. That also makes it clear it's a bigger ask - you're not asking a dependency "please also do X" but instead asking "please never need to more than Y". > Want to figure out what errors you might have to check for 'tar.Writer.Close()'? Well, the docs says "returns an error", the interface is "error", you have to read hundreds of lines of code to figure out the possible concrete types it could be. The concrete types it could be are unbounded, because `tar.Writer` wraps arbitrary `io.Writer`s. If you need multi-pathed error handling (usually people don't and are just making it out of habit!), worry about what things can do, not what they are.
- morelisp 4y agoWhy do you want a string reverse? - Do you want to reverse bytes, or codepoints? - Do you want to reveres codepoints, or grapheme clusters? - Do you really want to reverse grapheme clusters, or do you want to reverse some grapheme clusters while leaving e.g. sequences of control characters in the same order? - Do you really want to reify any of this rather than iterate backwards in the existing memory?
- pwinnski 4y agoI think most people are expecting something along these lines: C++: reverse(str.begin(), str.end()); Dart: str.split('').reversed.join(); Java: new StringBuilder().append(str).reverse().toString(); JavaScript: str.split('').reverse().join(''); PHP: strrev($str) Python: ".join(reversed(str)) Rust: str.chars().rev().collect()
- morelisp 4y agoYes but why? Those expressions do wildly different things both in terms of language semantics and in terms of observable behavior and most of them haul in some heavy additional machinery from the language. Perhaps where it is present, this is a case where stdlibs have implemented it because it's easy to implement, and not because it's actually useful. (What do I mean by wildly different things? C++: Swaps the string's contents in-place, and probably breaks any multi-byte code units unless you've got a parameterized std::string at hand. Dart: Makes a new string but has to round-trip via an array, because... it doesn't have a string reverse? This seems like a really bad argument for your side! Java: Reverses codepoints, but the fact you have to round-trip through a StringBuilder to handle this is also telling. JavaScript: Same comments as Dart, but I believe this is broken, it will reverse surrogate pairs incorrectly. PHP: Good luck figuring out what this does depending on your platform, locale, and moon phase. Python: Another codepoint reverse, again not via strings but a lazy sequence, and also not even idiomatic - use `str[::-1]`. Rust: And finally again... not a string reverse. You want a Go slice reverse? You can get a perfect one post-generics.)
- yencabulator 4y ago
- sam0x17 4y agoAnother big area that is lacking is Go makes it so hard if you want to use something other than a primitive as a hash key (Rust is guilty of this as well, mind you). This is something that should come out of the box in any modern language in my opinion.
- yencabulator 4y agoThe map key type can be anything for which `==` is defined. This includes structs for which `==` is defined for every field. Composite keys etc are trivial. https://go.dev/ref/spec#Map_types https://go.dev/ref/spec#Map_types
- the_duke 4y ago> Rust is guilty of this as well, mind you #[derive(Hash)] struct X{ ... } Seems easy enough to me? The only annoyance is if a third party type didn't implement Hash, but you can solve that with a manual implementation instead of a derive.
- stonewareslord 4y ago> you can solve that with a manual implementation instead of a derive. How? I thought the orphan rule said you can only define trait implantations at struct definition or trait definition
- sam0x17 4y agoding ding ding! This has been a problem for me a number of times. The quick workaround is pray that it implements Debug and in a reasonable way and take the hash of the string instead
- the_duke 4y agoYeah, for foreign types you will have to use the "newtype" pattern, aka: define your own wrapper struct.
- genthor 4y agoMaybe I misunderstood you, but you can use structs as keys of a map.