upvote
Note that many Rust libraries consist of multiple crates, which all end up in the dependency graph. This makes the number of dependencies seem higher than it actually is: the separate crates have the same maintainers and are often part of the same upstream git repo.

I agree with the general sentiment though. Rust also has a lot of crates that are stuck semi-unmaintained at some 0.x version, often with no better alternative.

reply
Unfortunately the 0.x version has pervaded because of community cargo culting claiming that versioning is easier with 0.x than with major version numbers > 0. Personally I find that hard to believe, especially given packages like Tokio and anyhow (still at v1) make it work and there’s others that are >v1.

That is to say 0.x doesn’t necessarily mean unmaintained, it can also mean “I don’t want to have to think about how to version APIs / make guarantees about APIs). Eg reqwest is very widely used and actively maintained yet is still at v0.13.

reply
> claiming that versioning is easier with 0.x than with major version numbers > 0

I think it's less that versioning is claimed to be easier with 0.x versions, and more that some people have got into their heads that 1.0 signals either "permanently stable" or "no new versions for several years" and they don't want to commit to that yet.

I do wish more crates would 1.0 (and then 2.0, etc).

reply
There is good reasons to break out projects into multiple crates. It makes reusing functionality elsewhere easier. It makes it easier to reason about behavior. It makes it easier for LLMs to understand (either working within the crate or consuming as an api surface.) So you end up with projects that have multiple crates inside the same workspace and it really blows up dependency count.
reply
The other very important reason for splitting into crates is compile times. Crates are the "compilation unit" and you often get more build paralellism with more crates.
reply
> rusqlite (sqlite), clap (cli), ratatui (tui), and tauri (gui)

Does any language, except like Java, exist with a standard library comprising matching that?

Also, keep in mind that Tauri itself is 14 crates, where each one shows up in your build tree.

https://github.com/tauri-apps/tauri/blob/dev/Cargo.toml

And Ratatui is 6:

https://github.com/ratatui/ratatui/blob/main/Cargo.toml

reply
reply
And ironically with the exception of the python sqlite3 module, the rust alternatives are much higher quality, IMO.

Does anyone even use tkinter in modern times anyways?

reply
I wouldn't start a company behind it but tkinter is perfectly fine for basic guis. It has its quirks but who doesn't?
reply
Right. The famous stdlib where once good libraries go to die so you instead depend on the latest community replacement choice.

Also argparse for Clap:

https://docs.python.org/3/library/argparse.html

reply
To highlight the problem for Python: Python's standard library has getopt, optparse, and now argparse. I don't think they set out to offer 3 argument parsing libs, one of which is marked superseded, but here we are.
reply
At least in the case of sqlite, rusqlite pulled in 5 or so in total whereas Go had a single library that was a thin wrapper around sqlite, and integrated into the stdlib interface. Many fewer deps

Edit: counts are fair, that’s still hundreds unaccounted

reply
Package management is the bane of nearly every language/technology

Nobody has "solved" it, and I don't think that there will ever be one (never say never, though, right?)

For Go we rely on developers of libraries to adhere to the semver versioning scheme accurately, and we cannot "pin" versions (a personal bugbear of mine)

There is a couple of workarounds - using SHAs not unlike the git commit hash to provide a pseudo version, and, vendoring (which is a cache of known dependencies - which brings with it cache management problems)

I had the misfortune of having to use Python with a virtual env on the weekend - it did not end well, and reminded me why I migrated away from Python.

Look at Perl (cpan) Java (maven, gradle) Ruby (gems) Go (dep, glide, vgo, modules) Rust (cargo) Node (npm, yarn, etc)

OSes too Redhat (yum, rpm, etc) Debian (apt) Ubuntu (snap - god why????)

And so on

reply
> I had the misfortune of having to use Python with a virtual env on the weekend - it did not end well, and reminded me why I migrated away from Python.

I see this sentiment a lot, and it doesn't match my experience at all.

In my decade-old bubble of using Python professionally, I've never had an issue with virtualenvs. The few issues I might've had with dependency resolution must be so far in the past that I don't remember. But that's not strictly about virtualenvs. Likewise, pip could be clunky, but we don't have to deal with it anymore.

