-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
[POC] Syntactic redirection of identifiers as a way to move libraries forward #2102
Conversation
I've added a commit (not to be merged with this PR!) to illustrate the concept. The stdlib is adapted for changes in Hashtbl.S.{find, find_opt, find_exn}, but not the compiler code base itself (which indeed makes use of Hashtbl.S.find). It can still be built by compiling it with STDLIB=4.07 through a simple addition to the build system (and one gets warnings on the console to show rewritings that happen under the hood). |
| _ -> failwith "Invalid condition" | ||
end | ||
| Ident id -> | ||
begin match Sys.getenv_opt (String.uppercase_ascii id) with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefix id
with OCAML_REDIRECT_
(or OCAML_REDIRECT_VAR_
or something else)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, or rely only on OCAMLPARAMS (that's what I meant by "this UI would need to be changed to something better"). Remember, this is only a proof-of-concept. Currently, the reactions from maintainers on the overall approach (here and on caml-devel) look rather negative, so I don't intend to put more time on it.
I do prefer this solution to the alternative of providing code-transformation tools that will mechanically upgrade a codebase. The reason is that it puts less pressure on the need for carefully versioned releases in opam that have all the constraints on ocaml versions exactly correct. With this solution, a single codebase can compile in multiple versions of OCaml, and reduce the pressure on our publishing infrastructure (the constraint solver, and so on). A second benefit to this approach is that it plays very well with Dune monorepos that embed lots of code into a single tree. With that approach to vendoring OCaml libraries, we do not need opam in the build path of development (reserving it for the publishing part). However, a downside to Dune vendoring is that we have to select a specific version of the OCaml compiler to vendor code against, since we no longer have an |
Thanks @avsm for your feedback.
Do you have specific past examples in mind? It seems to me that we have been historically very conservative in renaming components of the stdlib. "Subtle" breakages, such as code relying on Also: do you think the mechanism could be useful for other libraries as well? |
@alainfrisch WRT to other libraries: I'm quite sure that this feature would have made Lwt's recent breaking changes quite a lot smoother. @aantron would probably be a better judge. |
I wouldn't use this over existing deprecation in Lwt. Keeping in mind that some users of any library are other libraries that need to compile against multiple versions:
This may help slightly in some corner cases, but I can't think of a problem this solves that can't be solved about as well using existing features. Meanwhile, the cost of this feature is:
Dragging build systems into this process seems like a big conflation. |
How would you currently address the desire the rename say (One possible answer is that such renamings are only done in well-identified major versions, which come with other changes that wouldn't be dealt with the current proposal anyway. This might be the main difference with the stdlib, for which we don't really allow ourselves any major breaking version.) |
See ocsigen/lwt#293, "Semantic versioning; safely breaking Lwt." The short version is:
Then, we do a major version release (breakage is the only thing we do major versions for).
So, basically, we try to push all the users (libraries and applications) forward gently during a period of time, and give one upgrade path that is extremely simple: blindly replace Of course, it's still never possible to link libraries written against APIs that changed between Lwt 2.x and 4.x in the same project (and opam constraints prevent this). We are not looking to support this in Lwt, however, so I wouldn't want this language feature for use in Lwt. Stdlib is in a much more complicated situation, but I would like it better if stdlib maintenance could become more similar to that of third-party libraries, than if a unique language feature was introduced for dealing with breaking it. I don't have a proposal, though. I'm not suggesting that the Lwt approach would work well for stdlib. |
I don't understand this statement. |
Thanks for the detailed explanation.
I meant: as soon as the next version in preparation comes with a "small" breakage (e.g. a renaming), it becomes hard to evaluate how much other breakages impact code in the wild, since all code in the wild needs to be adapted first to the "small" breakage. In the context of the stdlib, my concern is that any breaking change would just immediately "destroy" enough of the ecosystem that OPAM becomes basically useless as tool to assess the impact of other changes (in any other part of the core distribution), except if there is a good automated migration story which can be easily deployed in the large. |
No positive opinion on this proposal from core maintainers, so no chance it's going to be accepted. Let's close it! |
This is a proof-of-concept of a proposal to allow breaking changes in the stdlib without actually breaking other libraries. With this PR, one can change from:
to:
and most codebase written "against" the stdlib before 4.08 will still compile fine with 4.08, without any change to the code. The compiler, when resolving any call to Int32.of_string, will automatically rewrite this to Int32.of_string_exn and continue type-checking as if the user had actually written that identifier.
To enable this, one only needs to tell the compiler that the current code fed to it was written against, say, stdlib = "4.07". This is a best-effort approach and is not bullet-proof; for instance, if the code pass Int32 to a functor which expects a
val of_string: string -> int32
, this will break. But the simple approach should be enough to handle the vast majority of cases. It would also work for renaming inside modules returned by functions (e.g. Hashtbl.S.find => Hashtbl.S.find_exn).The intention is not to encourage the author of such codebase to never upgrade their code, but rather to make it possible to introduce breaking changes in the stdlib without breaking the entire ecosystem at once.
Also, all the information is available to allow automated rewriting of code against the latest stdlib; a tool could easily parse the .cmt file and rewrite the source .ml accordingly. Library authors should definitely do that when they are ready to drop support for old versions of OCaml, and library consumers can always do that locally so as not to depend on the new rewriting hack.
I want to stress that this should not be seen as a change to the language; developers would normally not specify the expected version of the stdlib when developing the library. The information could for instance be added by OPAM package maintainers to unbreak existing libraries.
People on caml-devel suggested that this method could be implemented by an external tool, but in essence, the tool would be a compiler driver with an instrument type-checker extended with hooks. This is because the "redirection" needs to implement the same binding logic as the type-checker, but cannot be run as a post-processing pass (because without the redirection, type-checking fails). So in practice, I find it more convenient to implement that in the compiler directly and this will simplify the life for users. Let's consider we add to the compiler a "live" compatibility tool, without actually changing the official language.
The mechanism is actually not tied to the stdlib and could be used by other libraries facing the same challenges.
This PR is in a very early stage.
id <= "VV.VV.VV"
?[@@ocaml.redirect (stdlib < "4.08") Stdlib.Int32.of_string_exn]
.It might be useful to allow "relative paths" ("../../M.t"), or not.