-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Specifications can be terser through more type trickery #456
base: main
Are you sure you want to change the base?
Conversation
This is excellent Olivier, thanks a bunch! 🙏 As much as I love and agree with the benefits and in particular the added safety, some of the additional user-input required sticks out to me, e.g., the
At the same time, as an end-user I probably don't want to care for such a I'm not too concerned about breaking the API at this point, if we can arrive at something nice.
|
I would also love to sweep the existential under the rug, but this seems to me to clash with the fact that the spec writer needs to write a command generator. Since, as you say, the typechecker needs to unify all possible command types there. Perhaps we could hide it in a function similar to |
In the latest commit, the existential type is hidden behind a module with a nicer interface. The new compromise is that the sure must instantiate a small functor—see the new The result is maybe syntactically closer to the existing, and hopefully the user does not have to deal with the cryptic error messages that GADTs can give. |
A good news is that the same tricks (not implemented in this PR, but I have it on the side) allow to get rid of the calls to Lines 422 to 427 in c993045
without changing the tests that use the high-level Lin interface in any way. Tests that use Lin.Internal do have to be adapted (in much the same way as in this PR), but given the unstable nature of that interface, I feel this will be less of an issue.
|
As I was writing an STM specification for Dynarrays, I was a bit frustrated to have to add a catch-all
assert false
at the end ofpostcond
. So I went into an over-engineering rabbit hole and found that it can be avoided by making thecmd
type of specifications a GADT, which allows to specify the result type for commands. The typechecker is then able to deduce the result type when pattern matching on commands.As an example, I have rewritten
src/atomic/stm_tests.ml
to match the newSpec
signature.This has a number of benefits and some drawbacks.
Benefits
run
function, results no longer need to be wrappend into theRes
constructor. However, it is still necessary to also return an instance of'a ty_show
; I have not found a simpler way to make the results printable.postcond
function, it is no longer necessary to match on patterns likeRes ((Result (Int, Exn), _), v)
for the typechecker to deduce the right type forv
: the command name suffices. It is also no longer necessary to add a catch-all_ -> assert false
at the end.run
are safer because the result type is checked.Drawbacks
Defining a GADT in the specification adds its own boilerplate: most functions now need explicit type annotations with universal quantifiers; the user must also define an existential type
packed_cmd
and wrap the command generators in it. Such STM tests are harder to write when one is not familiar with qcheck-stm.And of course, another big drawback is that it changes the signature of STM specifications.
For these reasons, I open this PR as a draft, mostly to share the idea.