This small note describes a plan to change the default semantics of Hint commands w.r.t. scoping.
Summary of the situation
As for most commands, when declaring hints one can choose a locality that will change their scoping behaviour. As of 8.13, we have three possible explicit locality qualifiers for hint commands, namely:
- “local”
- “export” (introduced in 8.12 for basic hint commands, and in 8.13 for the remaining ones)
- “global”
The behaviour of those qualifiers depends on whether the command is issued within a section or not.
Inside a section:
- “local” means that the hint completely disappears at section closing time
- “export” is forbidden
- “global” is forbidden
Outside of a section:
- “local” means that the hint completely disappears at module closing time
- “export” means that the hint is made available whenever its enclosing module is imported
- “global” means that the hint is made available whenever its enclosing library (i.e. the toplevel module) is merely required
The “global” behaviour is frowned upon, because it makes writing modular libraries very hard. It is virtually impossible to control the order in which modules are actually required, and because module require is transitive, it is very easy to break a downstream development if some file in a library changes the set of files it requires. As such, the use of the “global” qualifier should be avoided.
Unfortunately, when a hint command has no explicit locality qualifier, as of 8.13 it defaults to the wrong behaviour outside of sections. Namely,
- inside of a section, the default is “local” (fine, and the only allowed qualifier anyways)
- outside of a section, the default is “global” (← THIS IS THE PROBLEM)
Since most people do not like to write text they deem useless, it means that many developments define global hints without even realizing. This creates a lot of modularity issues.
Towards a change of default behaviour
Since “global” should be avoided, the default implicit locality should not be “global”. One thus needs to change the default locality to the one that is more modular, i.e. “export”.
Unfortunately again, bluntly turning the default to “export” would be a very backwards-incompatible change. Therefore, the change needs to be incremental. The change of default is to be performed in three steps that will be synchronized with Coq releases.
-
Step 1 (Coq 8.13): adding a hint without a locality qualifier outside of a section is temporarily deprecated. One has to explicitly write the corresponding attribute, otherwise a warning is triggered.
-
Step 2 (Probably Coq 8.14): this warning is turned into an error by default.
-
Step 3 (Probably Coq 8.15): the warning is removed, and hints without a locality outside of sections are allowed again, but this time their default behaviour is now “export”.
Note that hints inside a section are totally unaffected by these incremental changes.
The step increment is not necessarily going to be increased at a distance of only one release, if we realize that the explicit annotation process is not performed fast enough in the wild.
What I, the maintainer of a Coq library, have to do
TL;DR
In Coq 8.13
You should explicitly add a locality qualifier to every hint declaration outside of a section from your library. Choosing the right qualifier depends on your situation.
QUICK & DIRTY
You should use the backwards-compatible #[global]
attribute.
The following script uses a dumb pattern-matching to do that semi-automatically.
#!/bin/bash
# Invoke as ./script.sh MYLIBRARYFOLDER
pattern() {
PATTERN="s/^\(\s*\)$1/\1#[global]\n\1$1/g"
sed -i "$PATTERN" $2
}
for i in $(find $1 -name "*.v");
do
pattern "Hint Resolve" $i
pattern "Hint Immediate" $i
pattern "Hint Extern" $i
pattern "Hint Constructors" $i
pattern "Hint Unfold" $i
pattern "Hint Variables" $i
pattern "Hint Constants" $i
pattern "Hint Transparent" $i
pattern "Hint Opaque" $i
done
This is a stupid sed, so in particular it will also add a #[global] attribute to hints inside a section, which will fail at runtime. You will have to remove those attributes by hand. It will also probably miss a few hints that do not conform to the regexp, but those ones will trigger the warning.
(VERY) SLOW & BETTER
We recommend that you consider using the backwards-incompatible #[export]
attribute instead. This change will be very work-intensive, because you will need to track the uses of your hints and explicity import modules that were only (possibly silently) required before. Since importing a module also imports a lot of unrelated stuff (e.g. notations…) this will be a mess and it might need a reorganization of the library. Yet, it will result in a more modular library so this is a very welcome change. It will also affect your downstream users, because Require-scoping sucks, but once again it is a one-time investment.
Note that you can first go for the quick-n-dirty solution, then in a second time incrementally convert your library to the recommended export
locality. It will be less easy to realize that you defined a global hint though.
In Coq 8.14
Nothing.
In Coq 8.15
You will be able to remove the explicit annotation if you want. We might provide an option to do that in a more transparent way starting from 8.14.
To insist: hints inside a section are totally unaffected by these incremental changes. You don’t have to do anything for those, and actually all flags that succeed have the same semantics.