Please be mindful of version bounds and semantic versioning when tagging your packages

If it isn’t intended to be a common package for broad use, perhaps it shouldn’t be in the main registry? Doesn’t mean your work has to be closed at all, but maybe a different forum is more suitable for research products?

4 Likes

I just want to understand what the misunderstanding here is about:

  • Everyone agrees that semver is a good thing.
  • Julia’s eventual adjustments (in syntax or functionality) to semver are fine.
  • Then the question is if we should:
    1. loosely remind people to adhere to semver
    2. build tools for semver adherence and build it into the package creation (e.g. automatically populate the [compat] section).
    3. encourage semver adherence by perks such as automated registration for semver compliant packages.
    4. downright enforce it somehow.

The disagreement is on where on that last enumerated list we should land. Do we have examples from other languages on how their adherence to semver and how they implemented it was a success/failure? I assume all of this is old news and that this has already been discussed on github or verbally.

2 Likes

Here is some stuff from Rust which people seem to like the package management in:

https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field

Before you reach 1.0.0, anything goes, but if you make breaking changes, increment the minor version.
After 1.0.0, only make breaking changes when you increment the major version. Don’t break the build.

This is the same as we do.

Cargo also forbids registering packages with “*” (meaning any version).

might be interesting as well.

5 Likes

Two tooling ideas I’ve not seen mentioned, but would be unable to write:

  • When trying to add [compat] section, it’s hard to know what lower bounds to put. A much earlier version of some package you use very little of may well be fine. Should there be a Pkg.down command that does the opposite of up, so that you can test there, and figure out generous lower bounds?
  • When trying to update, it can be pretty hard to figure out which package’s bounds are binding. Could up simply print a list of all packages barred from updating not by my Project, but by something I depend on? (I am picturing this being just one deep, not the whole tree.)
1 Like

The Julia community provides and maintains the General registry as a service, free of charge, for you to register your package in. In order to use it, you have to agree with the standards the Julia open-source community has established (for example considering package naming). If you do not accept the community standards for the General registry it is very easy to create your own registry.

These policies are, of course, not set in stone and are an attempt to provide a good experience both for authors and users when using the package management.

This has nothing to do with the importance of your package since the same policy applies to all packages. The General registry provides a service to the users of it, and we want that service to work well which necessitates some sort of policy making.

The type of argument “pay me to adhere to the Julia community established guidelines for automatic package merging” is unlikely to bring you much good-will (nor income).

16 Likes

Well, why didn’t you just admit this from the start? That you are only trying to make things easy for yourself instead of pretending you follow a much better path.

Also, you seem to base your reasoning on things that are not correct, e.g. here, where you (seem to?) think that adding bounds to a new release retroactively adds the same bounds on previous releases:

