Uh oh!
There was an error while loading. Please reload this page.
RFC to require impl MyStruct to be nearby the definition of MyStruct - #155
Conversation
adrientetar
commented
Jul 5, 2014
SiegeLord
commented
Jul 5, 2014
I have found this feature useful in my library to encompass the state of a foreign library and do dependency injection in a clean way. Here's a snippet of how its used: mod a
{pubstructBitmap{priv_field:()// note this field}implsuper::Core{pubfncreate_bitmap(&self) -> Bitmap{Bitmap{priv_field:()}}}}pubstructCore;implCore{pubfninit_library() -> Core{Core}}fnmain(){let core = Core::init_library();let bmp = core.create_bitmap();}I suppose I could work around this by using a macro that looks like this: mod a
{pubstructBitmap{priv_field:()}pubmod export
{cross_impl!{implCore{pubfn create_bitmap(&self) -> Bitmap{Bitmap{ priv_field:()}}}}// Expands to:/* pub trait _AnonTrait_XXXXXX { fn create_bitmap(&self) -> Bitmap; } impl _AnonTrait_XXXXXX for Core { fn create_bitmap(&self) -> Bitmap { Bitmap{ priv_field: () } } } */}}pubuse a::export::*;pubstructCore;But if I can do this via a macro, what prevents the compiler from doing it? |
apoelstra
commented
Jul 5, 2014
@SiegeLord if you add any static methods to your If you use non-anonymous traits as described, you cannot have static methods that are accessible as Edit: I think it doable to simply prevent static methods in Edit2: If we were to take this approach, the pretty error messages would be missing in the currently-broken cases, which would still be a bug, though a minor one. |
There was a problem hiding this comment.
I realized this has nothing to do with typeck, that's just where "module instead of type" is noticed. The reason that Vec in impl<U: T> Vec<U> resolves to a module here rather than a type is in Resolver::def_for_namespace(), which is eventually called from Resolver::resolve_crate(), the final function call of Resolver::resolve(). (The purpose of resolve_crate() is to go through once every struct and impl has been seen to resolve things completely.)
The way that def_for_namespace() works is to try and return a DefType first, which it will only find if the type Vec had been defined somewhere. Failing that, try and return a DefMod, which will be defined if an impl Vec or struct Vec had occured somewhere. Failing that, return None.
Notice that at no point are imports used when resolving Vec. This could happen when resolving Vec::from_slice() later on, in Resolver::resolve_module_path(), which first tries to find Vec in the current module, then failing that, resolves imports. (In fact this would not happen, since Vec would be found in the current module, as a module rather than type, thanks to the impl Vec and the anonymous trait module it creates.) But this doesn't even have a chance to happen, since, resolve_module_path() is never called when resolving impl Vec; impl blocks and functions become different beasts during the initial build_reduced_graph() run, so different code paths are taken in resolve_crate(). (And this makes sense, since when resolving impl Vec in resolve_crate(), we know that Vec will is in the module because we added it in build_reduced_graph() as an anonymous trait module. So there is no point in resolving imports.)
apoelstra
commented
Jul 6, 2014
@SiegeLord I notice that in Edit: In fact, I don't think there's a way (short of seriously refactoring resolve) to handle static methods for anonymous traits on elsewhere-defined structs. And I don't want to say "only non-static methods on impls, unless the struct is defined in the same file" because that's an extremely specific rule to memorize and clearly originates in compiler limitations. Let's not be like certain other languages which have a bajillion such rules :) My feeling for simplicity's sake is to go with the original RFC, sans the " |
sfackler
commented
Jul 7, 2014
👍 Even if resolve handled it well, I think it'd be best to restrict anonymous impls to the defining module. |
dobkeratops
commented
Jul 7, 2014
I'd be interested in a move in the opposite direction .. fewer restrictions on what can be impl'd where, and the option of duck type interfaces to cut down on the noise when dealing with single function traits |
…tion of `MyStruct` This fixes #15060 and rust-lang#3785.
apoelstra
commented
Jul 7, 2014
Pushed changes which fix my own line comments (remove requirement to have |
apoelstra
commented
Jul 7, 2014
pcwalton
commented
Jul 9, 2014
+1, language simplification. |
apoelstra
commented
Jul 9, 2014
I'm happy to implement this if it gains support. There are two new error messages to be added:
We can detect if I'm no good at bikeshedding, so can I get some suggestions for these? |
nikomatsakis
commented
Jul 24, 2014
I am of mixed minds. On the one hand, this is the conservative choice, works around the various resolve bugs, and can easily be extended later. It also seems to satisfy a sort of encapsulation concern, in that it kind of makes sense for "inherent methods" to be defined close to the type in question. On the other hand, I think it is frequently useful to be able to split apart the methods on a type. @SiegeLord brings up an interesting usage I hadn't considered. I frequently find I want to define a core type and then define methods related to (e.g.) type checking in the type checker and other things somewhere else. On the other other hand, both of these use cases can readily be accommodated with traits. One specific concern I have is that violates the rule of thumb that if an action is legal in module M, it is legal in submodules of M. I think this is a good rule, since it ensures that you can always split up a module M into multiple submodules when it gets too complicated. (Still, as before, you can work-around it with traits.) (I am also a bit disappointed in the idea of choosing our RFCs based on resolve bugs, rather than resolving on what we think the rules should be and filing bugs where we deviate.) |
pcwalton
commented
Jul 24, 2014
@nikomatsakis To me it's just a question of resourcing and priorities. I agree that what you describe is the best behavior, I just want to make sure we have something shippable for 1.0. |
apoelstra
commented
Jul 24, 2014
An example of the modularity that @nikomatsakis says is useful appears in @jeremyletang's rgtk. Combining all the |
huonw
commented
Aug 10, 2014
Another (relatively minor) issue: rust-lang/rust#16398 |
rainbow-alex
commented
Sep 5, 2014
I use |
In particular: * The RFC associated with rust-lang#127 should have had a link to rust-lang#19 as well (and has been assigned RFC rust-lang#19); it also was revised to match the markdown href style of other RFCs. * RFC rust-lang#34 needed its header entries filled in, * RFC rust-lang#123 had a typo in its header, and * RC rust-lang#155 was revised to match the markdown href style of other RFCs.
This fixes #15060 and #3785.