The baby and the bathwater
Neil Bartlett
njbartlett at gmail.com
Wed Mar 28 09:22:40 UTC 2018
On Wed, Mar 28, 2018 at 10:01 AM, Cédric Champeau <cedric.champeau at gmail.com
> wrote:
> 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).
>
You keep mixing up the perspective of an application (and application
assembler) with the perspective of a library/module.
As a library developer I should pick the lowest version of my dependencies
that my library can build against. When assembling an application you pick
the highest version of each module such that you have a graph that will
resolve.
Version ranges in a library indicate compatibility, they say nothing about
buggy point versions of the dependency. Yes you still need a mechanism for
locking buggy versions but you store that information outside the module
descriptor (because we cannot know about buggy versions that may be
released in the future). That locking mechanism is in the domain of
application assembly.
>
>
>>
>> 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.
>
Good to know. And how do you transform that information into module-info?
You talked about generating module-info but it sounds like you would need
two of them... one with foo.bar for compile (otherwise javac will barf) and
the other with foo.baz for runtime (otherwise the runtime resolver will
barf).
>
>
>> 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.
>
>
>
I love being told that I don't live in the real world, and that the
problems I (and many others) have been solving for over a decade are
insoluble :-)
Downgrading with version ranges is of course possible so long as they are
used properly, but they also protect you from downgrading SO far that you
get problems like NoSuchMethodError, NCDFE, etc.
More information about the jigsaw-dev
mailing list