And also, when presented with an actual example (Please be mindful of version bounds and semantic versioning when tagging your packages - #29 by fredrikekre), you didn’t explain and/or answer how you would solve that problem.

But at least there a state that is proven to work. That might not include beeing on the latest version of every dependency, but at least it is something working. The opposite would be that users just get some random version that claims to be compatible with everything.

Okay, so say I am completely new user and know nothing about versions etc. I decide to test out some of these packages: pkg> add A1 A2 B, and I get, say, A1@1, A2A1@2, BA1@3. Cool! I can start writing Julia code now!
Turns out there exist A1@2, which I am happily unaware of. Now, if it turns out I do need A1@2, I try to add it and get a resolver error message (admittedly these can be better, see Better resolver failure messages · Issue #819 · JuliaLang/Pkg.jl · GitHub, but at least I have something to report). So since I am a new user and don’t understand why, I raise an issue with A1: Hey, why can I now use A1@2 here?. Hopefully it is still a maintained package, and the problem can be resolved.

Consider now the case with no bounds; I try again pkg> add A1 A2 B, but this time I get A1@2, A2A1@2, BA1@3. I start writing code, nothing works.
As a new user, where do I raise an issue? I don’t know. Lets file an issue with A1. What do you as a maintainer of A1 tell this user? What versions of the dependencies do you have? Well, I just use what I got from the resolver, that you as the maintainer told the registry you were compatible with. Ok, but I just hoped nothing would break. You need to add this package at that version, and that other package on that version. Can you try that?

That does not seem more user-friendly to me.


Yea, but putting the latest (SemVer) breaking release there is never wrong, after all, it is unlikely that your package works with more than one or two breaking versions of your dependency, so it is not that hard to test. If you (or your users) feels it is important that the package also work with older releases of that dependency they can fix that. See also Introduce `down` as opposite of `up` · Issue #1062 · JuliaLang/Pkg.jl · GitHub

8 Likes

I want to point out that the current state of affairs have to be the default because it is the one that keeps code working. However, it does not mean that we can’t have:

  • Flags to Pkg to “turn off the resolver” or give other hints to it. pkg> add A B C --force-latest or something
  • Better tooling to run automatic test on packages that would get upper bounded when a new SemVer incompatible version is registered.
  • Better error messages to more clearly describe the problem and how one can go about fixing it.
30 Likes

Just as a side note, an interesting thing to consider is that the feedback from doing something like this (keep code working but with some drawbacks in some cases) will, almost by construction, only be negative. The reason is that you will never hear from someone saying “I added packages A, B and C and it just worked” because that is just doing what they expect and no one is going to write a discourse post about a system behaving according to expectation. You will only hear from people where they e.g. wanted to use the latest feature in C but that didn’t get installed because B wasn’t compatible with it.

It is in my opinion important to keep these type of asymmetries in consideration when listening to feedback (not to diminish any feedback given in this thread).

22 Likes

I have been thinking about this after reading all the comments here and there are a lot of comments.

And I have found the perfect solution for everyone which is guaranty to work. There are of course a few rules to follow:

But first, the solution.

The solution is that this is a FALSE PROBLEM. It is not really a problem if you think clearly about this.

The solution is “Package Namespace is infinite but people argue about artificial scarcity.”

Here is the solution

  1. Name your packages PackageName0001 (eg. OffsetArrays0001.jl )
  2. Maintain Forward Compatibility at all cost
  3. If you cannot maintain Forward Compatibility then create a new package called PackageName0002 (eg. OffsetArrays0002.jl )

This way a Julia environment can have both module OffsetArrays0001 and module OffsetArrays0002 at the same time. No more issues with Package B0001 breaking Package A0001.

Steven Siew

It does create other problems though. Consider your package is using two packages A and B which depend of OffsetArrays0001.jl and OffsetArrays0002.jl. Now your package gets an OffsetArray from A and one from B and wants to add them: that does not work because those two are different types: OffsetArrays0001.OffsetArray and OffsetArrays0002.OffsetArray.

4 Likes

argues similarly in that a breaking version is effectively the same as to just rename the package.

The whole video is a good watch for people interesting in these things.

5 Likes

mauro3, you are right. I didn’t think about that.

1 Like

I would like to highlight the constructive advice of the original post, which solves the greatest part of the conflict between adding or not adding upper compat bounds:

If you usually keep the compat section commented out in master, and have a suitable test suit, you may be aware at any time of compatibility issues with the latest package versions – and even approaching Julia versions, e.g. when Julia 2.0 becomes available for Travis to check. You fix it when errors happen, otherwise you rest.

Now, if you want to have a version registered in General (and get it registered automatically, without waiting for its maintainers to review it), you make a commit adding those compat bounds, and call JuliaRegistrator to register it. Then make another commit removing the compat bounds – and increasing the version number to make it unambiguous, so that master comes back to the “development”, no-guarantee status.

Notice the if of the previous statement. Packages can live without the services of the General registry. My understanding is that General wants to provide guarantees of packages not breaking due to major version changes in dependencies – if SemVer is followed – paying the cost of requiring major updates of dependent packages that might have not been needed. But users that do not need that guarantee, and can live in untested, bleeding-edge package environments, may choose clone the package straight from the original repository – or even from other registries that may have other policies. It is as easy as giving the suitable address to the package manager when you add.

On the other hand, there is the extra burden for package maintainers that do want to have registered versions of their packages installable with the latest compatible dependencies. It’s not that much, and the community can assist, as has already been pointed out.

And I daresay could be automated too. Safe compat bounds can be found out from the package’s Manifest.toml in a status where the tests pass. If I’m one of those package maintainers that make the development without compat bounds, my local installation of the package will normally be sync’d with master – i.e. without bounds --. There might be a tool that detects major updates of its dependencies, runs my package’s tests when those updates are installed, and if the tests succeed, makes those two commits (one adding the compat bounds and the next one reverting them), plus a PR to the repo that the maintainer can use to request the registration

1 Like

Maybe you missed it, but I think that

mentioned above should solve this whole issue in a much more streamlined way.

Generally, I think that it should be understood that even if the recommended approach for handling version compatibility looks cumbersome, a lot of it can and actually will be automated and streamlined. It’s just the tooling is also recently developed (or possibly WIP in some cases) and we need to get used to it.

6 Likes

Yes, I had missed it!
Thanks!

Not hypothetical. This is what is happening right now. Updating breaks things in weird and wonderful ways, instead of clear and easily fixed ways.

Bug fixes should always be available in patch releases that are compatible with the same things as you’re currently using. So that only leaves the new feature case. Users who lack time, skill or money to assist will, of course have to wait for new features, but that seems unavoidable. After all, those people are literally contributing nothing.

4 Likes

I am not pretending anything, I am just myself, if you got a problem with that, that’s your problem.

The guidelines you are asking me to follow are extra work, which I am not willing to attend to unless I am paid for enterprise reliability services.

This has nothing to do with trying to bring good will or income, it’s just a simple transaction.

If you expect a specific kind of long term reliability, then you need to pay me for tending to this guarantee.

So, can I get my release actually merged then? Or is everyone going to argue about this forever?

There are 3 options as far as im concerned:

  • Either pay me for enterprise service to get reliability,
  • tag my release with my preferred Project.toml
  • quit making free releases

With a free release, and no paying for reliability, people should be grateful to use my software and send me bug reports or compat issues if they find them. That’s a reasonable transaction for free users.

If someone pays for external reliability, then I will make sure it is reliable ahead of time myself. Otherwise, i’d rather have my free users report the issues.

1 Like

The upper bounds are useful for many developers.

@chakravala: if you do not want to use them, why don’t you simply set very loose upper bounds? You can update the bounds every time you release a new version, and provide the type of support you seem to be aiming for (i.e., driven by GitHub issues).

I am not suggesting you should do it (it seems bad practice to me). However, there is no need to be conflictual with this choice.

Well, you argue for an alternative approach, but you have failed to explain to me why it is better; e.g. you stil have not answered my questions in Please be mindful of version bounds and semantic versioning when tagging your packages - #46 by fredrikekre

But you not following the guidlines creates extra work for the registry maintainers. Are you paying them for that service? I happen to know that there are people that have spent, and still do when time allows, countless of hours each weak on their free time (without getting payed) on maintaining the registry.

12 Likes