Fwd: Fwd: Compatibility etiquette for apps, with cabal sandboxes and `stack`

[... and now to the whole list, I hate gmail's defaults... :-]
---------- Forwarded message ----------
From: Sven Panne
[...] What if the top package (in namespace) contained major version?
E.g. Cabal_1_22
below packages might use minor versions - basically, whenever api changes, change the version part of the affected package. [...]
As a developer, what should I import if my program/library works with e.g. the version range [1.20 .. 1.23]? It definitely can't be import Cabal_1_23.Foo.Bar because if it later still works with e.g. 1.24, I would have to rename all my imports. And always using the lower bound is probably too restrictive, unless I'm mistaken... In general I think it's a bad idea to spread build dependencies all over the code. Cheers, S.

As a developer, what should I import if my program/library works with e.g. the version range [1.20 .. 1.23]?
maybe change only that part of the namespace where api changed? also, why not publish less frequently? I mean, nothing stops anyone from making frequent changes to a library, but why not limit number of versions released to public?

2015-11-29 21:23 GMT+01:00 Imants Cekusins
As a developer, what should I import if my program/library works with e.g. the version range [1.20 .. 1.23]?
maybe change only that part of the namespace where api changed?
In the exporting library? In the importing library? also, why not publish less frequently? I mean, nothing stops anyone
from making frequent changes to a library, but why not limit number of versions released to public?
Could you explain this in more detail, please? I don't seem to understand what you're proposing... :-/

In the exporting library? In the importing library?
Well, in both places. Basically, similar part of namespace guarantees that api is the same below. If api (or code) changed, then it will lead to a different result. As consumer of a library, you'd refer to exactly the version you used while developing. This exact same version would be pulled in alongside other versions of the same library, used in other parts of a large app. It may lead to code duplication and larger binaries however it would essentially give you a sandbox with very little effort.
also, why not publish less frequently?
Could you explain this in more detail, please? I don't seem to understand what you're proposing... :-/
Well, let's say I am working on a library. Tempting as it is to release the first draft, I'd first use this fresh library in a few places, catch some bugs, fix them, and then release. Because this takes time, this library would see very few releases per year. It would be less likely to cause multiple version conflict.

Here is an allegory: There is Toyota 1985 and Toyota 2010. Although they both are Toyotas, they may be very different cars. ads show cars by brand, model and year, because brand alone is rarely enough. So why not spell this out in code? Why dump this task on tools which can not really tell what importing code actually requires?

2015-11-29 22:03 GMT+01:00 Imants Cekusins
In the exporting library? In the importing library?
Well, in both places. Basically, similar part of namespace guarantees that api is the same below.
To make this work on the exporting side, the namespace hierarchy would need to be structured according to API versions. This would mean constant reshuffling of modules in the hierarchy every time you make an API change. Furthermore, speaking from a more aesthetical point of view, names in the hierarchy should have some sensible semantic meaning and should not be littered with more or less random name suffixes.
[...] This exact same version would be pulled in alongside other versions of the same library, used in other parts of a large app.
This won't work when e.g.the libraries have a C part (unless you convince all people out there to use some kind consistent hierarchical naming scheme for C, too).
It may lead to code duplication and larger binaries however it would essentially give you a sandbox with very little effort.
Personally, I don't consider littering my code with version numbers as "little effort". Stuff like this should be specified outside of the source code IMHO.
Well, let's say I am working on a library. Tempting as it is to release the first draft, I'd first use this fresh library in a few places, catch some bugs, fix them, and then release.
Because this takes time, this library would see very few releases per year.
It would be less likely to cause multiple version conflict.
This contradicts the common "release early, release often" scheme of doing things, which has *many* advantages. And the number of releases is not relevant in itself, it's how often you change the API, which is a totally different matter. The longer you wait with releases, the higher the chance is that the next release has an incompatible API change, and your users won't get bug fixes without that API change, which won't make them especially happy. Cheers, S.

Am 30.11.2015 um 08:20 schrieb Sven Panne:
Personally, I don't consider littering my code with version numbers as "little effort".
Indeed it isn't. The effort could be reduced with proper tool or language support.
Stuff like this should be specified outside of the source code IMHO.
Well, sort-of. Let's assume semantic versioning: major version number changes for incompatible API changes, minor for downwards-compatible API changes, and tertiary ("milli") version number changes for API-unaffecting changes. So if your code calls into foo-3.4.1, you shouldn't have to worry whether it is actually being used with foo-3.4.2, or foo-3.5.0. However, you need to say foo-3 somewhere, inside your sources, because your code may break with foo-4.x.x. One issue I'm having with semantic versioning is that supposed-to-be-compatible library updates tend to be actually incompatible, often in subtle ways, so the library is released with a millversion change but that's a mistake (and lieing towards the application that's assuming an unchanged API). It's a big issue with imperative languages, where implementation details can leak via state. In Haskell, I suspect that (non-)termination behaviour is a similar potential implementation leak, though there's less opportunity for that to actually happen since the library would need to have lots of complicated, potentially infinite data structures hidden below opaque types. Regards, Jo
participants (3)
-
Imants Cekusins
-
Joachim Durchholz
-
Sven Panne