The baby and the bathwater

Cédric Champeau cedric.champeau at gmail.com
Wed Mar 28 09:01:04 UTC 2018


>
> They do. The fact that they create further (solvable) challenges does not
> mean that they are not a solution to the initial problem.
>
> The second point is also incorrect - indeed, this is exactly the point of
> using a range rather than a point version. If I depend on a range "[1.4,
> 2.0)", this is because I need a *feature* that was released in version 1.4
> of the dependency.
>

This is an arbitrary interpretation of a range. In practice people use them
for very different purposes. If, when you write "[1.4,2.0)", you assume
that you need a feature of 1.4, this is already an assumption. Most people
use 1.4 as the baseline because _this is the latest version available when
I started_. They also _assume_ that anything from 1.4 would work. In
practice this is rarely the case. There are bugs introduced, there are
binary incompatibilities (despite semantic versioning). Ranges are a
_convenience_, but certainly not an answer. Ranges + locking are better,
because you _have to_ test, but they don't account for the environment
either (say, my app depends on servlet-api, which version should you use?
It should be _strictly_ what the runtime environment will give).


>
> Well what does it mean when you write "compile 'foo:bar:1.0.4'" in your
> build.gradle file? It means you have compiled against that version of the
> API, and your module will be compatible with that version up to the next
> breaking change (2.0 if the dependency is using semver).
>
>
In Gradle you'd not use `compile` anymore. You would use:

api 'foo:bar:1.0.4'

for an API dependency, one that is exposed by your very own library (mostly
maps to "requires transitive")

and you'd use:

implementation 'foo:baz:2.1.4'

for an implementation dependency, that is _not_ exposed by your API (mostly
maps to "requires").

And if a transitive dependency needs a different version, we have
strategies to select a best match, or fail.


> If you wanted your module to be compatible with 1.0.3 then you would have
> compiled against 1.0.3. Unless you do that, there is no way for any tooling
> to infer that you are indeed compatible with 1.0.3.
>

That's again an over simplification. Real world apps have different
problems. You may say "1.0.3", because 1.0.2 had a bug. Maybe your app
didn't even depend on the faulty behavior, but because it had a bug, you
upgraded. And, maybe one of your dependencies actually required 1.0.2
because 1.0.3 introduced a regression. So you want to be able to downgrade
dependencies. Gradle makes it possible. There's a big difference between
the "ideal world", and the world we live in.


More information about the jigsaw-dev mailing list