Difference between revisions of "Package versioning policy"

From HaskellWiki
Jump to navigation Jump to search
m (Library versioning policy moved to Package versioning policy)
Line 1: Line 1:
  +
== Rationale ==
[[Category:Proposals]]
 
We all know what is a "DLL hell" - if some program written against
 
version 2.0 of library, then using version 1.0 or 3.0 of the same
 
library when program compiled may call all sorts of devil
 
   
  +
The goal of a versioning system is to inform clients of a package of changes to that package that might affect them, and to provide a way for clients to specify a particular version or range of versions of a dependency that they are compatible with.
there is a great solution of this problem - Eternal Compatibility
 
Theory. unfortunately, it's so great that seldom used on practice
 
because it requires significant efforts from library developer
 
   
  +
[http://haskell.org/cabal Cabal] provides the raw materials for versioning: it allows packages to specify their own version, and it allows dependencies that specify which versions of the dependent package are acceptable. Cabal will select dependencies based on the constraints.
i propose another solution for this problem which don't require to
 
write anything and just impose some policies both for library
 
developer and user
 
   
  +
What is missing from this picture is a ''policy'' that tells the library developer how to set their version numbers, and tells a client how to write a dependency that means their package will not try to compile against an incompatible dependency. For some time there has been an informal policy in use in the Haskell community, but it became clear that we were running into trouble with incorrectly-specified dependencies and unbuildable packages, so this page is an attempt to formalize the policy.
library developer should just explicitly declare and obey some policy
 
of incrementing library versions which will allow library user to
 
select proper range of versions which are guaranteed to work with his
 
code. i propose the following as standard policy:
 
   
  +
== Version numbers ==
* major version change (2.2->3.0) means total incompatibility. all sorts of changes may come
 
   
  +
A package version number should have the form ''A.B.C'', and may optionally have any number of additional components, for example 2.1.0.4 (in this case, ''A''=2, ''B''=1, ''C=0''). This policy defines the meaning of the first three components ''A-C'', the other components can be used in any way the package maintainer sees fit.
* middle version change (2.1.3->2.2) means addition of new facilities (functions, constructors, classes...). in most cases, such semi-compatible version can be used if that's done with caution
 
   
  +
Version number ordering is already defined by Cabal as the lexicographic ordering of the components. For example, 2.1 > 1.3, and 2.1.1 > 2.1. (The <tt>Data.Version.Version</tt> type and its <tt>Ord</tt> instance embody this ordering).
* minor change (2.1.1->2.1.2) means only internal changes and bugfixes
 
   
  +
''A.B'' is known as the ''major'' version number, and ''C'' the ''minor'' version number. When a package is updated, the following rules govern how the version number must change relative to the previous version:
other policies may be used as well, library developer should just
 
declare his policy at the library birth and use it consistently
 
   
  +
# If any entity was removed, or the types of any entities or the definitions of datatypes or classes where changed, or instances were added or removed, then the new ''A.B'' must be greater than the previous ''A.B''.
  +
# Otherwise, if only new bindings, types or classes were added to the interface, then ''A.B'' may remain the same but the new ''C'' must be greater than the old ''C''.
  +
# Otherwise, ''A.B.C'' may remain the same (other version components may change).
   
  +
Hence ''A.B.C'' uniquely identifies the API. A client that wants to specify that they depend on a particular version of the API can specify a particular ''A.B.C'' and be sure of getting that API only. For example, <tt>build-depends: mypkg-2.1.1</tt>
this will allow library users to declare in their cabal files range of
 
library versions they are accepted and be sure that this range will
 
include latest bugfixes but don't include any incompatible changes.
 
then Cabal (which now can handle many versions of the same lib) should
 
select latest acceptable version of library requested and make it
 
available for compilation
 
   
  +
Often a package maintainer wants to add to an API without breaking backwards compatibility, and in that case they can follow the rules of point 2, and increase only ''C''. A client can specify that they are insensitive to additions to the API by allowing a range of ''C'' values, e.g. <tt>build-depends: base >= 2.1.1 && < 2.2</tt>.
say, if i wrote my program using Streams 1.2.1, i can specify
 
   
  +
== Dependencies in Cabal ==
Build-Depends: Streams 1.2.*
 
   
  +
When publishing a Cabal package, you should ensure that your dependencies in the <tt>build-depends</tt> field are accurate. This means specifying not only lower bounds, but also upper bounds on every dependency.
or, if i brave/accurate enough:
 
   
  +
At some point in the future, Hackage may refuse to accept packages that do not follow this convention. The aim is that before this happens, we will put in place tool support that makes it easier to follow the convention and less painful when dependencies are updated.
Build-Depends: Streams >= 1.2.0 && < 2.0
 
   
  +
To minimize breakage when new package versions are released, you can use dependencies that are insensitive to minor version changes (e.g. <tt>foo >= 1.2.1 && < 1.3</tt>). However, note that this approach is slightly risky: when a package exports more things than before, there is a chance that your code will fail to compile due to new name-clash errors. The risk from new name clashes tends to be small, and you can always eliminate it by using explicit import lists if you want.
and Cabal should select the best library available at build time
 
   
 
== Related ==
 
== Related ==

Revision as of 11:35, 17 October 2007

Rationale

The goal of a versioning system is to inform clients of a package of changes to that package that might affect them, and to provide a way for clients to specify a particular version or range of versions of a dependency that they are compatible with.

Cabal provides the raw materials for versioning: it allows packages to specify their own version, and it allows dependencies that specify which versions of the dependent package are acceptable. Cabal will select dependencies based on the constraints.

What is missing from this picture is a policy that tells the library developer how to set their version numbers, and tells a client how to write a dependency that means their package will not try to compile against an incompatible dependency. For some time there has been an informal policy in use in the Haskell community, but it became clear that we were running into trouble with incorrectly-specified dependencies and unbuildable packages, so this page is an attempt to formalize the policy.

Version numbers

A package version number should have the form A.B.C, and may optionally have any number of additional components, for example 2.1.0.4 (in this case, A=2, B=1, C=0). This policy defines the meaning of the first three components A-C, the other components can be used in any way the package maintainer sees fit.

Version number ordering is already defined by Cabal as the lexicographic ordering of the components. For example, 2.1 > 1.3, and 2.1.1 > 2.1. (The Data.Version.Version type and its Ord instance embody this ordering).

A.B is known as the major version number, and C the minor version number. When a package is updated, the following rules govern how the version number must change relative to the previous version:

  1. If any entity was removed, or the types of any entities or the definitions of datatypes or classes where changed, or instances were added or removed, then the new A.B must be greater than the previous A.B.
  2. Otherwise, if only new bindings, types or classes were added to the interface, then A.B may remain the same but the new C must be greater than the old C.
  3. Otherwise, A.B.C may remain the same (other version components may change).

Hence A.B.C uniquely identifies the API. A client that wants to specify that they depend on a particular version of the API can specify a particular A.B.C and be sure of getting that API only. For example, build-depends: mypkg-2.1.1

Often a package maintainer wants to add to an API without breaking backwards compatibility, and in that case they can follow the rules of point 2, and increase only C. A client can specify that they are insensitive to additions to the API by allowing a range of C values, e.g. build-depends: base >= 2.1.1 && < 2.2.

Dependencies in Cabal

When publishing a Cabal package, you should ensure that your dependencies in the build-depends field are accurate. This means specifying not only lower bounds, but also upper bounds on every dependency.

At some point in the future, Hackage may refuse to accept packages that do not follow this convention. The aim is that before this happens, we will put in place tool support that makes it easier to follow the convention and less painful when dependencies are updated.

To minimize breakage when new package versions are released, you can use dependencies that are insensitive to minor version changes (e.g. foo >= 1.2.1 && < 1.3). However, note that this approach is slightly risky: when a package exports more things than before, there is a chance that your code will fail to compile due to new name-clash errors. The risk from new name clashes tends to be small, and you can always eliminate it by using explicit import lists if you want.

Related