WIP: Hide bound variables marked with [@ocaml.private] from signatures#682
WIP: Hide bound variables marked with [@ocaml.private] from signatures#682alainfrisch wants to merge 1 commit intoocaml:trunkfrom
Conversation
|
I'm generally in favour of this kind of feature as it is a reasonably frequent request from (mostly internal) users. I would actually prefer it be made available for general use by giving it a proper syntax. I had in mind something like: private let ... = ...I was also thinking in terms of a general feature on all definition-style structure items (so not open and include), which also partially explains my suggested syntax. Of course this syntax doesn't allow a direct encoding of your example, where only one variable in the pattern is made private. But of course you could always do: private let x, y = ...
let y = ywhich I assume would be just as easy for ppx expanders to generate. I also wouldn't be against using an attribute-based syntax for now to get a feel for the feature first, since it seems relatively easy to deprecate the attribute-based syntax in the future. |
|
As for the toplevel I suspect the most consistent behaviour is probably to allow private identifiers to be used in later phases. I tend to think of the top-level as a slight variation of defining a giant module but with some relaxed rules for naming, and so that would the behaviour I would expect. |
|
For the record, there were private instance variables in OCaml 1.0x, with the behavior described above. I agree with Leo that if you want to make it a feature of the language, then it had better have a proper syntax. I would rather spell it However, I'm not sure I see the connection with the bugs you describe. For signatures alone, it should be sufficient to have mechanism that avoids printing some declarations when using |
The bugs are related to instrumentation tools (Bisect, Landmarks) that need to bind one identifier for the scope of the current unit. Basically they add a declaration: let __foo__internal__ = ...on top of each compilation unit, and then rewrite its body to insert reference to this identifier. This goes well until people write: where Yes, this is a problem with these tools, not on programs using them. But what is the proper solution? In both cases, we change the name of the synthesized identifier to contain a unique enough stamp. I believe that taking the digest of
Probably, but how to make an identifier non overridable? Actually, this might suggest an alternative to this PR: since the problem is related to
At least two problems:
|
Fair enough, I'm generally the one advocating against the use of attributes for features that impact type-checking ( I'm only a bit concerned by changing the Pstr_value constructor in the Parsetree (thus breaking syntactic tools). If we do such a change, one should probably either change the current rec_flag into a record type for later extensibility; or switch the constructor to using an inlined record (also for its value_bindings). Note that it would even simpler to support an entire group of let bindings to be made private rather than a per-variable choice as in the PR.
Meaning that the private marker would be ignored altogether, or would there still be some (less obvious) impact? |
SML has an even more general approach here: you can write local
decs₁
in
decs₂
endto make the declarations Adding local
let g₁ x = e₁
let g₂ x = e₂
in
let rec f₁ x = e₃
and f₂ x = e₄
endIt's possible to achieve the same thing in current OCaml using an awkward tuple binding for |
Allowing to hide e.g. type definitions would be useful, but it is more complex than hiding value definitions, since one must ensure that the types can be erased without breaking the well-formedness of the residual signature (giving an "would escape its scope" error otherwise). Do you know if this can be handled easily with the existing level-based scoping machinery in the type-checker? |
|
Couldn't be translated into something like: include (struct decs1 decs2 end : sig include module type of (struct decs2 end) end)which would handle all scoping issues automatically ? |
|
@nojb: However, something like this might work: include ((functor (X: module type of struct decs1 end) ->
struct open X decs2 end)
(struct decs1 end))(except, as usual, this can't be a purely syntactic transformation because it needs a fresh name, and resolving scopes needs type information) |
|
@alainfrisch : Concerning the hiding of type (and module) definitions, that's a question that already arises when typing functor applications (see examples below). The Example: the effect of functor Sometimes it can be done, other times it cannot: |
|
A possible alternative to adding let private x = e₁
let private y = e₂could be written like this open struct
let x = e₁
let y = e₂
endand local
decs₁
in
decs₂
endcould be written like this include struct
open struct decs₁ end
decs₂
endThe treatment of module and type identifiers would be the same as for uneliminable functor arguments. Are there any obstacles to such an extension? |
include struct
open struct decs₁ end
decs₂
endWhat's the use of the |
Without it, |
Yeah it would be ignored in the toplevel.
As Xavier said, I would expect |
It is worth noting that, thanks to the somewhat broken nature of |
Ok, that's for emulating let private x = ....would simply be written instead: open struct let x = ... end |
|
I don't mind |
|
(I also would still like to have |
|
Yet another alternative would be to support only |
Thanks @xavierleroy. I've created a branch to experiment with private module declaration (and opened #683). |
|
The idea of having a shared local scope between global functions is intriguing. I've often wished for such a thing, when some local functions become useful to more than one global function and I'd rather not make the local function global. It's also the best way to use global mutable state -- by limiting its scope to only a few select functions. It'd be nice if the syntax for this wasn't convoluted. |
@xavierleroy Do you stand by this position? If so, I guess this would exclude more general proposals by @yallop and @lpw25. Would the softer original proposal (or #683), based on attribute (no proper syntax) and advertised only as an extension intended for ppx developers (not an official language feature), be acceptable? |
|
@alainfrisch I like |
|
I like both Is the only way this can be integrated into the language if it survives a developers' meeting before a new version? That doesn't seem fair to small but very useful changes such as this, which don't make the cut for the agenda. Why not expand the language with these useful tools? Or even better -- insert them as part of the 'beta features' section of the language (something I've suggested before) which aren't guaranteed full future support. If they take off, we can keep them. For the record, I recommend placing all new features in a 'beta features' section, so we don't bind ourselves for all of eternity to features that don't work out or remain unused, and so that we don't remain overly conservative about accepting new ideas. |
Remove set_of_closures_symbol_ref etc.
…ges (ocaml#682) Co-authored-by: Sabine Schmaltz <sabine@tarides.com>
Not ready for merge!
This is a first proposal to address http://caml.inria.fr/mantis/view.php?id=5764 by providing a way to specify that some non-local let-bound pattern variables should not be exposed in their structure. This is done by detecting a special attribute on pattern variables (the lhs is used in case of or-patterns):
For instance in
outside
M, onlyyexists.This is not really intended for end-users and more for ppx or other code generators that need to insert declarations for internal uses which should not be exposed in inferred signatures. (See LexiFi/landmarks#2 for a recent case where such a feature would have been useful.)
This PR is to discuss the general idea.
The current implementation is not very satisfactory, because it parses the attribute potentially multiple times. A better approach would probably to add to the
Tstr_valueconstructor an explicit list of "public" identifiers, rather than recover it from analyzing its patterns. The logic to parse the attribute would then be nicely located inTypemod.What to do in the toplevel is not completely clear. Should private identifiers be usable by later phrases?