-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Private items in structures and signatures #2016
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
Conversation
|
So, I get a ton of errors from travis that seem unrelated to this PR: the location of most of the error messages in the testsuite seem to have changed but:
For example here I agree the line displayed is the 19th and not the 15th. |
|
This might be related to the Menhir bootstrap, but it's unclear how. (In theory, a menhir change that did not come with a bootstrap commit could change the locations.) I would rather make the guess that some PR recently merged broke the CI in a subtle way that is related to a trunk rebase (the PR's branch was fine, but merging on trunk breaks the tests). |
|
I initially assumed so too, but I don't think so. I took the tip of trunk, built and ran the tests (everything was fine), then did Note that applying that diff (which removes the use of diff --git a/parsing/parser.mly b/parsing/parser.mly
index cff42b8c5..36eab64da 100644
--- a/parsing/parser.mly
+++ b/parsing/parser.mly
@@ -903,11 +903,6 @@ paren_module_expr:
{ unclosed "(" $loc($1) ")" $loc($5) }
;
-%inline private_item:
- | { false }
- | PRIVATE { true }
-;
-
structure: extra_str(structure_nodoc) { $1 }
structure_nodoc:
seq_expr post_item_attributes structure_tail_nodoc
@@ -922,11 +917,16 @@ structure_tail_nodoc:
;
structure_item:
- private_item let_bindings
- { val_of_let_bindings ~private_:$1 ~loc:$sloc $2 }
- | private_item structure_item_with_ext
+ PRIVATE let_bindings
+ { val_of_let_bindings ~private_:true ~loc:$sloc $2 }
+ | PRIVATE structure_item_with_ext
{ let item, ext = $2 in
- wrap_str_ext ~loc:$loc (mkstr ~private_:$1 ~loc:$loc item) ext }
+ wrap_str_ext ~loc:$loc (mkstr ~private_:true ~loc:$loc item) ext }
+ | let_bindings
+ { val_of_let_bindings ~private_:false ~loc:$sloc $1 }
+ | structure_item_with_ext
+ { let item, ext = $1 in
+ wrap_str_ext ~loc:$loc (mkstr ~private_:false ~loc:$loc item) ext }
| item_extension post_item_attributes
{ let docs = symbol_docs $sloc in
mkstr ~loc:$sloc (Pstr_extension ($1, (add_docs_attrs docs $2))) }
@@ -1048,9 +1048,12 @@ signature_nodoc:
| signature_item signature_nodoc { text_sig $startpos($1) @ $1 :: $2 }
;
signature_item:
- | private_item signature_item_with_ext
+ | PRIVATE signature_item_with_ext
{ let item, ext = $2 in
- wrap_sig_ext ~loc:$loc (mksig ~private_:$1 ~loc:$sloc item) ext }
+ wrap_sig_ext ~loc:$loc (mksig ~private_:true ~loc:$sloc item) ext }
+ | signature_item_with_ext
+ { let item, ext = $1 in
+ wrap_sig_ext ~loc:$loc (mksig ~private_:false ~loc:$sloc item) ext }
| item_extension post_item_attributes
{ let docs = symbol_docs $sloc in
mksig ~loc:$sloc (Psig_extension ($1, (add_docs_attrs docs $2))) }I guess I just don't know what I'm doing |
|
I also don't understand how the printed location can change, but the highlighted part of the code remain unchanged. @Armael any guess? |
|
I believe that the issue comes from nullable productions and the difference between $loc and $sloc. If your rule starts with an empty symbol, the $loc location will start at the end of the previous non-empty symbol, while the $sloc location will start at the beginning of the next non-empty symbol (so it is finer-grained). From a user perspective, $sloc is essentially always better, but the current Menhir parser still uses $loc in many places, by default, to match the locations produced by the Yacc parser. If that guess is right, here is what you can do:
We may want to think about turning all $loc into $sloc globally. I believe that this is always correct from a user point of view, but it could not be part of the Menhir PR as it would have broken our correctness testing check. |
|
Alright, your guess sounds believable to me.
So, I think I'm just going to avoid using |
|
PS: thanks! |
|
I don't understand what is tedious. If I read your PR patch correctly, you touch exactly two semantic actions using $loc instead of $sloc, so you would have a commit with those two changes plus testsuite update (use |
Not really, I'd be happy to make a separate PR for just that change.
Hum, for some reason (simply looking at the locations changes in the testsuite) I assumed I would have to update all the rules used by the rules I directly modified, and the rules that they themselves use, etc. |
|
Unrelated, but an obvious question is why use |
6dbbfce to
399d124
Compare
Apparently I was. Changing the 3 relevant
Fair question! I'd be happy to flip that around. |
|
I have a preference for At some point I would really like to add support for virtual modules -- analogous to virtual classes and a way to support simple mixins in the module system. Just like with Unfortunately, as you point out, the existing class system syntax for private and virtual is already inconsistent in this regard, using both |
|
I'm trying to understand what this PR is about. I see only a reference to a paragraph in @lpw25 's blog, which has only examples of using this feature for type and module aliases in signatures, Looking at the blog, I'm not sure type tmp := t list
module M := F(X)hoping that we don't end up wanting to use this syntax for something else later. Independently of this, it would be nice to have a more comprehensive description of the syntax and semantics of this feature. |
|
So, for reference, it would allow to fix some cases of MR#6635, i.e. type alias added in |
My understanding is that
|
|
Might be worth mentioning #1506, and discussing both PRs together. #1506 was about allow open (struct
type t = ....
end)As @lpw25 pointed out, it might be better to directly express the intent of making some declarations local to the current structure (marking them as private module Foobar1234 = ...
open Foobar1234Typically, one wouldn't do that when the module expression is directly a structure; one would simply mark all its items as So let me cc @yallop, @objmagic. @trefis , @lpw25 : do you intend this PR to subsume #1506, or do you that both should be considered for inclusion? |
|
Personally I don't think that the two proposals are conflict. While they share some goals and results, they are fairly distinct language features and I think they would both have use-cases. On one hand, |
|
@gasche On the other hand, there is really no need to have two implementations. Each version can be more or less encoded in the other. This is probably going to be one of the big point to discuss if we want both: which one to implement in term of the other. I have not yet review the implementation, but from my discussion with @trefis and looking at generalized open, private items are, in a way, lower level (the implementation should do less work, especially after #1892), which might make them a decent choice for the primary implementation, and doing generalized open on top of them. |
|
Agreed, I'm personally rather in favor of including both proposals -- it's not like the OCaml globally aimed at orthogonality in its feature set. But since the two proposals come roughly at the same time and can be encoded in each other to some extent, I thought it would be useful to remind everyone about the existence of the other PR to evaluate the usefulness of both (and perhaps to discuss some possible sharing between the two implementations). |
|
@Drup: I wouldn't expect an implementation approach translating one construction into the other, but rather the two implementations sharing common utilities to ensure that non-included items do not leak out in the final signature. There is also no strong need for deciding an ordering a priori: general code can be reused, but less-general code can be factored out and reused as well by a subsequent PR. I think it's mostly a matter of people discussing the design(s) and doing thorough implementation reviews in time. (@alainfrisch started doing a review for #1506 but the current status seems stalled, it is not clear to me why and who has to pour some work next.) For both PRs, they can be merged whenever they have been approved. |
|
@gasche OK, the blog entry had no precise explanation about the behavior for structures. |
I can see what you mean, but at the same time for items allowed in both structures and signatures the feature really is the same in both places. For example, private type tmp = t
type t = intdoes the same thing in both contexts. So I think it would be strange to use different syntaxes for the two different contexts. |
|
@lpw25
This said, I do understand that the Of course this is only my opinion. By the way, maybe I should have started a discussion on you blog post. Would it be a good idea? |
Well, ideally the discussion should have started before the blog post, when I posted the same plans to the caml-devel list. |
|
Sorry, it looks like I missed this one. I think each of those should be discussed first, at least for those which introduce language or typing changes. |
|
@trefis, @lpw25 : can you elaborate on the meaning and use cases for the new feature on signature items (the blog post only mentioned structure items)? Are type aliases, class types and module types the only meaningful items to support the Concerning structure items: is |
399d124 to
7587adc
Compare
And don't include private items in the signature.
7587adc to
f4fdcb4
Compare
I believe @objmagic is planning to return to #1506 soon, to rebase the PR and incorporate feedback. |
As far as I could tell from the paper linked in #1506 they should indeed be equivalent. It's been a while since I looked at the implementation of that feature however, so I might be missing something.
I personally tend to agree with the answer given by @gasche: there is a decent amount of overlap (as discussed above), but some other features of #150 (e.g. For the part where they overlap I believe the current proposal is, currently, cleaner in terms of its implementation and leads to better error messages (no synthesized names appears).
A few things to note here:
Both @garrigue and @gasche seem to agree that this PR extends the syntax, while the I don't understand this. Both propose to give meaning to a new combination of keywords that already exist.
That is a fair point. And fwiw, I think the meaning proposed here is probably more intuitive than this one for example.
I agree that
I believe that, apart from the more precise question I replied to above, Leo already answered that point. |
Another way to put it is: if someone encounters the new construction, (1) will they notice that it is a new feature and (2) will they feel a need to consult documentation to know what it does? I'm rather confident that, while most people would recognize |
|
I see. Thanks for clarifying! Note that I'm fairly sure every one encountering So I'm not sure that argument quite holds :) |
Sorry, I cannot find any intended use cases for allowing private on signature items. @bobot mentioned the use of type aliases to simplify writing the signature, without actually exposing the alias to external code. This is a very narrow use case, and possibly a bit puzzling for users (they see a type alias in the documentation of a library but cannot use it, and the compiler complains as if the alias did not exist at all). Are there other use cases? |
|
One example is shown in the blog post (and discussed in more details in section 3 of the module type S = sig
type t
module Sub : sig
private type outer = t
type t
val to_outer : t -> outer
end
endOf course, as Jacques noted, this can already be expressed using destructive substitution: module type S = sig
type t
module Sub : sig
type outer = t
type t
val to_outer : t -> outer
end with type outer := t
endIt's just a bit lighter with Btw, I do not agree with @bobot that the aliases in module type S = sig
type t
module Sub : sig
type t
val to_outer : t -> t
end
endwith links the links pointing to the right Anyway, that's a discussion for another day, on another bugtracker. |
|
This PR was discussed today at the caml-dev meeting. Conclusion:
|
|
Cf. #2122 . |
This GPR implements the change described in https://blog.janestreet.com/plans-for-ocaml-408/#private-structure-items.
Some notes about the implementation:
%inlinerule! (One gets 11 shift/reduce conflict without it.)Types.signature, the overloading of the name is unfortunate). One could have also chosen to include them but mark them as private.The chosen implementation has several benefits:
Includemodis required.