[racket] Should we _always_ use `only-in` or `prefix-in` when `require`-ing packages?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Mon Nov 18 10:22:01 EST 2013

Pre-caveats:
- Maybe this has been discussed before?
- This is true (IIUC) of the old Planet as well as the new package system.
- Maybe it's true of every package system.

With that said:

Technically, to maintain backward compatibility, a package should
_never_ `provide` a new name in an existing file. Either that or,
package users should _always_ use the `only-in` or `prefix-in` forms
of `require`.

Why?

1. My package defines `foo`. I `(require other-package)` (i.e.
other-package/main.rkt) which today does not provide any `foo`.  I
list other-package as a `dep` in info.rkt.

2. Someday, other-package add and starts to provide a `foo`, too. (I
don't notice. How/when/why would I?

3. Soon after, a user installs my package for the first time, and in
the process the dependency other-package is automatically installed --
latest version. Result: It breaks, `foo` is already defined.

If instead my package had done `(require (only-in other-package things
...))`, everything would have been fine: I wouldn't get the other
`foo`. Or, if I'd used `(require (prefix-in x: other-package))`, I
would harmlessly get the other `foo` as `x:foo`.


Is this correct?  Because it seems like something that needs to be in
bold type in the package docs: Simple Practical Advice.

(Otherwise, for many people, I think the notion of backward
compatibility is "don't remove or change old stuff".  Not, "don't add
new stuff".  So it might not be obvious to everyone. It wasn't to me,
until thinking about this recently.)


p.s. Even in the case where I _know_ that `foo` will soon be provided
in other-package -- let's say I submit a PR for my handy `foo` to be
added to that package, with a view toward eventually dropping my own
version -- the timing could be tricky. There's a window where a given
user might get the wrong combo of package versions. Using `only-in` or
`prefix-in` allows there to be a bridge period where it can exist in
both packages.

p.p.s. I suppose another strategy is a rule for pkg devs: Never
`provide` new things in an existing file. Always create a new file,
and put the `provide` there. To get it, users must `require` the new
file.  This is a sort of "`only-in` by others means".  However it also
means a convenient all-in-on main.rkt is no longer an option. This
rule seems to mean a proliferation of files, because once you deploy
the package, the new-file rule kicks in again. As a result, it seems
like the only practical solution is in the hands of package users.

Posted on the users mailing list.