RFC: give up on SemVer

For using Library or Library.addition to not break, it would have to export only version 1 forever. And I think it’ll hurt productivity if we have to specify explicit numbers one by one just to avoid code breaking in new versions.

Where is the line, though? As fierce the argument has been about SemVer, I think we’re all in agreement that “we can break anything” is not the way to go, that there is a point between that and ideal SemVer adherence (,and closer to the latter). But how do we calculate and agree on whether a breaking change is minor? Should we make a list of measures that we should do before considering a breaking change e.g. deprecating obsolete names?

3 Likes

I honestly think using is a horrible mistake anyway, but that leads to another topic.
Does it break import?

Well, do we really want to live in a world, where things break so often, that “it hinders productivity” when we enter the version, at which the function still worked?

And this even includes, that you assume we would rather just use the old version, rather than updating.
As said in another thread, has the Linux kernel solved to stay API compatible for a couple of decades.
Why does this seem to be not such a priority in Julia?

A lot of the criticism I read, has talked about that topic.
It seems like it pushes people away.

Isn’t this something to tackle?

The Elm video I posted, makes a proposal to exactly that.

The API break is determined by a change in the type system, and I imagine we could add tests to the equation.

Once you break the API in Elm, by changing the type signature, you automatically push the package with a major version increase.

This is done by the packaging tool.

1 Like

Yes, that’s why I said Library.addition.

It’s not that we would rather default to version 1 forever, it’s necessary to avoid breaking code across versions. If I write Library.addition(1,2), and upgrading Library makes that code give a different result, then it’s breaking. The only way to avoid that is to guarantee the same results across all the versions, in which case it’s just public API and there’s absolutely no reason to keep any obsolete versions. I think that’s what you intended in your example (put text in code blocks instead of screenshots, makes it easier to quote), and FYI changing addition(x,y)=x+y to addition(a,b)=a+b is not a breaking change. This isn’t different from how things are done already.

1 Like

Yeah, I didn’t intend to write breaking change, just threw out some lines.
Its late here, and I think my point was more about making the functions versioned, rather the libraries.
It might be, that this has no sensible benefits.

In order to give a more objective basis to this discussion, it would be very nice to have a list of those “technically breaking changes” that have been included so far in Julia releases. In this moment I don’t even know if it is a long or a short list.

https://github.com/JuliaLang/julia/issues?q=is%3Amerged+label%3A%22minor+change%22+

2 Likes

Thanks, but that is the list of changes labelled as “minor”. Are all those changes technically breaking in the sense that @Tamas_Papp meant?

I don’t understand how this is a change to the status quo. Reasonable people already understand that any change whatsoever may be breaking. Semver are soft guarantees, up to the judgement of the maintainers. That’s basically what the risk tolerance post is about. Announcing “we don’t follow Semver” sends the wrong message. You can be an honest person without always replying every mundane question with 100% accuracy.

As industrial julia users, the minor breaking changes to julia so far have been entirely in line with expectations. Sometimes we hold off on upgrading. That’s just a regular Monday in software engineering.

11 Likes

It’s important context that the “standardized entry point” PR was originally also marked as a minor change. So either the label is not accurate, or we’re not good at assigning those labels and should be better (though I do want to emphasize that @mbauman also was the one removing that label and adding breaking instead).

1 Like

Looks like the discourse onebox munged my link. I’ve edited it. The “minor change” label is trying to identify exactly this — things that are technically breaking but have been deemed acceptable or a minor release.

2 Likes

I think that should be highlighted in the label description - it currently only mentions behavioral changes, nothing about minor breakages:

image

3 Likes

In my view it was accurate until it was reverted. It was retrospectively deemed too breaking to be a minor change.

Right, it definitely was a fitting label until we discovered that it wasn’t - which kind of gels with the theme of this thread about having to do better in anticipating the consequences a change really has :slight_smile: I.e., less cowboy attitude, more careful planning & defensive progress.

In my view, there is no one person at fault here - it’s the current (extremely informal) process that could have easily caught this particular instance, e.g. via a PkgEval. To me, that means there’s room for improvement in the process here.

2 Likes

This didn’t get released. It was briefly on a development branch. PkgEval did flag it, and there would’ve been many more hurdles for it to pass before even getting close to landing on a release.

