No. Cargo's dependency resolution would take care of that in most cases.
No. Even if Bevy re-exported wininit by mistake, you shouldn't directly depend on transitive dependencies since, at any point, Bevy developers could correct such mistake and pull the rug under your feet.
You should never take your transitive dependencies for granted. If you depend on any library, just add it to your list of dependencies.
As far as I’m aware you do have to manually pick the correct version to match a public dependency of a crate. That is, as far as the major version is concerned; but winit isn’t a post-1.0 API, so there are “relatively” frequent new major versions. (Sub-1.0 the second digit is considered “major” by cargo.)
By convention, the major version of such a dependency may only be changed by bevy if it itself changes major versions, too. Which is why a PR such as this will itself be labeled a breaking change.
So if you change your bevy dependency from – say – 0.11.* to a future 0.12.0, not only its API may have changed, but you may need to update some other dependencies, too, such as winit; and if you use their API, that usage may need to be adjusted to the new version’s in your program, too.
Strong disagree. Re-exporting the dependent crates is the only way to ensure that end-users use the proper version. I'm no familiar with the API of Bevy and don't know whether it really exposes winit in its API, but if it does, it should re-export it.
That said, as the end user you need to be sure that the re-export is intentional, otherwise it could indeed break in any update.
While choosing the same version of dependencies as Bevy would likely mean that you choose the same actual version, it's not guaranteed, and it can break on any minor update due to other crates imposing version restrictions. This means that the process is extremely manual: on every dependency update you'd have to carefully check the versions of crates that both you and they use, and pin your version to that value. If two crates enforce incompatible transitive dependency versions, you're screwed. By incompatible I mean semver-compatible but different. In that case Cargo won't allow you to satisfy both dependencies at the same time.
As a library crate, bevy will never depend on a single version such as 0.28.6. It will always be a range; it could be the range 0.28.6 .. 0.29.0 (for lack of a better notation, i.e. all x such that 0.28.6 <= x < 0.29.0).
To use a compatible winit version, your program, too, should in that example case specify any 0.28.… version. Say it specified 0.28.3 in its Cargo.toml, to make it more interesting. That too stands for the same style of range. The intersection of these ranges would still be the 0.28.6 .. 0.29.0 one. Cargo can then choose any version out of the intersection to fulfill the dependency. (It will either be the one already present in the Cargo.lock, or the latest, and the Cargo.lock can also be updated to use all the latest minor versions with cargo update).
Even though the specified versions e.g. 0.28.3 vs 0.28.6 don’t match exactly, since these are really ranges, there is overlap; and within a major version, cargo never allows any duplicates, so there always will be compatibility.
A reason for requiring something lower than bevy does not really exist though… there’s a good reason for requiring something higher though, as the minimum: you might have never tested the lower version, never checked if it already has all the API, too, that you’re using, etc… and newer is generally better anyways with minor versions.
Well, raise an issue on that crate then, not the user’s fault. The only pattern where that’s legal that I’m aware of is when two crates the belong together have one pin the exact version of the other. Otherwise, it’s going be able to lead to broken builds no matter what.
Typically their versions match, too.
foo @ 0.42.0 depends on exactlyfoo_macros_funny_helper_crate @ 0.42.0 foo @ 0.42.1 depends on exactlyfoo_macros_funny_helper_crate @ 0.42.1 foo @ 0.42.2 depends on exactlyfoo_macros_funny_helper_crate @ 0.42.2
Because it's a hard guarantee. If I depend on Bevy and its version resolves successfully, I can use the proper version of its dependencies. Anything else is a manual process of trying to get Cargo pretty please to choose a compatible version.
I don't need to pollute my own dependency list with the dependencies of dependencies, I don't need to manually track their version updates, I don't have the possibility of diamond dependency problems, I can't mess up feature selection.
The proper way is either to avoid exposing transitive dependencies entirely, by wrapping them in your API (the best but verbose solution), or to add pub extern crate winit; to your library root.
Yes. As soon as you expose some types by re-exporting them, they become part of your public API, therefore you should be careful about it because, as @steffahn mentioned above, changing a transitive dependency that a library is re-exporting can be a breaking change upstream.
There’s no “pretty please”, this is all established practice and well-defined procedures.
Of course there can be usability advantages to the re-export. As can there in not having all your public dependencies re-appearing in your module structure.
Well, until your usage of those updated public dependencies breaks because their API changed. Then you need to look up the relevant docs, anyways. Of course, it’s less effort in case you didn’t hit any of the changed API surfaces (and as long as you hope they ensure that nothing breaks and changes behavior “silently”, without compile-time or run-time errors…)
In my view, the question of how proper adding a pub extern crate … thing for your public dependencies depends on many factors. One of them might be how popular the crate is, and how frequently it changes major versions. For example I would imagine that you, too, don’t do it for something like serde, and it’s clear that very few crates re-export serde when they publicly depend on it.