Hacker News new | ask | show | jobs
by techsystems 280 days ago
> ndarray = "0.16.1" rand = "0.9.0" rand_distr = "0.5.0"

Looking good!

3 comments

I was slightly curious: cargo tree llm v0.1.0 (RustGPT) ├── ndarray v0.16.1 │ ├── matrixmultiply v0.3.9 │ │ └── rawpointer v0.2.1 │ │ [build-dependencies] │ │ └── autocfg v1.4.0 │ ├── num-complex v0.4.6 │ │ └── num-traits v0.2.19 │ │ └── libm v0.2.15 │ │ [build-dependencies] │ │ └── autocfg v1.4.0 │ ├── num-integer v0.1.46 │ │ └── num-traits v0.2.19 () │ ├── num-traits v0.2.19 () │ └── rawpointer v0.2.1 ├── rand v0.9.0 │ ├── rand_chacha v0.9.0 │ │ ├── ppv-lite86 v0.2.20 │ │ │ └── zerocopy v0.7.35 │ │ │ ├── byteorder v1.5.0 │ │ │ └── zerocopy-derive v0.7.35 (proc-macro) │ │ │ ├── proc-macro2 v1.0.94 │ │ │ │ └── unicode-ident v1.0.18 │ │ │ ├── quote v1.0.39 │ │ │ │ └── proc-macro2 v1.0.94 () │ │ │ └── syn v2.0.99 │ │ │ ├── proc-macro2 v1.0.94 () │ │ │ ├── quote v1.0.39 () │ │ │ └── unicode-ident v1.0.18 │ │ └── rand_core v0.9.3 │ │ └── getrandom v0.3.1 │ │ ├── cfg-if v1.0.0 │ │ └── libc v0.2.170 │ ├── rand_core v0.9.3 () │ └── zerocopy v0.8.23 └── rand_distr v0.5.1 ├── num-traits v0.2.19 () └── rand v0.9.0 ()

yep, still looks relatively good.

    cargo tree llm v0.1.0 (RustGPT)
    ├── ndarray v0.16.1
    │   ├── matrixmultiply v0.3.9
    │   │   └── rawpointer v0.2.1
    │   │       [build-dependencies]
    │   │       └── autocfg v1.4.
    │   ├── num-complex v0.4.6
    │   │   └── num-traits v0.2.19
    │   │       └── libm v0.2.15
    │   │           [build-dependencies]
    │   │           └── autocfg v1.4.0
    │   ├── num-integer v0.1.46
    │   │   └── num-traits v0.2.19 ()
    │   ├── num-traits v0.2.19 ()
    │   └── rawpointer v0.2.1
    ├── rand v0.9.0
    │   ├── rand_chacha v0.9.0
    │   │   ├── ppv-lite86 v0.2.20
    │   │   │   └── zerocopy v0.7.35
    │   │   │       ├── byteorder v1.5.0
    │   │   │       └── zerocopy-derive v0.7.35 (proc-macro)
    │   │   │           ├── proc-macro2 v1.0.94
    │   │   │           │   └── unicode-ident v1.0.18
    │   │   │           ├── quote v1.0.39
    │   │   │           │   └── proc-macro2 v1.0.94 ()
    │   │   │           └── syn v2.0.99
    │   │   │               ├── proc-macro2 v1.0.94 ()
    │   │   │               ├── quote v1.0.39 ()
    │   │   │               └── unicode-ident v1.0.18
    │   │   └── rand_core v0.9.3
    │   │       └── getrandom v0.3.1
    │   │           ├── cfg-if v1.0.0
    │   │           └── libc v0.2.170
    │   ├── rand_core v0.9.3 ()
    │   └── zerocopy v0.8.23
    └── rand_distr v0.5.1
        ├── num-traits v0.2.19 ()
        └── rand v0.9.0 ()
linking both rand-core 0.9.0 and rand-core 0.9.3 which the project could maybe avoid by just specifying 0.9 for its own dep on it
It doesn't link two versions of `rand-core`. That's not even possible with rust (you can only link two semver-incompatible versions of the same crate). And dependency specifications in Rust don't work like that - unless you explicitly override it, all dependencies are semver constraints, so "0.9.0" will happily match "0.9.3".
So there's no difference at all between "0", "0.9" and "0.9.3" in cargo.toml (Since semver says only major version numbers are breaking)? As a decently experienced Rust developer, that's deeply surprising to me.

