Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upParametrise modules #424
Comments
nrc
added
the
postponed
label
Oct 30, 2014
This comment has been minimized.
This comment has been minimized.
|
I want this all the time when writing lots of generic code. |
This comment has been minimized.
This comment has been minimized.
eternaleye
commented
Apr 3, 2015
|
Massive agreement here. |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Mar 31, 2017
|
I missed this issue and posted another version here https://internals.rust-lang.org/t/implicit-module-arguments/5022 In effect, I'm wondering there if modules could perhaps not use the usual Rust type parameter syntax but instead refer to items like types in the scope using them. These are parameters would be viewed as implicit instead of explicit. You read the scope to determine the module's parameters, not the call site. The reason for making module parameters implicit would be that they are usually library configuration parameters. We want them out of the way so that code does not read as overly generic. It might resemble :
The bad part about this |
This comment has been minimized.
This comment has been minimized.
eternaleye
commented
Mar 31, 2017
•
|
@burdges: I think your proposal conflates things, in a way I find rather problematic.
In short, I think that proposal would not work out well at all, and strongly prefer:
If module-level parameters are merely a shorthand for additional parameters on the items of the module, the latter can be left to later, and eventually defined as a similar shorthand for setting those parameters. EDIT: Ah, I'd missed your "use whatever's fitting in-scope" bit. That's the least workable part of this, IMO - it's akin to Coq's curly-braced parameter declarations, which really only work because Coq is a proof assistant, and can provide incredibly detailed bounds on them. Without that, I suspect they'd be the next thing to useless, because an unbounded type parameter could be satisfied so many ways it's absurd. |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Mar 31, 2017
|
As I posted in the internals thread, I think I agree with @eternaleye that implicit passing should be skipped. There are no soo many use lines that this will make anything awkward. In any case, I do like the idea of type and constant parameters for modules. I mostly just wondered if this would be an opportunity to do something implicit really well. |
This comment has been minimized.
This comment has been minimized.
|
Perhaps this paper would be of use? It brings parametrized modules to Haskell: |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Apr 3, 2017
•
Or look at how OCaml does it (especially soon-coming implicit module support), which does first-class modules in a way that is perfectly efficient at run-time and compiles significantly faster than HKT's while supplying the entire power there-of (and far more, OCaml's HPT modules can do many things that HKT's cannot). An OCaml-like first-class module system would pretty well fix most (all?) of the remaining higher typing problems in rust. |
This comment has been minimized.
This comment has been minimized.
eternaleye
commented
Apr 3, 2017
•
|
@OvermindDL1: ML-style Functor-based modules have problems of their own; a significant motivation for Backpack was providing a similar level of power while avoiding those downsides. It's based on an earlier work by the same authors, called MixML, which entirely subsumed the features of ML-style modules. |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Apr 3, 2017
•
OCaml's modules are not as limited as SML modules and although I've done a cursory glance over the MixML documentation I was not able to see what it gained (other than the examples being slower to compile). Over standard ML modules MixML seems to add recursive module definitions (which can be done in OCaml already) and mixins (already supported in OCaml), however OCaml supports a great deal that ML/SML do not support, including going far beyond MixML, those being that I can name off the top of my head:
Among others that I cannot recall off hand. But overall yes MixML is higher than ML, but OCaml is much higher still, and OCaml's module design is well worth copying for 2 very very large reasons (not the syntax of course), those being compile-times, they were designed for being extremely easy and efficient to handle especially during optimization (very large OCaml projects with large amounts of modules still only take seconds to compile hundreds of files, unlike rust...), and the second being that they grew up based around necessity, it is not a Haskell'ish style research project, it is a real-world language that had its features added to solve problems, regardless of what they are, and consequently it is a very well tested style of which the only down-side is syntax verboseness that Implicit Modules solves soon anyway. Also, I've not touched SML/ML itself in a decade, only OCaml for ML-style languages, so they might have some more developments as well... |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Apr 13, 2017
|
If you're module is a file, then I suppose the syntax might be |
This comment has been minimized.
This comment has been minimized.
|
I just want to note that "ML-style modules" is a much bigger feature than the "parameterizable modules" that are actually being proposed here. In particular the crucial part of "ML modules" is functors, that is, modules parameterized over modules, which (together with the ability to specify module signatures, by analogy to type signatures) allows one to express various kinds of ad-hoc polymorphism*. Allowing parameterization over modules together with module signatures would be a huge addition to Rust, especially since Rust already has its own solution for ad-hoc polymorphism (traits, a.k.a. type classes). What is being proposed is merely being able to parameterize modules over types and lifetimes, which is a considerably smaller addition, and really only goes toward "abstracting the same things, just with less typing" rather than "new and more powerful abstractions". (Although abstracting a module over a type with a trait bound, * ("Polymorphism" is maybe not exactly the right word here given that functoring is explicit, but it's used for the same things.) |
This comment has been minimized.
This comment has been minimized.
comex
commented
Apr 16, 2017
|
@glaebhoerl I'd put it a different way… Rust already supports parameterized modules and module signatures; they're called impls and traits (with singleton types). If more expressivity or sugar would be needed to make them as useful as in ML, perhaps it should be added, but it should be an extension of the existing system, not its own separate thing. |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Apr 16, 2017
|
I'd think modules parameterized over constants, types with trait bounds, and lifetimes provide an ergonomic and productivity win. There are frequently parameters you do not want to focus on in a first pass, so modules parameters give a "canonical easiest" way to export to them to the caller. You can achieve similar functionality with a associated types and constants in a trait for singletons or uninhabited types, but now you're invested in deciding what goes into this trait and how it should parameterize every item in your module. I suppose It'd be lovely if
In fact, if file modules supported parameters then conceivably inherent As an aside, there are nice translations in ML Modules and Haskell Type Classes: A Constructive Comparison including some explosion in complexity in both directions. In my reading, there are new "interesting" ways to obtain features from ML-style modules, but Rust already has most like privacy, namespace management, etc. via |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Apr 16, 2017
•
|
I suppose zero allocation futures rust-lang-nursery/futures-rs@0f12f1d might benefit from module parameters. @leodasvacas |
This comment has been minimized.
This comment has been minimized.
OvermindDL1
commented
Apr 16, 2017
As an aside, this seems to ignore the upcoming "Implicit Modules" coming to OCaml style ML Modules, which pretty well fix the verbosity of the witness passing in ML style modules, making them about as succinct as type classes but significantly faster to compile and better able to optimize the output code. But yes, I would definitely choose OCaml-ML-style modules over just parameterized modules as it would give a lot of safety, power, be quick to compile, and has been very well tested for decades. |
This comment has been minimized.
This comment has been minimized.
comex
commented
Apr 16, 2017
I think they should be able to. Sugar can come after that... |
This comment has been minimized.
This comment has been minimized.
jackalcooper
commented
Dec 27, 2017
|
Is there any progress on this feature? |
Centril
added
the
T-lang
label
Dec 27, 2017
This comment has been minimized.
This comment has been minimized.
|
Maybe time to revisit this issue? I have a use-case:
It's not really possible to workaround this by making everything within the back-end generic, because there are a huge number of type aliases, structs and free standing functions which would have to be made generic. I would be happy with |
This comment has been minimized.
This comment has been minimized.
|
My understanding is that this is fundamentally incoherent and so can't happen. Could be wrong though! |
This comment has been minimized.
This comment has been minimized.
|
@steveklabnik what makes you say that? Generally coherence is only a problem cross-crate, but there's only one crate involved here? |
This comment has been minimized.
This comment has been minimized.
|
I don't remember the exact details, to be honest. I think @withoutboats knows? |
This comment has been minimized.
This comment has been minimized.
|
(Yeah generally |
This comment has been minimized.
This comment has been minimized.
|
How do you deal with |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Feb 21, 2018
|
I'd imagine If you later use Is there any notion of variance for items like I'd assume parameterized modules would take their own variance from the types they contain, yes? |
This comment has been minimized.
This comment has been minimized.
|
See
The idea of a module level variance seems too broad, but I like the idea of items in a module not being parametric if they don't use the module parameters or have their own parameters. |
This comment has been minimized.
This comment has been minimized.
|
I don't understand why y'all would implement this anemic attempt at module functions when you have a perfectly serviceable applicative module system in the trait system. With some minor extensions, one could use the trait system to pull all of this off, aiui, without the major extension of adding functors to the language. |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Feb 21, 2018
|
I suppose parameterized modules do not require variance anymore than traits require variance, but if you instantiate a parameterized module then instantiating particular types might become impossible. What would that look like? I suppose
becomes
We'd seemingly need:
Are those extensions all viable? I recall previous RFCs with There is yet another approach using only
which provides some advantages over traits, but runs into the |
This comment has been minimized.
This comment has been minimized.
eternaleye
commented
Feb 24, 2018
|
It's worth noting that rust-lang/rust#48411 will very likely allow "hypotheticals" to work - i.e. fn bar() {
/* SomeTrait is not presumed to be implemented */
}
fn foo() where (): SomeTrait {
/* uses SomeTrait::bar() */
}Note that the bound is not on a parameter of Hypotheticals like this are very closely related to nullary typeclasses, as well as module signatures, as a module doesn't really have a meaningful For example, mod foo {
use bar;
const X: usize = bar::Y;
}could be equivalent to: trait foo {
const X: usize;
}
impl foo for () where (): bar {
const X: usize = <() as bar>::Y;
}via a trivial desugaring that "an imported module At that point, I feel there are a number of ways the module system could be extended and empowered, all of which would effectively boil down to mere syntax sugar over traits. Adding parameters could be done easily enough, perhaps with the added requirement that parameters be specified both in the Because the desugaring would enforce that the That power could be added later, in a backwards-compatible manner, if it was found to be desirable (cough cough, global allocator backends, cough cough). |
nrc commentedOct 30, 2014
I would like to be able to parametrise modules by types and lifetimes. Type parameters are useful where many items in a module should use the same concrete type. E.g., taking some implementation as a parameter we want to ensure that all functions and data types in a module use the same implementor without annotating every item with the same type parameters. Likewise, parameterising by lifetimes is useful if we are to assume that many objects in a module have the same lifetime. This is especially useful in conjunction with arena allocation.
Details
Module declarations may have formal type and lifetime parameters and where clauses, e.g,
mod foo<X, 'a> where X: Bar { ... }.Module uses, including in use expressions which include an alias, can have actual type and lifetime parameters. E.g,
let x: foo<int>::Baz = ...;oruse foo<int, 'static> as int_foo.The usual rules around well-formedness wrt bounds, and inference would apply.