For the good and the bad, open source means you see the floor of the sausage factory and can even participate in it.

18 Likes

Any change, or at least addition to an exported API (of Julia), is potentially (actually, technically, in fact) a breaking change.

Major languages, like C++ break compatibility all the time, also Python and Java. An exception might be Clojure, but it has full immutability, persistent data structures, i.e. features helping never needing breaking changes (and almost minimal syntax, and doesn’t need to add to it).

It’s an ideal to not break code, or do it so that very few users notice.

Python is in the process of dropping some outdated stdlibs, in 3.x, so it’s not just making breaking changes to its C API.

in its API. These changes might trigger compile-time, link-time, or run-time errors in client code […]
We identify and address some limitations of the original protocol and expand the analysis to a new corpus spanning seven more years of the MCR. We also present a novel static analysis tool for Java bytecode, Maracas, […]
contrast with the original study and show that 83.4% of these upgrades do comply with semantic versioning. Furthermore, we observe that the tendency to comply with semantic versioning has significantly increased over time. Finally, we find that most BCs affect code that is not used by any client, and that only 7.9% of all clients are affected by BCs.

C++ and other separately compiled languages, i.e. ahead of time, are in a special position. They can go with breaking API and it only affects developers. They are however famously afraid of, or against breaking the ABI, making C++ slower than it could be, thus not living up to its ideal “you don’t pay for what you don’t use”.

That said, I think Julia should strive for the SemVer ideal, to not break before 2.0.

I’m not sure I understand this part. I don’t think a large fraction of users stick to [Julia] LTS releases, but since you mentioned “of the ecosystem” did you mean there are LTS packages? Some such as DataFrames.jl strive to still support Julia 1.6 LTS, but there’s no need I think. They can target (1.9 or) 1.10 now that will become the next LTS.

Julia has reproducability for any version, not just LTS, so people can e.g. program for 1.9 (or 1.3 for Cxx.jl…) and keep using it forever, with the Manifest for their project.

To me it’s a bonus if you can upgrade Julia, and yes ideally it would just work. I think it does except for some very few packages that pirate the internals of Julia. However, those foundational packages are used by many in the ecosystem, so in effect it affects most. It’s non-ideal, but I believe can always be handled by upgrading packages (in the past there was an exception Cxx.jl, that people no longer use).

Now about the potential breakage in Julia. If it adds an exported function or macro say named KsdhsSF2efD then it’s relatively safe. But if it adds such a function or macro named e.g. S, then it has a large probability of conflicting. In either case PkgEval is run and it will likely be found to be conflicting, but only for registered packages using the same name, so since some packages are private, there’s just no way to be 100% sure for any addition to the exported API. Julia recently added the public keyword, so now non-exported functions and macros can be added without them exported, but would people be ok with e.g. Base.new_thing(), for any additions, as I suggested? I got downvoted on that suggestion at JuliaLang. People do not like fully-qualified for everything new from now on. I think that may be done in Clojure (and C++ and Python) for at least new stuff.

The same argument applies to packages, they can’t export new things, technically speaking without updating the the major version according to SemVer.

What should be guaranteed? Julia adds things all the time, with e.g. “available in Julia 1.11”, and I think all new additions should be marked Experimental, or at least implicitly. Then documented as such globally on new additions. Julia is getting a new stdlib StyledStrings. At first a new string type S"content" was proposed (then as exported; from Base). Its S_str macro conflicted with a known registered package and would have been trouble. It was renamed styled_str, and it’s NOT exported. You might think we’re ok, but even the name of the stdlib StyledStrings is in a global scope so that you can import it. Then we are kind of stuck with that name. Arguable if it’s not good, then instead of renaming a stdlib (or function or macro) we could rename as a synonym, and keep the old name just for compatibility. I would rather want to avoid accumulating too much such old cruft, why I recommend all additions are not committed to until next release, or later, for this 1.12 (or 1.13?). Who ever made the perfect API the first time around?

What Rick Hickey is talking about arguing against SemVer, is deletion (or changes) to API, as never really needed. He’s not arguing against additions, but I think he would agree with exported, i.e. unqualified additions.

This has neither been confirmed nor denied. LTS decisions are made after the release, not before it.

7 Likes