Skip to content
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

Allow inheritance between structs. #12562

Closed
wants to merge 1 commit into from
Closed

Allow inheritance between structs. #12562

wants to merge 1 commit into from

Conversation

nrc
Copy link
Member

@nrc nrc commented Feb 26, 2014

No subtyping, no interaction with traits. Partially addresses #9912.

@@ -758,6 +758,13 @@ pub fn print_struct(s: &mut State,
span: codemap::Span) -> io::IoResult<()> {
try!(print_ident(s, ident));
try!(print_generics(s, generics));
match struct_def.super_struct {
Some(t) => {
try!(word(&mut s.s, " : "));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of traits, it was decided that trait X: Y { } was to be preferred over trait X : Y { }. I believe that this should use ": " rather than " : " for consistency.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Comparing with how it's implemented for trait, putting the space in the string is probably not the optimal thing to do anyway. word_space(&mut s.s, ":") is probably better, though I haven't traced through the code to see what that actually does.)

@jdm
Copy link
Contributor

jdm commented Feb 26, 2014

Will syntax like Sub { y: 11, .. Sup::new(x) } work? It seems like it could be desirable not to have to list every parent type's fields in the initializer for DRY purposes.

@huonw
Copy link
Member

huonw commented Feb 26, 2014

I can't see any tests for

struct A: B { ... }

fn foo(_: &B) {}

fn bar(a: &A) { foo(a) }

does this patch support that yet?

@nrc
Copy link
Member Author

nrc commented Feb 26, 2014

@jdm It does not - we still require all the fields in any .. expr in the initialiser (I think). This sounds like a good thing to add though. There are a few questions about whether we should allow only a direct super-struct, or any transitive super-struct. We might also want to allow multiple expressions, which would be complicated. We might want a more general mechanism which allows a .. expr to provide only some of the fields, and then the super-struct cases would 'come out in the wash'.

@nrc
Copy link
Member Author

nrc commented Feb 26, 2014

@huonw No, I explicitly avoided adding any subtyping or coercions here. I think we need to think a little more about the implications of that, but I foresee adding it in another PR.

@alexcrichton
Copy link
Member

Should sub-structs have access to private fields in parent super structs? It seems the answer is "yes" from this implementation, but it may be worth considering this and testing it one way or another. I would mildly expect the answer to be no.

@bill-myers
Copy link
Contributor

I kind of wonder if a syntax where you specify a field as "use foo: S" where the "use" keyword is syntax sugar that imports the fields in the struct namespace would be a better design, since that would give access to the base struct for free without having to introduce a "super" keyword, would allow "multiple inheritance" (this could be extended to allow importing single fields via use), and would be a simpler change to the language.

Trait inheriting structs can then be an orthogonal feature, where the first field of the struct is considered as being the "parent" structure, regardless of whether it was imported or not via "use" (but with the restriction that only parents that are public are considered parents if the trait impl is in another crate, so that changing the first field of a struct is not an API change when the field is private).

@emberian
Copy link
Member

@bill-myers super is already a keyword for relative imports; use super::foo

@nikomatsakis
Copy link
Contributor

I'd like to review

@nrc
Copy link
Member Author

nrc commented Feb 26, 2014

@nikomatsakis I was going to address the comments others have made here (in particular, adding debug-info and privacy checks). You might want to hold off till then for a proper review. In the mean time, any comments on the general idea would be appreciated.

@nikomatsakis
Copy link
Contributor

On Wed, Feb 26, 2014 at 02:08:50PM -0800, Nick Cameron wrote:

@nikomatsakis I was going to address the comments others have made here (in particular, adding debug-info and privacy checks). You might want to hold off till then for a proper review. In the mean time, any comments on the general idea would be appreciated.

Will do.

@brson
Copy link
Contributor

brson commented Feb 27, 2014

Is this design written up somewhere?

@nrc
Copy link
Member Author

nrc commented Feb 27, 2014

@nrc
Copy link
Member Author

nrc commented Mar 1, 2014

@nikomatsakis - ready for review

I'm not sure how much in the way of tests are required for debug-info - I added a simple test, let me know if we need more.

@dobkeratops
Copy link

a possible point in favour of having single inheritance: fewer symbols to remember when accessing struct members, which is a bigger deal without code-completion. "which sub-member contains which named field?" .. "i want .name' ..

if a primitive tool just lists all struct members after pressing '.' , a codebase that has single-inheritance will have a smaller amount of false posatives in that list

@dobkeratops
Copy link

One more idea,
if not having single inheritance, would you consider allowing element access to 'shortcut' where names are unambiguous.
example

struct Foo { id:int, name:~str }
struct Bar  { foo:Foo, x:int, y:int }

let b=Bar::new();    
println!("id={:?}", b.id) // a.id is a shortcut for  b.foo.id ... since its unambiguous...

Even if you dont want that, it would be nice to make an error message that does that lookup for you... "Bar has no member id... did you mean .foo.id"

Without this I'm going probably going to end up making a trait of accessors. trait IFoo { fn id()->int..} impl IFoo for Bar ...

I thought that traits inheriting structs would also let you use struct elements in default implementations, which would also be really helpful.

This is about ease of navigating code, ease of refactoring.. if you start moving fields between structures.. (which should be part of the common base ? .. you evolve that decision over time as your source grows..) .. you have less to go back and rewrite.

@nrc
Copy link
Member Author

nrc commented Mar 18, 2014

Sorry the commits are kind of messy - lots of rebasing going on.

@nrc
Copy link
Member Author

nrc commented Mar 18, 2014

@nikomatsakis r? I rebased everything and added a requirement for the virtual keyword.

Its all feature gated, so if we do something different for the DOM problem it shouldn't be too hard to rip out. But if we do go the virtual structs route, then this is the first step and it will rot quickly if we don't land it, I think.

@nikomatsakis
Copy link
Contributor

@nick29581 ok, I read through it. Everything looks fairly reasonable. I think the big comment is that I'd rather see the set of struct fields collected in a pre-pass or sidetable rather than scraping and re-scraping them from the AST. If you fear bitrot, would you prefer to land and then address that?

@nrc
Copy link
Member Author

nrc commented Mar 18, 2014

Thanks for the review. I can make the changes now. I was worried about bit rot if we leave this until we are ready to implement virtual structs or post-1.0, another few days won't hurt.

@nikomatsakis
Copy link
Contributor

@nick29581 ping me when updated

@nrc
Copy link
Member Author

nrc commented Mar 24, 2014

@nikomatsakis pushed an updated version. It doesn't quite use a side table for all the fields of a struct. I did move some of the field checking and collation into the collect phase and I build side tables for the super-struct of a struct and the declared fields of a struct. (I couldn't create a table for all fields here because some of the super-structs may not yet have been encountered, of course we could do another pass, but more on that later).

So after collect, we never scrape the AST, but we don't have a simple mapping from a struct to all its fields. I add a few methods to ty for getting all the fields for a struct (in ast and ty flavours, annoyingly), so this is only done in one place, eliminating the errors you worried about. If you like, we could cache these lists of all fields here. I believe that is easier than doing this pre-emptively either as a new pass or part of an existing one. I haven't done it because I'm not convinced it is a worthwhile optimisation for now, but I don't have a philosophical objection if you think otherwise.

@nrc
Copy link
Member Author

nrc commented Mar 31, 2014

@nikomatsakis updated and ready for re-review

@nrc
Copy link
Member Author

nrc commented Apr 2, 2014

SIgh, needs a rebase

@nrc
Copy link
Member Author

nrc commented Apr 3, 2014

Rebased.

@nikomatsakis (or anyone else) please could you re-r+?

@nrc
Copy link
Member Author

nrc commented Apr 3, 2014

Oh ffs, needs another rebase - looks like I was right about this bit-rotting quickly...

@nrc
Copy link
Member Author

nrc commented Apr 3, 2014

Rebased again. Please could someone r+?

@nrc
Copy link
Member Author

nrc commented Apr 4, 2014

AGAIN?! :-(

@nrc
Copy link
Member Author

nrc commented Apr 4, 2014

OK, let's try again. Can someone r+ please?

@nrc
Copy link
Member Author

nrc commented Apr 5, 2014

OK, I am mystified by that failure - it seems to be because of a missing feature gate, but the required #![feature(struct_inherit)] is in the file. Also it passes locally. Anyone any ideas?

@nrc
Copy link
Member Author

nrc commented Apr 5, 2014

Oh, wait, did it merge anyway? I am confused.

@huonw
Copy link
Member

huonw commented Apr 5, 2014

This is still open, so nope.

The problem is the check-fast driver; it creates a single huge crate from all the tests that don't have // ignore-fast. i.e. your files are a submodule, and so the features don't work. Just add that ignoring comment to the tests.

@huonw
Copy link
Member

huonw commented Apr 5, 2014

(If #13288 lands this cycle, then this just needs a retry, the check-fast driver won't exist and so ignore-fast won't do anything.)

@nrc
Copy link
Member Author

nrc commented Apr 8, 2014

Could this get a retry and/or another r+ please?

@nrc
Copy link
Member Author

nrc commented Apr 8, 2014

Oh, someone changed an error message. That is a dumb way to fail tests. Sigh.

Rebased/updated again, please to r+?

No subtyping, no interaction with traits. Partially addresses rust-lang#9912.
@nrc
Copy link
Member Author

nrc commented Apr 20, 2014

Rebased and fixed the failing test. Could someone r+ again please?

bors added a commit that referenced this pull request Apr 20, 2014
No subtyping, no interaction with traits. Partially addresses #9912.
@bors bors closed this Apr 20, 2014
@nrc nrc deleted the fields branch April 20, 2014 07:04
@emberian
Copy link
Member

Wow this landed!

bors added a commit to rust-lang-ci/rust that referenced this pull request Jul 25, 2022
Split completion context module into definitions and analysis parts
flip1995 pushed a commit to flip1995/rust that referenced this pull request Apr 4, 2024
Allow `filter_map_identity` when the closure is typed

This extends the `filter_map_identity` lint to support typed closures.

For untyped closures, we know that the program compiles, and therefore we can safely suggest using flatten.

For typed closures, they may participate in type resolution. In this case we use `Applicability::MaybeIncorrect`.

Details:
https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Should.20.60filter_map_identity.60.20lint.20when.20closures.20are.20typed.3F

changelog: `filter_map_identity` will now suggest using flatten for typed closures.

r? `@y21` && `@Centri3`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.