My niche is mostly backend. Other Python niches must be considerably worse in this regard.

reply
I used Python for a decade (professionally), gave up on it once I started using Go (professionally) in earnest - about 8 or 9 years ago.

I never liked virtual envs, having to remember where they were, what their names were, and what was installed into each one was a pain point for me.

This weekend I was trying to learn some AWS stuffs, and I cloned the official repo of example code which was Python. I followed the directions exactly and ... boom Python versioning issues... inside the freaking venv

Who needs that?

Why do I need to spend the better part of a couple of hours debugging a versioning problem? (FTR The problem turned out to be the repo was hardcoded to 3.8 and my local Python was 3.9.. or something along those lines - you are welcome to correct me, but that's what I remember of a painful waste of my time)

With Go I have backward compatibility guarantees - usually (there have been instances in the past where the backward guarantee have been broken AND the build process got broken hard for modules, with the claim that it was external and therefore not subject to the same guarantees)

> I see this sentiment a lot, and it doesn't match my experience at all.

My old HCI professor used to tell me - if users are complaining (or producing workarounds like post-it notes on their monitors) - regardless of how clean or elegant you think the system is - it's not.

You're saying you see people complain about it a lot - therefore it's a genuine problem.

reply
Actually with Go modules you are always pinning dependencies. What’s in your go.mod is what is used. If your go.mod needs to be updated because a dependency wants to bring in a newer version of a transient dependency, the go.mod has to be modified (by the go command, not by you)
reply
I don't think you understand the term "pinning"

go mod tidy will update your go modules whenever it feels it needs to and there's nothing you can do to stop it.

The workaround is vendoring, where you control the versions in a cache.

reply
> we cannot "pin" versions

you can? that's why go.sum exists. you can also use the replace directive for more advanced scenarios.

reply
Nix solved it. Languages could choose to adopt Nix as their packaging system.
reply
It did and didn't. Nix tools for building language-specific packages almost always wrap the language build tool/package manager. This can be easy or hard, depending on how onerous the build tool is for vendoring libraries.

What Nix and build tools need to agree on is a specification or protocol for "building a software dependency tree". Like, I should be able to say 'builder = cargo' in a Nix derivation and Cargo should be able to pick up everything it needs from the build environment. Alas, there is simply far too much tied up in nixpkg's stdenv for this to be viable, so we have magic stdenv builder behavior via hooks when a build tool is included in nativeBuildInputs.

reply
Thanks for writing this, I learned something
reply
I think one of the key problems too is that a system level dependency is managed by people dedicated to ensuring the chaotic nature of the package they are responsible for conforms to the way the OS they are maintaining for has proscribed.

There's no real way to do that at a language level - we cannot have "Go has determined the package you are trying to fix has not met the versioning requirements proscribed so you cannot submit the patch to fix it"

What language dependencies do is what OSes would think of as "unofficial versioning" that is, an OS will let you install and run an unofficial version of some lib (we've all been there, right, multiple versions of some core library because one doesn't work with whatever you are trying to install), but they will not manage it at all.

reply
In theory, but not in practice
reply
The stdlib is the place where good ideas go to die.

And then you have httplib3 followed by httplib4.

In other words: I highly prefer the Rust approach.

It doesn't matter a lot whether I rely on the stdlib or another dependency to me.

It's a dependency after all.

People think just because it's the stdlib it's somehow better quality or better maintained, but these are orthogonal concepts.

In the end it depends solely on resources.

Sure, the stdlib may get more of these, but it may also grow fat and unmaintainable...

reply
That's an interesting viewpoint, but one I've noticed is less prevalent in other languages.

The c# guys at microsoft created an enormous stdlib, and the overwhelming majority of it is pretty good. The outliers being of course older stuff they've never really had time to upgrade. And they don't seem to be afraid to deprecate stuff, every major version brings a couple of minor breaking changes. But it all seems to work out just fine somehow

reply
C# massive standard library and first party libraries means much, much fewer external dependencies and these libraries are managed by a team of paid, professional engineers.

Highly, highly underrated.

reply
I’d argue that this is wrong. Having a conservative standard library that aims to contain most things most people need is preferable to third party libraries in 90%. For the 10% that isn’t covered to your liking by the standard library you can turn to third parties. You get both a practical standard library and third party options.

I did a lot of cryptography over the past couple of years. Go has that in the standard library. For the last decade and a half cryptography is something that every developer has to deal with at some point, and it NOT being the awful pain that it is in just about any other language, is a good thing. Sure, it does not contain every algorithm and mechanism in the world, but it contains everything you need for 90% of cases. That means that most of the time you don’t have to do the extra work of ensuring you have an out if the library you depend on should go away/bad, bugs will be fixed, people speak a common language and you don’t have to do twice the work in terms of risk assessment.

People keep forgetting that you have to evaluate these things in the real world. In practical real-world situations. The real world is not about what works in theory but what actually provides value for actual people working on actual projects.

reply
I’m not arguing on quality of the library, I’m arguing on not getting pwned by the sheer number of transitive dependencies
reply
The problem is that trust shouldn't be so binary. We should have ways to increase trust without needing to resort to the standard library. There was an effort to do this at some point in rust but the idea was sadly not well received. Maybe it'll end up reviving itself with modern supply chain concerns.

The idea is that there could form some groups of well maintained crates that only depend on each other and have a similar amount of oversight. This actually naturally happens in c++ because grabbing dependencies is so painful, but it makes dependencies more trustworthy. For instance boost, absl, folly, etc.

reply
I've harped on this for years, but few devs seem to grasp the concept that less dependencies is better than more. Especially library authors.

It's only now that the supply chain problems with npm are becoming beyond obvious that we are seeing devs come around to this notion (leftpad should have been the canary in the coal mine).

The javascript ecosystem has corrupted far too many other programming ecosystems. The notion of "just make a small package like is-even" is really the core of the problem. But also people making libraries often have the wrong mentality about that process. They think of it like they are making an application (So why not just pull in a bunch of random deps). Every dependency a library brings in should have a serious conversation and analysis on "how much work would it be to just do this functionality here". And if it's not that much, then preference should be to duplicate, not depend.

reply
A lot of libraries should have been gists, blog posts, or stack-overflow answers. When I see a library imports a dependency of a few function related to its domain, I can’t help but wonder why they don’t want to take responsibility for that small snippet of code.
reply
If you look at the number of authors vs the number of dependencies the gap narrows but doesn't disappear. Many of the most commonly used crates are written by members of the rust foundation amd are used in the tools themselves. But it is always a concern. I'm looking forward to the upcoming option to forbid versions newer than N days at the project level. But just manually only y updating versions when you need a new feature or there is a cve works pretty well.
reply
deleted
reply
The stdlib isn't necessarily better, but it's always there. To use Python as an example, I tend to prefer requests to urllib2, as do most programmers. But I've absolutely been in scenarios where all I could get was the stdlib, and having urllib2 saved my ass. I think it's extremely important for the stdlib to be batteries included, even if they aren't the best versions of those batteries on the market.
reply
Interesting. I'm not very familiar with Go. What is the equivalent for Tauri in Go's stdlib?

Would it make sense to continue using Go for the frontend and doing only the backend in Rust for your user case?

reply
Go's stdlib has none of the things GP listed. No sqlite3, no ratatui, no cli (though there is `flag` if it's enough for you), and no tauri equivalent in its stdlib. Those would be go-sqlite3, bubbletea, cli or cobra, and wails.

Charitably, I think OP meant to say that in the rust project only four dependencies were added and that caused 400 transitive dependencies to be pulled. Adding the four Go equivalent will still result in 10x less packages being pulled.

It's a culture problem, Go authors prefer solutions that are self contained, rust authors embrace the culture that gave us left-pad.

But, at least in GP's case, it's not a stdlib problem. Not one solved by Go, anyway.

reply
wails, there's wails3-alpha which some people said is even better than tauri
reply
Thanks. Is wails a Go stdlib component, as GP implied or is it third party?
reply
tauri isn't stdlib and neither is wails
reply
Why is it worse to import a number of other packages that provide exactly the functionality you need, than to have a large standard library that provides some but not all of the functionality you need, requiring you to still use some large dependencies?
reply
For example, security. See all the supply chain attacks from the past couple of years.
reply