What if devs don't do a good job of versioning and there is a real incompatibility between 0.9.3 and 0.9.4? Surely there's some way to actually require an exact version?

They are different:

    "0": ">=0.0.0, <1.0.0"
    "0.9": ">=0.9.0, <1.0.0"
    "0.9.3": ">=0.9.3, <1.0.0"
Notice how the the minimum bound changes while the upper bound is the same for all of them.

The reason for this is that unless otherwise specified, the ^ operator is used, so "0.9" is actually "^0.9", which then gets translated into the kind of range specifier I showed above.

There are other operators you can use, these are the common ones:

    (default) ^ Semver compatible, as described above
    >= Inclusive lower bound only
    < Exclusive upper bound only
    = Exact bound
Note that while an exact bound will force that exact version to be used, it still doesn't allow two semver compatible versions of a crate to exist together. For example. If cargo can't find a single version that satisfies all constraints, it will just error.

For this reason, if you are writing a library, you should in almost all cases stick to regular semver-compatible dependency specifications.

For binaries, it is more common to want exact control over versions and you don't have downstream consumers for whom your exact constraints would be a nightmare.

Note that in the output, there is rand 0.9.0, and two instances of rand_core 0.9.3. You may have thought it selected two versions because you missed the _core there.

> So there's no difference at all between "0", "0.9" and "0.9.3" in cargo.toml

No, there is a difference, in particular, they all specify different minimum bounds.

The trick is that these are using the ^ operator to match, which means that the version "0.9.3" will satisfy all of those constraints, and so Cargo will select 0.9.3 (the latest version at the time I write this comment) as the one version to satisfy all of them.

Cargo will only select multiple versions when it's not compatible, that is, if you had something like "1.0.0" and "0.9.0".

> Surely there's some way to actually require an exact version?

Yes, you'd have to use `=`, like `=0.9.3`. This is heavily discouraged because it would lead to a proliferation of duplication in dependency versions, which aren't necessarily unless you are trying to avoid some sort of specific bugfix. This is sometimes done in applications, but basically should never be done in libraries.

Sorry, I don't understand the "^ operator" in this context. Do I understand correctly that cargo will basically select the latest release that matches within a major version, so if I have two crates that specify "0.8" and "0.7.1" as dependencies then the compiler will use "0.8.n" for both? And then if I add a new dependency that specifies "0.9.5", all three crates would use "0.9.5"? Assuming I have that right, I'm quite surprised that it works in practice.
This doesn't sound right. If A depends on B and C - B and C can each bring their own versions of D, I thought?
Within a crate graph, for any given major version of a crate (eg. D v1) only a single minor version can exist. So if B depends on D v1.x, and C depends on D v2.x, then two versions of D will exist. If B depends on Dv1.2 and C depends on Dv1.3, then only Dv1.3 will exist.

I'm over-simplifying a few things here:

1. Semver has special treatment of 0.x versions. For these crates the minor version depends like the major version and the patch version behaves like the minor version. So technically you could have v0.1 and v0.2 of a crate in the same crate graph.

2. I'm assuming all dependencies are specified "the default way", ie. as just a number. When a dependency looks like "1.3", cargo actually treats this as "^1.3", ie. the version must be at least 1.3, but can be any semver compatible version (eg. 1.4). When you specify an exact dependency like "=1.3" instead, the rules above still apply (you still can't have 1.3 and 1.4 in the same crate graph) but cargo will error if no version can be found that satisfies all constraints, instead of just picking a version that's compatible with all dependents.

can does not mean must. Cargo attempts to unify (aka deduplicate) dependencies where possible, and in this case, it can find a singular version that satisfies the entire thing.
This doesn't mean anything. A project can implement things from scratch inefficiently but there might be other libraries the project can use instead of reimplementing.
is this satire or does I must know context behind this comment???
These are a few well-chosen dependencies for a serious project.

Rust projects can really go bananas on dependencies, partly because it's so easy to include them

The project only has 3 dependencies which i interpret as a sign of quality
I don't know if OP intended satire, but either way it is an absurd comment. Think about how "from scratch" this really is.