diff --git a/0000-template.md b/0000-template.md deleted file mode 100644 index 629e4e4a37e..00000000000 --- a/0000-template.md +++ /dev/null @@ -1,29 +0,0 @@ -- Start Date: (fill me in with today's date, YYYY-MM-DD) -- RFC PR #: (leave this empty) -- Rust Issue #: (leave this empty) - -# Summary - -One para explanation of the feature. - -# Motivation - -Why are we doing this? What use cases does it support? What is the expected outcome? - -# Detailed design - -This is the bulk of the RFC. Explain the design in enough detail for somebody familiar -with the language to understand, and for somebody familiar with the compiler to implement. -This should get into specifics and corner-cases, and include examples of how the feature is used. - -# Drawbacks - -Why should we *not* do this? - -# Alternatives - -What other designs have been considered? What is the impact of not doing this? - -# Unresolved questions - -What parts of the design are still TBD? diff --git a/active/0000-relative-use-mod-imports.md b/active/0000-relative-use-mod-imports.md new file mode 100644 index 00000000000..5e7438cab5f --- /dev/null +++ b/active/0000-relative-use-mod-imports.md @@ -0,0 +1,101 @@ +- Start Date: 2014-06-01 +- RFC PR #: (leave this empty) +- Rust Issue #: (leave this empty) + +# Summary + +introduce ```use mod ...;``` (or ```import ...;``` ) as a simultaneous import and 'use', with relative module paths, which have a 1:1 mapping to relative filename paths. + +``` use mod foo::bar::baz``` brings in module foo/bar/baz.rs & uses' bar. + +Creates a graph of imports between files as in other module systems, but still mounts modules heriarchically, mirroring the directory tree. + +```use mod``` brings a module into scope along with the hint: "this module is an actual file" + + + + +# Motivation + +## avoids repeating information + +This idea exploits coherence between the module heirarchy and the filesystem directory tree - but it *assumes* this coherence, instead of relying on the user to manually *create* it with 'mod.rs' files. So the information you give when 'bringing things into scope' should be enough to specify what to load. + + +## versatility for compile units + +Consider moving between the extremes of one compilation unit per file, vs an entire project as a single compilation unit - with the existing use/mod behaviour, you would have to refactor how modules are brought in and how components are referenced. + +a faster debug build with less inlining might be possible with smaller translation units; or you want to switch to a single translation unit (like C++ unity builds) for the maximum optimization possible. + +Relative paths would allow greater flexibility when wanting to treat project subtrees as seperate libraries, or vica versa. eg. for building examples demonstrating components of an SDK, or a single source tree building a suite of tools. + +A build system would be at liberty to cache any appropriate subtree equivalently to a library crate with no pre-planning on the users' part. + + +## shorter learning curve +The seperate absolute and relative paths, and mod / use statements are a tripping point for new users. Under this scheme, you only see relative paths, and you only need one statement 'use mod '. + +eliminates the need to create seperate ```mod.rs``` files within directories. Each file would do the job of mod.rs specifying further files to bring in. + +## parallelize --test +This might be useful for compiling tests, eg it would be theoretically possible to start at any individual file and test it, in isolation from the whole-project build. So building for test could be done across more cores. + +## tooling +with a project setup this way, a tool can locate definitions starting at any 'current' file and spidering outward. While working on a project, one may have source from different component libraries open; Under the current system, each of which would have different addressing scheme, relative to its own crate root. Under this scheme, a tools needs to know less about the whole project to give consistent help to the user. + +# Detailed design + +```use mod``` would look for a file relative to the current file. + +given some source files: + + foo.rs + bar.rs + baz/qux.rs + ../qaz.rs + +from ```foo.rs,``` the following statements + + use mod bar; + use mod baz::qux; + use mod super::qaz; + +would add ```foo.rs, bar.rs, baz/qux.rs, ../qaz.rs ``` to the project (eg, baz::qux is like saying 'load baz/qux.rs'), and make ```bar::,qux::,qaz::``` available as qualifiers within foo.rs . + +This would work regardless whether ```foo.rs``` was the crate root or further down the tree. + +Further ```use``` statements could give shortcuts to individual symbols, and longer paths could be written to access subtrees of these modules. + +Each individual file would in turn be able to bring in its own relative files - starting from the project root, the build system would spider outward. + +eg if qux.rs contained the statement ```use mod super::super::qaz;``` , ```../qaz.rs``` would be brought into the project, although 'foo.rs' would still need an additional ```use super::qaz``` to reference symbols in ```qaz.rs```. + +## use mod between siblings +Symbol paths would always reflect the directory-structure: - when a series of siblings reference eachother, one would not be able to follow this graph to reach symbols. eg if there is a relationship a.rs->b.rs->c.rs but they are all in the same directory, there is no path ```a::b::c```, just seperate ```a:: b:: c::``` + +##submodules wthin files +mod {...} within a file would still be available - this is where the module heirarchy can differ from the file layout, but its assumed every file must be referenced explicitely by a ```use mod``` statement. (submodules would be reached with additional ```use```'s + +## use vs use mod +if it wasn't for the existence of submodules, would it be possible to infer load information entirely from relative use directives, and individual qualified symbols ? However this system relies on "use mod" as a hint, "this module is a file" + +# Drawbacks + +The behaviour of the standard library prelude might not seem as consistent with this scheme. + +Replicates functionality available with use, mod and #[path=...] directives, and is a slightly different mentality to the existing system. + +Might look more complicated *when used alonside the existing system* (even though its' intended as a replacement, it would require a rolling refactor) + +heirachical 'use' paths have their own problems. When moving sources up or down the directory tree, refactoring would still be needed; Rust supposedly already moved from relative to absolute. + +If this was to replace the existing use/mod behaviour, one might need references to a long string of ```use mod super::super::super::...::main``` statements to refer to symbols relative to the project root. + +perhaps the tree flattening effect of explicit crate files which are them imported into a project root is desirable. +(under this scheme, *every* source file that wants to refer to a particular crate conveiniently would have some ```use mod super::super..some_major_module_that_would_currently_be_a_crate```) + +if modules down the graph did import files earlier in the tree, the tool would have to warn you about this and possibly dissalow when you compile a subtree as a library crate. + + + diff --git a/text/infer function signatures from trait declaration into impls.md b/text/infer function signatures from trait declaration into impls.md new file mode 100644 index 00000000000..307f74ab919 --- /dev/null +++ b/text/infer function signatures from trait declaration into impls.md @@ -0,0 +1,113 @@ +- Start Date: (fill me in with today's date, YYYY-MM-DD) +- RFC PR #: (leave this empty) +- Rust Issue #: (leave this empty) + +# Summary + +Allow the ommision of function parameters and return types, in the implementation of a trait for a type; +Infer this information directly from the trait declaration. + +# Motivation + +Rust signatures can become quite heavy with nested angle-bracketed types, trait-bounds, lifetimes etc, +Also,coming from C++, the need to write (and reference) traits *before* you can write 'overloads' comes as a shock, +especially for people trying to escape the repitition of 'header files'. + +(Furthermore, the types are in a different location ```type argname``` vs ```argname:type``` .. although more logical there is a cost to any reading convention-switch ) + +However, if the trait was used to *avoid* repeating information, +they would come across more obviously as a virtue: +You would leverage the trait name to specify many detailed signatures. + +Note that this would not make writing the implementation any harder:- + +Unlike with general purpose whole-program inference , constraining is already implied (unambiguously) by the trait itself; +The compiler already knows that one must match the other, and when it doesn't it reports an error. + +Compared to C++, Rusts syntax allows the ommision of types whilst still parsing parameter names in a straightforward manner, +creating this opportunity. +The lack of overloading *within* a trait/impl means there is no need to write the types to disambiguate the functions; +you would be fully leveraging the trait name to do that. + +Behaviour of this type can be seen in the Haskell language, i.e:- + + class FooBar f where -- typeclass definition (roughly = Rust trait) + foo::f->i32->[i32]->String -- only write function signatures + bar::f->[String]->String->Maybe String + + instance FooBar Apple where -- typeclass instance (roughly = Rust impl) + foo s x y = /*..1..*/ -- only write the argument names and function definition + bar s z w = /*..2..*/ + + instance FooBar Banana where + foo s x y = /*..3..*/ -- only write the argument names and function definition + bar s z w = /*..4..*/ + + +(/*..1..*/ etc denote function definition bodies) + +Surprisingly, coming from C++ (where familiar users read ```Type argname```), a seperation into 'just types', and 'just names' is actually easier to adapt to (the absence of a detail, rather than the detail being in a different place) + + +The trait is still usually very easy to find - thanks to Rusts syntax, declarations are easy to grep for. + +# Detailed design + +by example: the proposal is to allow the following to compile +(```/*..1..*/``` etc denote the function definition bodies roughly equivalent to the pattern above) + + struct Apple(i32); struct Banana(String) + trait FooBar { + fn foo(&self, x:i32, y:Vec)->i32; + fn bar(&self, z:&Vec, w:&String)->Option; + } + + impl FooBar for Apple { + fn foo(&self, x,y){ /*..1..*/ } // no need to repeat :i32 :Vec ->i32 + fn bar(&self, z,w){ /*..2..*/ } // no need to repeat :&Vec , :String -> Option + } + + impl FooBar for Banana { + fn foo(&self, x,y){ /*..3..*/ } // no need to repeat :i32 ->i32 + fn bar(&self, z,w){ /*..4..*/ } // no need to repeat :Vec , :String -> Option + } + +Trait definitions are easy to grep, but to further streamline locating them, a "File:line: -see definition of " styl error message would tend to bring these into the text-editor as the user steps through error messages in the usual edit-compile cycle. + +## concern about return values + +A variation would be to require a trailing placeholder ```->_``` to make it clearer if there is a return value + + +# Drawbacks + + +One potential objection is that you can no longer see the types when you read the impl. + +However, whilst engaged in the compile-edit cycle, the compiler can directly report what the types should be, +if you make an error; +also the programmer *must* have the trait documentation or original source at hand +(or gain enough guidance from the error message) in order to actually write the implementation in the first place. + +as far as users go, refering to the trait should suffice; there may be example code close to the trait decl; +trait implemenations are easy to search for, thanks to rusts syntax. *RustDoc* already gives browseable reference; trait declarations are very easy to grep for, and future IDE tools may have other interactive assists. + +As such , this should not be a problem - even for cross-module implementations + + +# Alternatives + +* allowing more general whole-program inference; +* another way to streamline the number of mental steps when writing trait 'impls' +would be to swap the trait/self-type order as this is more coherent with the function declarations themselves +(no need to mentally swap them back and forth), as well as 'trait object casting' (type as trait) +and disambiguation syntax ::method_name() ; +this would be the subject of another RFC (a very different request aimed at an overlapping scenario) +It would be an alternate declaration syntax complemeting the existing one. +impl type as trait {..}, or impl type:trait {} It would complement this suggestion. + +* Getting back to the expectations from C++, if writing the types out, one might expect the reverse: that the language could infer which *trait* is being implemented, allowing that to be ommitted; unfortunately this goes against the idea that the trait is part of the function's namespace. + +# Unresolved questions + +What parts of the design are still TBD?