Skip to content
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

Add missing interfaces #11288

Merged
merged 40 commits into from
Jul 1, 2022
Merged

Add missing interfaces #11288

merged 40 commits into from
Jul 1, 2022

Conversation

shindere
Copy link
Contributor

@shindere shindere commented Jun 1, 2022

Studying the build system shows that the list of warnings used to compile
the different components of the compiler is not always the same.

That made me curious about which warnings we really need an which we don't.

Thus, the first commit in this pull request, which is not intended to
be merged, reveals all the warnings.

On this basis, I started to try to eliminate the warning about missing
interfaces. It may look useless to fix warnings, but the idea is that
if a state is reached where a warning does not appear any longer,
then we can re-enable it and that warning can become useful again
to test the quality of code that will be added after it has been enabled.

So, the core of this pull request, which does intent to be merged
once completed and cleaned up, consists in adding .mli files.

At this stage, only 3 occurrences of warning 70 remain, in the
native backend, for the modules arch, CSE and branch_relaxation_intf. The
last commit is a failed attempt
to disable the warning for branch_relaxation_intf.

Since this attempt does not work, would it be okay to create
an interface, although it will be redundant with the implementation?

Another approach would be to leave this module as is, since
the future rules used to build the compiler will have room for
per-module flags, so it will be possible to pass compiler-specific
options to the compiler. But that would still be an irregularity.

Regarding arch and CSE, I started to look at the different interfaces
and, although there seem to be some differences, it may still be
possible to come up with a common interface. If that's okay I would be
happy to investigate in this direction.

Ultimately, this PR could conclude with a commit re-enabling warning
70, and then other warnings could be fixed and re-enabled in the same way.

Of course the goal here is not to fix all warnings. Warning 4, for
instance, does nhot look like a warning one may want to fix in a
systematic way.

@xavierleroy
Copy link
Contributor

OK, I'll bite:

What's wrong with .ml files without .mli interfaces?

I know some people don't like that and that's why we have an optional warning for this, but in the context of the core OCaml system I don't see much harm.

@shindere
Copy link
Contributor Author

shindere commented Jun 1, 2022 via email

@bluddy
Copy link
Contributor

bluddy commented Jun 2, 2022

I do wish there was some other way to indicate private and public elements of a module. OCaml has a schizophrenic approach here. Haskell and Rust require signatures on their functions, mostly because of their inability to infer sufficiently. OCaml insists on only allowing types that can be fully inferred by default so you don't have to annotate anything, and yet 'good practices' requires writing out the full types, in a separate file, no less (requiring synchronization). Maybe I wouldn't mind it so much if I could just mark a function with [@@export] and let the compiler update the signature in-place in the mli for me. But then again, if I could do that, why not just use the annotation to specify the interface without an mli file?

@xavierleroy
Copy link
Contributor

It's an invitation to write specifications and to have a clear distinction between what's private and what's public.

I agree 100% for library modules or application modules that have a well-defined interface (pun intended!) with the rest of the application. But, to take an example, ocamldoc doesn't fit this pattern and will probably be replaced by something else before anyone writes any documentation on its modules. Just adding a .mli containing the output of ocamlc -i doesn't help much by itself.

@shindere
Copy link
Contributor Author

shindere commented Jun 2, 2022 via email

@shindere shindere force-pushed the add-missing-interfaces branch 4 times, most recently from b7bf0e9 to c390476 Compare June 16, 2022 15:12
@shindere
Copy link
Contributor Author

The code has been rebased and updated and the story has been made
complete and (hopefully) coherent, so this PR is now ready to be
reviewed.

It consists of 40 commits. The first commit enables warning 70 about
missing interfaces so that all warnings of this kind can be seen. The 38
next commits introduce
the missing interfaces. Finally, the 40th commit turns warning 70
into an error.

Regarding ocamldoc, the introduced interface files have been minimized.
This allowed to detect a few unused values, types, constructors and
exceptions that have also been removed (many thanks to @Octachron for
having pushed me to go beyond the automatically generated interfaces,
the result feels much more satisfactory that way).

Regarding the motivation of this PR, interface files become
useful in the context of out-of-source-tree builds and also make
it possible to parallelize builds evenmore.

