# Semver enforcement

**URL:** <https://discourse.elm-lang.org/t/semver-enforcement/9263>\
**Category:** Learn\
**Created:** [August 3, 2023, 4:42pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263 "2023-08-03T16:42:57Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![ShalokShalom](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/shalokshalom/32/2203_2.png) [@ShalokShalom](https://discourse.elm-lang.org/u/ShalokShalom)\
**Post date:** [August 3, 2023, 4:42pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/1 "2023-08-03T16:42:57Z")

</div>

Hi there 🙂

Is there any check in place, that goes further than checking the type signature, in order to determine the API changes?

---

<div class="post-metadata">

**Author:** ![wolfadex](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/wolfadex/32/2461_2.png) [@wolfadex](https://discourse.elm-lang.org/u/wolfadex)\
**Post date:** [August 3, 2023, 5:39pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/2 "2023-08-03T17:39:46Z")

</div>

What are you looking for? Not sure I understand what else would impact semver.

---

<div class="post-metadata">

**Author:** ![choonkeat](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/choonkeat/32/1555_2.png) [@choonkeat](https://discourse.elm-lang.org/u/choonkeat)\
**Post date:** [August 3, 2023, 10:46pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/3 "2023-08-03T22:46:13Z")

</div>

@wolfadex type signature could be the same but logic inside the function behaves differently, e.g. the withDefault logic was True but is now False

@ShalokShalom no there isn’t 😔

---

<div class="post-metadata">

**Author:** ![wolfadex](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/wolfadex/32/2461_2.png) [@wolfadex](https://discourse.elm-lang.org/u/wolfadex)\
**Post date:** [August 4, 2023, 12:31am UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/4 "2023-08-04T00:31:17Z")

</div>

@choonkeat that’s exactly what semver covers, which is why I asked. That would constitute a patch change.

So yes, Elm has enforced semver.

---

<div class="post-metadata">

**Author:** ![choonkeat](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/choonkeat/32/1555_2.png) [@choonkeat](https://discourse.elm-lang.org/u/choonkeat)\
**Post date:** [August 4, 2023, 1:32pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/5 "2023-08-04T13:32:36Z")

</div>

If `String.append a b` was returning `a ++ b` but now returns `b ++ a`.

While no type signature had changed, all user code compiles after upgrade but would be an incompatible change and as far as [semver](https://semver.org/) itself is concerned, should bump major version.

But `elm publish` doesn’t catch that and would only be a patch change.

---

<div class="post-metadata">

**Author:** ![Sebastian](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/sebastian/32/98_2.png) [@Sebastian](https://discourse.elm-lang.org/u/Sebastian)\
**Post date:** [August 5, 2023, 7:21am UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/6 "2023-08-05T07:21:00Z")

</div>

Elm has no way to detect those breaking changes, it will see this as a patch version. All you can do is force Elm to think it is a breaking change by introducing a made up type signature change somewhere.

---

<div class="post-metadata">

**Author:** ![lydell](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/lydell/32/178_2.png) [@lydell](https://discourse.elm-lang.org/u/lydell)\
**Post date:** [August 5, 2023, 8:20am UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/7 "2023-08-05T08:20:55Z")

</div>

When making a breaking change that doesn’t cause compilation errors (which as said won’t count as a breaking change by Elm), consider actually causing compilation errors. Rename the function or something. Then users of your package get help finding all the places they need to account for the new behavior.

---

<div class="post-metadata">

**Author:** ![Magnetize2072](https://avatars.discourse-cdn.com/v4/letter/m/f17d59/32.png) [@Magnetize2072](https://discourse.elm-lang.org/u/Magnetize2072)\
**Post date:** [August 7, 2023, 3:46pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/8 "2023-08-07T15:46:45Z")

</div>

I’ve been thinking about this since I first learned about Elm’s enforced semver.

I THINK it would be possible to create a tool that will run one version of the code against another version’s tests. This would make sure that version `1.1.1` or `1.2.0` still passes all the tests from `1.1.0`.

Obviously, that only gives you as much guarantee as the tests in the previous version.

---

<div class="post-metadata">

**Author:** ![solificati](https://avatars.discourse-cdn.com/v4/letter/s/2bfe46/32.png) [@solificati](https://discourse.elm-lang.org/u/solificati)\
**Post date:** [August 9, 2023, 7:00pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/9 "2023-08-09T19:00:39Z")

</div>

I always found this semver enforcement a little silly. I mean Elm libraries are consumed inside Elm code so everything that changed and caused major version bump will error nicely in my code.

And because semver lacks granularity, just version number change doesn’t tell me much.

As someone said - Patch or minor change? Don’t care. Major change? Dunno, we’re probably fucked.

So after major version bump I still need to run compiler and see what changed and how it impacts my code.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [August 11, 2023, 10:02am UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/10 "2023-08-11T10:02:10Z")

</div>

> [@solificati](#):
>
> I always found this semver enforcement a little silly.

I see what you are saying - it would break anyway regardless of what the version number says. But the point is…

You can put version ranges in your packages elm.json, for example “elm-community/json-extra”: “4.2.0 \<= v \< 5.0.0”. This protects the package from ever using the next major version which will break it, so any consumer of the package with this dependency can be certain that their build will always work. Without this 1:1 mapping between breaking changes and the major version number, things could break without warning and we would not have such a robust and reliable package system - it would be more like the wild west npm system.

---

<div class="post-metadata">

**Author:** ![gampleman](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/gampleman/32/43_2.png) [@gampleman](https://discourse.elm-lang.org/u/gampleman)\
**Post date:** [August 11, 2023, 11:06am UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/11 "2023-08-11T11:06:12Z")

</div>

The slight problem (and we should definitely build some tooling to address this problem) with that is that the author can put just about any range they want in there. As long as the latest resolved version compiles, the compiler will not complain even if a previous (or later) version would be completely broken…

Thankfully this seems to almost never happen in practice (probably because actually being compatible with multiple major versions is relatively rarely possible and generally packages do not restrict maximum minor version, so consumers tend to always resolve the backwards compatible latest minor version), but the possibility is rather annoying.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [August 11, 2023, 11:25am UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/12 "2023-08-11T11:25:42Z")

</div>

Yes, a restriction to ranges of the form “x.y.z \<= v \< (x+1).0.0” is generally what is most useful and happens in practice. I suppose a hard rule about that might be going too far?

The `elm publish` tool just checks that it builds correctly locally. To do more sophisticated checking, we would need a package server that checks the builds in a controlled environment on the server-side. And then you have the problem of potentially checking a large number of combinations of versions which potentially makes it all a bit too much to fully check and enforce.

Certainly, I think that at least doing the step of checking a compile against the latest versions of the current state of the package repo in a controlled server-side environment makes sense. For example, there are packages built on Windows or Mac-with-case-inesnsitive-file-system that will not compile on a Unix box due to files having the wrong capitilization on them.

---

<div class="post-metadata">

**Author:** ![gampleman](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/gampleman/32/43_2.png) [@gampleman](https://discourse.elm-lang.org/u/gampleman)\
**Post date:** [August 11, 2023, 12:36pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/13 "2023-08-11T12:36:07Z")

</div>

> [@rupert](#):
>
> nd then you have the problem of potentially checking a large number of combinations of versions which potentially makes it all a bit too much to fully check and enforce.

Seems fairly unlikely. As far as I can fathom, the only time you would need to check combinations is the situation where a package depends on 2 or more packages with more than one major version (this is _very_ rare in the Elm ecosystem). These can break for instance if in the package does `B.bar A.foo`, and this works in version A 1 x B 1 and A 2 x B 2, but not for instance in A 1 x B 2.

Otherwise for minor versions there isn’t really a situation where packages can affect each other, so the total number of builds necessary is just the maximum number of version resolved for any dependency.

---

<div class="post-metadata">

**Author:** ![mattpiz](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/mattpiz/32/860_2.png) [@mattpiz](https://discourse.elm-lang.org/u/mattpiz)\
**Post date:** [August 11, 2023, 12:49pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/14 "2023-08-11T12:49:35Z")

</div>

For information, elm-test-rs enables you to test against the lowest specified version. There is a small explanation in the readme.

---

<div class="post-metadata">

**Author:** ![solificati](https://avatars.discourse-cdn.com/v4/letter/s/2bfe46/32.png) [@solificati](https://discourse.elm-lang.org/u/solificati)\
**Post date:** [August 11, 2023, 5:50pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/15 "2023-08-11T17:50:50Z")

</div>

> [@rupert](#):
>
> You can put version ranges in your packages elm.json, for example “elm-community/json-extra”: “4.2.0 \<= v \< 5.0.0”.

Or you can use strict versions for reproducibility and use dependabot for bumping dependencies. That way you won’t get random CI errors because someone published new package. All of deps updates are in separate PRs, so every error is minimal.

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [August 21, 2023, 5:51pm UTC](https://discourse.elm-lang.org/t/semver-enforcement/9263/16 "2023-08-21T17:51:13Z")

</div>

Closed on August 21, 2023, 5:51pm UTC

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
