7 ms·
Actually, the "batteries included" school of library design was a 20th century idea; the trend in the 21st century in all other ecosystems very much goes in the
by codeflo 5y ago
Actually, the "batteries included" school of library design was a 20th century idea; the trend in the 21st century in all other ecosystems very much goes in the opposite direction: fewer features in the stdlib to allow faster iteration, and strong package managers that make it seemless to mix and match packages.
Go just dodges that trend and does the 20th century thing, as it does for many other design decisions. Just as it has common data structures as hardcoded language features, instead of the ability to build them as abstractions.
To be clear: One can take the position that the trends go in the wrong direction and Go is right to reverse them -- that's a matter of opinion. I just don't think it's fair to argue Go is the language that does the more modern thing.
- wakeupcall 5y agoHard disagree. The main reason I've wrote so much python in the last 10 years is due to it's stdlib being comprehensive enough to do 95% of the tasks I need without adding any dependency. This despite the fact that I never was super-fond of python's syntax and ideology, although I just learned to accept it. I was writing a ton of perl before that, and with python I could do more with less "CPAN". I would have _never_ made the switch without. A good stdlib ensures decent performance, stability and overall code quality to your project. Without that, you need tons of dependencies along with version pinning (as developers nowdays understand semver even less than 20 years ago) and duplication due to your dependencies picking different packages as their own base due to the lacking stdlib. I hate the sort of ecosystem which is built around this pattern. See npm for one extreme, although I see cargo not too far away in the horizon.
- hiptobecubic 5y agoOk but you didn't contest anything in their argument as far as I can tell.
- cies 5y ago> A good stdlib ensures decent performance, stability and overall code quality to your project. How then? I can give counter examples of the opposite easily: An extensive stdlib ensures decent performance: https://stackoverflow.com/questions/31548680/why-is-python-3-is-considerably-slower-than-python-2 https://stackoverflow.com/questions/31548680/why-is-python-3... An extensive stdlib ensures stability: i'm not even sure how, with good version pinning it should always work, regardless of the it being std lib or otherwise. An extensive stdlib ensures overall code quality to your project. This one I agree most with, but because the std lib sets the idiomatic writing style of the project. I'm not how important the size of the std is for this to work.
- progval 5y ago> An extensive stdlib ensures decent performance: https://stackoverflow.com/questions/31548680/why-is-python-3-is-considerably-slower-than-python-2 https://stackoverflow.com/questions/31548680/why-is-python-3... This example is about a language issue, not the stdlib. And it's only slower on purely computational code, which Python is known to be bad at anyway, as a tradeoff to avoid overflow issues. > An extensive stdlib ensures stability: i'm not even sure how, with good version pinning it should always work, regardless of the it being std lib or otherwise. Version pinning is a bad practice because it slows deployment of security updates. It also only works for end applications, as libraries cannot reasonably pin their own dependencies.
- cies 5y agoIn rust an int is an int, in Python this changes with versions. Std lib needs to change along. > Version pinning is a bad practice because it slows deployment of security updates. How is that not true for stdlibs? > It also only works for end applications, as libraries cannot reasonably pin their own dependencies. Really?
- codeflo 5y ago>> It also only works for end applications, as libraries cannot reasonably pin their own dependencies. > Really? At least not usefully if types from those dependencies appear on the API surface.
- progval 5y ago> In rust an int is an int And Rust ints can overflow. It's a tradeoff. >> Version pinning is a bad practice because it slows deployment of security updates. > How is that not true for stdlibs? Because, if without pinning, the package manager always gets the latest available version and installs it for all applications on the system once and for all. When pinning dependencies, system administrators need to wait for every single application to update its pin.
- 5y ago
- duped 5y agoI think this mindset is exactly what Rust's stdlib encapsulates, where the differentiator comes is "scope." As an example, most of STD (the stuff outside core) makes the assumption that a nonfallible allocator exists. This is an entirely reasonable assumption for any high level programming language... yet it's one of the biggest complaints about Rust's standard library from systems programmers. And so a not-insignificant amount of (mostly volunteer) developer time has been spent modifying very basic data structures and APIs to support the (not so niche) use case of fallible and pluggable allocators. If you're working on a stdlib where the question, "what if my allocator doesn't work" is meaningful, it's not a big jump to much more complex questions about how to implement "standard" features in other languages that simply don't have the same concerns as a systems language like Rust - making it much more reasonable to shove off the responsibility of implementing those features in libraries out in the ecosystem. And I think that's wholly in line with the space that Rust occupies, which is next to C++ (which also has a lacking stdlib for "standard" features), but at least has a good enough package manager to deal with it.
- mlindner 5y agoJust try to do anything that involves any kind of heavy calculation with Python and tell me it has "decent performance". If you write such code in pure python it can easily be up to 1000x slower than a compiled language or using dedicated libraries that link C/C++/Rust libraries to Python. This is why you need to immediately reach for numpy and similar libraries that aren't part of the standard library.
- p7g 5y agoThis discussion is about the standard library, not the language runtime. Decent performance here is meant relative to the performance of the language. In this case it could mean algorithmic complexity, for example.
- wheelerof4te 5y agoSoftware does not always require "heavy calculations". That is the case in majority of applications today. You would be surprised as to what can be made in Python using stdlib only. Ironically, Python makes the best desktop calculator. Go figure.
- rob74 5y ago"All other ecosystems"? Not sure about that - besides Python, which another commenter mentioned, there is also PHP, which is pretty much 21st century and also "batteries included". I totally get it that small teams developing a language (Node, Rust) need to focus their efforts, but please don't try to spin this limitation into a "new way of doing things". What I hate most about this "package manager"-based way is not only having to choose between a multitude of options, each with its own pros and cons, for basic functionality, but also the burden of keeping everything safe and up to date (while making sure it's still working), and the constant threat of having to switch to another package/crate if the one you have decided to use is abandoned.
- dhosek 5y agoThe batteries included aspect of PHP is very 1990s. It's the thing I always disliked the most about PHP in that so much of the functionality required PHP to be built with all kinds of stuff compiled in and in shared hosting environments you would be at the mercy of however the admins built their PHP (not to mention having to deal with the overhead of having loads of code that you might not want in your system). Maybe it's gotten better since I was writing PHP code 14 years ago, but ugh.
- stonemetal12 5y agoTalking about centuries in programming is pretty silly. A large number of popular languages (Java, C#, Python, PHP) of a certain age went down the batteries included route. All of them have "dead batteries" in their standard libraries that can't be removed because of backwards compatibility. At this point more of Java's standard library shouldn't be used than should. Java literally has multiple UI implementations in the standard lib and none of them are the recommended method of UI development in Java. As far as I am concerned the only thing worse than having to use a package manager to make choices, is having to use the package manager to make choices to replace the dead ends codified in the standard library.
- rictic 5y ago<non-judgmental> PHP and Python were both released in the 90s
- sigmonsays 5y agoDisagree. The go stdlib has the compatibility promise. Managing ANY external dependencies is exactly what causes breaking changes to be introduced over time. Think of it as a long term support plan on all your packages. python had a HUGE stdlib, which was its downfall. Go's stdlib is quite small in comparison. I'd say the kitchen-sink batteries included is the 20th centry idea, Not the approach go has taken.
- Macha 5y agoAs a counterpoint, we can look at the npm ecosystem for the disadvantages of a "just use small packages from the ecosystem" approach. Look how many dependencies a typical npm package has, how many different authors there are, and what happens when one of them goes off the deep end?
- throwaway894345 5y agoI don’t think this is right? C, C++, and JavaScript certainly had very spartan standard libraries. Python and Java certainly emerged in the mid 90s (within striking distance of the 21st century), but I’m not sure the state of their standard libraries at the time. I suspect other languages also had smaller libraries but can’t prove it. With respect to mainstream 21st century programming languages, I’m only familiar with Go, Rust, and C#, of which C# and Go certainly have pretty comprehensive standard libraries. Other mainstream 21st century languages I can think of run atop either JVM or .Net and I believe they have access to the Java or C# standard libraries, respectively but I’m not sure if it would be fair to say they inherit those standard libraries or not.
- codeflo 5y agoI'm not sure those are counterexamples. The discussion is about large standard libraries vs. package managers. C and C++ are even older languages that had neither. Back then, the idea of having a large abstraction layer between the language and the OS wasn't even thinkable -- that idea didn't really appear before the 90s. If you don't know the size of Java's standard library in the 90s, it's maybe risky to imply that it must have been small. :) Kidding a bit. But to give a hint, it included two different incompatible GUI frameworks by 1998. JavaScript is from the 90s, but wasn't a standalone programming language until Node.js, which was released in 2009. C# is the newest non-Go language you mention with a large standard library. It was released in 2000 (so in the 20th century if we're being pedantic), and even it has moved a lot of stuff into Nuget packages that used to be built in. For example, the entirety of ASP.net.
- pjmlp 5y agoThe idea was surely thinkable, just not for C, whose UNIX was basically its standard library. Hence why everyone kind of expects POSIX to compensate for the anemic ISO C. While ISO C++98 was built on the same anemic principle, due to its relation to C and UNIX, all major C++ compilers had rich frameworks, which unfortunately WG21 ignored.
- 5y ago
- chrismorgan 5y agoGo has a much easier time of it for including some batteries, because it’s a simpler language. Take HTTP, for example: the decision of the data type to use for storing headers is easy, because there are really only four possibilities, two binary decisions to make: ① do you use string or []byte; and ② do you use map[T][]T, or join values with commas and special-case that pesky Set-Cookie header somewhere and use map[T]T? And so map[string][]string was fairly obviously the best choice from the start, and I think still is—in Go. Meanwhile, in Rust, are you going to go Vec<(Vec<u8>, Vec<u8>)>, can you get away with HashMap<String, Vec<String>>, do you store a central buffer and work with slices for fewer allocations, or do you say “no, that’s stupid, headers aren’t strings, they’re just serialised as strings” and go all fancy typey in one of a variety of ways, some the most efficient of which depended on GATs which are only recently stable? Go could have net/http from the start. I don’t know if there’s something better now (I don’t use Go), but I expect that the better would still be very similar in API. If Rust had had a std::net::http at 1.0, it would certainly have been deprecated by now. Probably even over four years ago. (Disclosure: I wrote the first de facto standard HTTP library in Rust, rust-http, back in 2013. Then in 2014, realising its design was a dead end, I went to write a new one from scratch, Teepee, but never finished it because of decision paralysis, others took up much of my work and finished the concept off in Hyper, and I’m glad I got out of the critical path and I’m glad they took it up.)
- xigoi 5y agoThen you go “Can you multiply a duration with a number? No, that wôuld be stupid. Can you multiply a duration with a duration? Heck yeah!” Such an intelligent type system.
- chrismorgan 5y agoHmm? std::time::Duration doesn’t implement Mul<Duration>, and does implement Mul<u32>, and has methods mul_f32 and mul_f64. So you can multiply a duration with a number; and you can’t multiply a duration with a duration because that would be stupid.
- 5y ago
- jcranmer 5y agoI think it's worth expanding this a little more. The problem with standard libraries in general is that it's not really possible to adjust the API later if it turns out to not be well-designed. And it turns out that "oops, we got the API wrong" afflicts, well, literally every standard library I've ever worked with (note: this even does include Rust, as young as it is). Examples include: * C/C++: wide strings, locale support, std::unordered_map (it prevents you from using a good hashtable implementation) * Python: mail parsing libraries, http requests [and this even after having an exceptionally painful major version that allowed them to break compatibility!] * Java: java.util.Date, java.util.Vector [as opposed to java.util.ArrayList] * Rust: raw FD support, std::io::Read interactions with partially-uninitialized buffers There is something you notice when you look at standard library misfeatures, which is there are different kinds of issues. The simplest issue is something like locale support in C/C++: you can just simply not use it, and everything will be fine. On the other hand--and this afflicts Python the most of any language I'm familiar with--having a broken implementation in stdlib can dissuade the community from making a good version of what you want (this is what happens with the mail format stuff). The worst possible kind, though, is when you make a core type with an utterly broken API--and this is what java.util.Date qualifies as. Having "batteries included" makes it more likely you get more severe kinds of API failures in the standard library. Already, the Rust ecosystem has had evolution in core package libraries that allowed it to absorb poor API design--consider the shift from error-chain to thiserror/anyhow, or the futures 0.1->0.3 change.
- tptacek 5y agoBut the comparison here is between the organization of the Rust library ecosystem and Go's; the Go standard library has, I think, more (and more ambitious) strongly-accepted abstractions --- it's uncontroversial to observe that Rust programs pull in more deps than Go packages pull in modules. But the phenomenon you refer to in your last 2 paragraphs hasn't really occurred with Go; it's hard to point to something in the stdlib that Go just straight-up botched, to the detriment of all other packages. Go programs pull in deps, of course, but it's unusual bordering on unidiomatic to pull in a dep that changes the general programming environment (idiomatic Go sticks with the data structures and, notably, concurrency primitives in the stdlib, net/http remains the de facto standard HTTP interface, things tend to build on top of database/sql instead of replacing it, for the most part the stuff in encoding/* is canon, &c). That's not a plus for Go, but it's a contrast with Rust, where crates routinely redefine or refine the underlying Rust programming environment (best example is anyhow, of course). So Go programs rely heavily on the stdlib and its abstractions. And my perception is that by and large Go devs are pretty happy with it? Maybe DNS would qualify as such a botch; maybe the interaction between sockets and contexts as well. And we'll see what chaos erupts from 1.18 generics. (None of this should be construed as in any way a dig on Rust, which I find frustrating but also enjoyable to work in, and whose expressiveness and utility advantages over Go I respect).