Regarding out-of-source-tree builds, is a module has no interface file,
then compiling its implementation will produce a .cmo file
which will be added to the build tree but, if no care is taken, the .cmi
file produced as a side-effect wiill go to the source tree.

It would certainly be possible to extend the compiler's build system
to take special care and put these .cmi files generated while compiling
.ml files at the right place, but this would make our already-complicated
build system even more complex, for no good, it seems.

About parallel builds: one may want to build a bytecode and a native
version of a program simultaneously. If an implementaiton-only module
is simultaneously compiled by ocamlc and ocamlopt, then the two compilers
will compeet to produce a .cmi file, which does not seem desirable.

Finally, this PR revealed that we still build the cmt2annot tool
which we do not install any longer. How about getting rid of it completely?

@damiendoligez
Copy link
Member

What's wrong with .ml files without .mli interfaces?

See #10364 (comment) for an example of annoyance caused by a missing .mli.

@shindere
Copy link
Contributor Author

This is currently going through precheck, see build #714.

@shindere
Copy link
Contributor Author

Rebased on latest trunk

Copy link
Member

@damiendoligez damiendoligez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you've renamed branch_relaxation_intf.ml to branch_relaxation_intf.mli, thus getting an .mli without a corresponding .ml. Are you sure this will not cause problems down the line? Note that the dune file mentions branch_relaxation_intf as a module name.

Otherwise this looks good modulo a few typos.

Comment on lines +18 to +19
val main : unit -> unit
(** The entry point for ocamllex *)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to export main? What is the difference with driver/main.mli and driver/optmain.mli?

(** Representation and manipulation of exceptions. *)

(** This module has an implementation although it declares only types.
This is because other modules yse the let module construct ot access it
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This is because other modules yse the let module construct ot access it
This is because other modules use the let module construct to access it

(* Interface to the std_exit module *)

(* This interface file is empty because the std_exit module only runs
code during initialisation and does not export any funciton *)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
code during initialisation and does not export any funciton *)
code during initialisation and does not export any function *)

(* *)
(**************************************************************************)

(* Interface to expunge's main entry poit *)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(* Interface to expunge's main entry poit *)
(* Interface to expunge's main entry point *)

Comment on lines +18 to +19
val main : unit -> unit
(** The entry point for expunge *)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I don't understand why you need to export this.

@shindere
Copy link
Contributor Author

shindere commented Jun 28, 2022 via email

ocamldoc/odoc_test.mli Outdated Show resolved Hide resolved
ocamldoc/odoc_module.ml Outdated Show resolved Hide resolved
@shindere
Copy link
Contributor Author

shindere commented Jun 28, 2022 via email

@shindere shindere force-pushed the add-missing-interfaces branch 2 times, most recently from 6ddb974 to 1e6e32f Compare June 28, 2022 14:11
@shindere
Copy link
Contributor Author

shindere commented Jun 28, 2022 via email

This commit also removes the unused graph type.
This commit also removes two unused value declarations from the module.
This commit also removes a few unused values, one unused type constructor
and one exception from this module.
@shindere
Copy link
Contributor Author

Following an off-line suggestion by @dra27 (thanks!), I checked that all the
added interfaces get installed correctly by make install when they should.

For those interfaces outside of the ocamldoc directory things were
already working, but it was not the case for the ocamldoc interfaces.

The commits have now been installed to install most of them.

Those which are not installed are odoc.mli which is empty, likewise
for odoc_test.ml and those of the two generators, odoc_todo.mli
and odoc_literate.mli.

Copy link
Member

@Octachron Octachron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I rather like to have interface file available in a fully uniform way.

The most thorny changes are the new interface files for ocamldoc's generators which are half-public interfaces which were never written explicitly. Consequently, preserving backward-compatibility for ocamldoc generators make those interface files quite messy. However, the current state of this PR does seem like a seem sensible compromise to avoid pouring too much effort and time on ocamldoc.
I am thus also approving this PR.

@shindere shindere merged commit 97bfe6d into ocaml:trunk Jul 1, 2022
@shindere
Copy link
Contributor Author

shindere commented Jul 1, 2022 via email

@shindere shindere deleted the add-missing-interfaces branch July 1, 2022 13:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants