-
Notifications
You must be signed in to change notification settings - Fork 123
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
Rexporting functor parameters in an instantiation #1699
Comments
It seems weird to have public/private annotations in interfaces, since interfaces are supposed to define public stuff. My thought would be that it's not, therefore, really sensible for interface parameters to be private and that there's no need to worry about that -- if you really want it to be private chances are it ought to be a parameter of the underlying module and not the interface. I think. If naming is a concern one could introduce an extra reserved (sub)module name, e.g. FWIW in ML this doesn't arise because functor arguments can only be modules, not types. So you're always doing Workaround 2. |
Overwriting a parameter name with a declaration of the same name is common, for example key and block types for a mode derived from a block cipher, or a carrier type for a field derived from additive and multiplicative groups over the same carrier type. Forward (1) could not apply to any of the growing number of use cases involving functors that import multiple and/or qualified interfaces. Challenge (1) could be overcome if importers of an instance could (through reserved naming as @sauclovian-g suggested, or syntax as suggested below) refer to (and if necessary alias) the qualified interface names that are already necessary to instantiate such functors, to "recover" the submodules and/or parameter values implementing these interfaces:
Parameter values could be recovered directly using a corresponding direct import rather than a submodule assignment:
Direct parameter recovery could grant access to individual parameters (as in #1494 and cryptol-specs #79 (comment)), and submodule recovery might also address some issues arising from generative instantiation (#1484, #1581 (comment)), where the type checker does not recognize declarations from different instances of the same functor with equivalent implementations as equivalent. This comes up, for example, when a test module reconstructs an implementation of a custom field interface (not just an instance of the primitive |
In case it is helpful, this is how OCaml modules handle the situation (assuming that references to
The only difference is that a functor argument must be named (here, I've named it Is it possible to type I tried your example in my local Cryptol and I couldn't get it to accept
|
Also, the key to deciding what the behavior 'should be' here is deciding whether or not the
If you don't unify them, the type you want to assign to |
I guess one last thought... if you don't want the user to have to type
That way, if you want to change |
I'd like to propose the approach that interface arguments would implicitly define submodules using the name of the imported interface within the module generated from the functor. We could then access these using imports.
In the case that we were using the inline
I think we could use the existing |
@glguy If I understand correctly, this proposes that imported interfaces and parameters be considered a public part of the signature for the functor. That seems like a sensible way to satisfy the requirement. I wonder about @yav 's first concern listed in the original issue:
I don't fully understand the concern, but it sounds like there may be a complication when the functor does a qualified import of an interface: That said, I still have concerns about this requirement since it makes it harder to introduce type abstraction in the future. I believe that keeping functor parameters (declared via either The issue of public/private precedent notwithstanding, I think you could support the same semantics more explicitly with ~1 LOC per |
In this case I would have the submodule exposed from the generated module be |
Consider the following example (the use of submodules is not important, it is just easier to work with a single file):
The definition of
g
is OK, but we cannot write the type signature, at least not in the style in the comment.The reason for that is that
n
is a module parameter, and its instantiation is not exported myM
.Workaround 1: Manual Export
The draw-back to this approach is that you have to make a new name (e.g.,
p_n
) and possibly duplicate stuff (e.g., docstrings).Workaround 2: Save Parameter Module
The drawback here is that things look more complex than, perhaps, they should be, and one could accidentally use the
wrong
Param
qualifier if a functor has multiple parameters.The Challenge
There are two reasons for the current design (i.e., to not make parameters available in the instantiated module):
import interface I as I
). Note that we cannot just usex
for parameterI::x
because the module might already containx
. It is also possible to import the same interface more than once.A Way Forward
Here's one possible design that could allow us to "export" functor parameters in common cases:
parameter
block is just syntactic sugar for this. This should address issue (1) above.public
/private
blocks in interfaces (and by extension,parameter
blocks). This indicates the visibility of the parameter in instantiations.Related to (2) there's the question of what should be default visibility of interfaces. The most backward compatible choice
would be to make them
private
by default (i.e., we'd basically get the current behavior where nothing is exported, andone would have to add a
public
annotation to exported parameters). The drawback of this choice is that is the oppositeof other modules, where things are
public
by default. Because of that we don't actually have apublic
keyword at themoment but, hopefully, it should not be a big deal to add this.
Thoughts?
The text was updated successfully, but these errors were encountered: