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 upRFC to require `impl MyStruct` to be nearby the definition of `MyStruct` #155
Conversation
apoelstra
referenced this pull request
Jul 5, 2014
Closed
An impl on Vec<T> for trait T causes Vec::from_slice to disappear #15060
This comment has been minimized.
This comment has been minimized.
adrientetar
commented
Jul 5, 2014
This comment has been minimized.
This comment has been minimized.
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
{
pub struct Bitmap
{
priv_field: () // note this field
}
impl super::Core
{
pub fn create_bitmap(&self) -> Bitmap
{
Bitmap{ priv_field: () }
}
}
}
pub struct Core;
impl Core
{
pub fn init_library() -> Core
{
Core
}
}
fn main()
{
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
{
pub struct Bitmap
{
priv_field: ()
}
pub mod export
{
cross_impl!
{
impl Core
{
pub fn 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: () }
}
}
*/
}
}
pub use a::export::*;
pub struct Core;But if I can do this via a macro, what prevents the compiler from doing it? |
This comment has been minimized.
This comment has been minimized.
|
@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. |
apoelstra
reviewed
Jul 6, 2014
| ```` | ||
| which @Ryman noticed in https://github.com/rust-lang/rust/issues/15060 . It is | ||
| not clear to me why this one fails, since the failure is in typeck, which I am | ||
| not familiar with. |
This comment has been minimized.
This comment has been minimized.
apoelstra
Jul 6, 2014
Author
Contributor
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
reviewed
Jul 6, 2014
| - `impl MyStruct` must occur <i>after</i> `MyStruct` is defined. This is a | ||
| minor nit to make implementation much easier, since we can simply refuse | ||
| to create a module in `build_reduced_graph_for_item` for anonymous traits | ||
| unless the name of the time already occurs in `TypeNS`, the type namespace. |
This comment has been minimized.
This comment has been minimized.
apoelstra
Jul 6, 2014
Author
Contributor
There is no need for this restriction. The appropriate place to do the check is in Resolver::resolve_implementation(), which is called from Resolver::resolve_crate(), the final step of resolve. At this point, struct MyStruct will have been seen no matter where in the source file it occurs.
This comment has been minimized.
This comment has been minimized.
|
@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 " |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
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 |
This comment has been minimized.
This comment has been minimized.
|
Pushed changes which fix my own line comments (remove requirement to have |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
+1, language simplification. |
This comment has been minimized.
This comment has been minimized.
|
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? |
This comment has been minimized.
This comment has been minimized.
|
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.) |
This comment has been minimized.
This comment has been minimized.
|
@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. |
This comment has been minimized.
This comment has been minimized.
|
An example of the modularity that @nikomatsakis says is useful appears in @jeremyletang's rgtk. Combining all the |
This comment has been minimized.
This comment has been minimized.
|
Another (relatively minor) issue: rust-lang/rust#16398 |
SiegeLord
referenced this pull request
Aug 31, 2014
Closed
library stabilization: allow inherent methods on primitive types #16862
nrc
assigned
pcwalton
Sep 4, 2014
This comment has been minimized.
This comment has been minimized.
rainbow-alex
commented
Sep 5, 2014
|
I use |
apoelstra commentedJul 5, 2014
This fixes #15060 and #3785.