From murdoch.duncan at gmail.com  Thu Apr 12 19:27:09 2012
From: murdoch.duncan at gmail.com (Duncan Murdoch)
Date: Thu, 12 Apr 2012 13:27:09 -0400
Subject: [Rd] [patch] giving library() a 'version' argument
In-Reply-To: <21A5E1E970CD46459ECBE86D6CC4B28C667AA9BA@spexch01.WindLogics.local>
References: <21A5E1E970CD46459ECBE86D6CC4B28C667AA79C@spexch01.WindLogics.local>
	<4F86C8DC.7020608@gmail.com>
	<21A5E1E970CD46459ECBE86D6CC4B28C667AA9BA@spexch01.WindLogics.local>
Message-ID: <4F87106D.9050402@gmail.com>

On 12/04/2012 11:11 AM, Ken Williams wrote:
>
> >  -----Original Message-----
> >  From: Duncan Murdoch [mailto:murdoch.duncan at gmail.com]
> >  Sent: Thursday, April 12, 2012 7:22 AM
> >  To: Ken Williams
> >  Cc: r-devel at r-project.org
> >  Subject: Re: [Rd] [patch] giving library() a 'version' argument
> >
> >  On 12-04-11 11:28 AM, Ken Williams wrote:
> >  >
> >  >  Reasons one might want this include:
> >  >
> >  >     * you know that in version X some bug was fixed
> >  >     * you know that in version X some feature was added
> >  >     * that's the first version you've actually tested it with&   you don't want to
> >  >   vouch for earlier versions without testing
> >  >     * you develop on one machine&   deploy on another machine you don't
> >  >  control, and you want runtime checks that the sysadmin installed what
> >  >  they were supposed to install
> >
> >  I don't really see the need for this.  Packages already have a scheme for
> >  requiring a particular version of a package, so this would only be useful in
> >  scripts run outside of packages.
>
> The main distinction here is that the existing package mechanism enforces version requirements at *install* time, but this mechanism enforces it at *run* time.

I haven't tested it, but according to the documentation in Writing R 
Extensions, the dependencies are enforced at the time library() is called.


>   So this indeed applies well to scripts run outside packages, but it's also useful inside packages when they're loading their dependencies at runtime.  I was trying to illustrate that with the 4 bullet points above (especially the last one) but I should have said so explicitly.

If the docs are wrong (or I misread them), you could equally put a 
run-time version test into the .onLoad function in a package.
>
> It can happen very easily that constraints that were satisfied at install time get out of whack by subsequent package installations, but the violations go undetected.  The result can be breakage, whether dramatic or subtle.
>
> The main hats targeted here are really people (like me, of course) who are trying to "productionize" results, not so much people who are doing offline analysis.  In a production system
>
> >  But what if your script requires a particular
> >  (perhaps obsolete) version of a package?  This change only puts a lower
> >  bound on the version number, and version requirements can be more
> >  elaborate than that.
>
> Certainly true; this was meant as a first iteration, and support for the more elaborate requirements specifications could certainly be added.
>
> The more elaborate specs actually illustrate the need for a runtime mechanism nicely - if code X (which may be a package, or a script, it doesn't matter) requires exactly version 3.14 of package B, and someone in the production team upgrades version 3.14 to version 3.78 because "it's faster" or "it's less buggy" or "we just like to have the latest version of everything all the time", then someone needs to be alerted to the problem.  One alternative solution would be to use a full-fledged package management system like RPM or Deb to track all the dependencies, but yikes, that doesn't sound fun.

But a single line at the top of the script would fix this:

stopifnot(packageVersion("foo") == "3.14")

Making the library() function more elaborate doesn't seem to add anything.


>
> >  I think my advice would be:
> >
> >  1.  Put your code in a package, and use the version specifications there.
> >
> >  2.  If you must write it in a script, then put a version test at the top, using packageVersion().
>
> Certainly those are alternatives, but to us they are somewhat unsatisfactory.  The first option doesn't help with the crux of the problem, which is runtime enforcement.  The second is essentially the same solution I've proposed, but doesn't help anyone outside our organization who has the same problem.

Another problem with putting this into library() is that packages aren't 
always loaded by library():  there is require(), and there are implicit 
loads triggered by dependencies of other packages.

Duncan Murdoch



[Rd] [patch] giving library() a 'version' argument
Duncan Murdoch