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

Option<T> does not implement OwnedToVariant when T implements only OwnedToVariant. #869

Open
B-head opened this issue Mar 2, 2022 · 6 comments
Labels
breaking-change Issues and PRs that are breaking to fix/merge. c: core Component: core (mod core_types, object, log, init, ...) quality-of-life No new functionality, but improves ergonomics/internals status: upstream Issue that originates in an upstream project and can't be dealt with here.
Milestone

Comments

@B-head
Copy link
Contributor

B-head commented Mar 2, 2022

For example, the following code will not work.

#[derive(NativeClass)]
#[no_constructor]
struct Foo {}

#[methods]
impl Foo {
    #[export]
    fn get(&self, _owner: &Reference) -> Option<Instance<Foo, Unique>> {
            Some((Foo{}).emplace())
    }
}

This issue can be avoided by using into_shared() to perform type conversion.

#[derive(NativeClass)]
#[no_constructor]
struct Foo {}

#[methods]
impl Foo {
    #[export]
    fn get(&self, _owner: &Reference) -> Option<Instance<Foo>> {
            Some((Foo{}).emplace().into_shared())
    }
}

I tried to solve this issue, but implementing impl<T: OwnedToVariant > OwnedToVariant for Option<T> causes a conflict with impl<T: ToVariant> OwnedToVariant for T.

@B-head B-head added the quality-of-life No new functionality, but improves ergonomics/internals label Mar 2, 2022
@Bromeon Bromeon added the c: core Component: core (mod core_types, object, log, init, ...) label Mar 2, 2022
@Bromeon Bromeon added this to the v0.10.0 milestone Mar 2, 2022
@Bromeon
Copy link
Member

Bromeon commented Mar 13, 2022

I'm not sure how to address this now, due to the conflicts you mentioned. Rust's lack of specialization is quite limiting sometimes.

Any ideas?

@Bromeon Bromeon removed this from the v0.10.0 milestone Mar 13, 2022
@B-head
Copy link
Contributor Author

B-head commented Mar 16, 2022

I'm not familiar with Rust either😅 In conclusion, I do not have an easy idea. So what I write below is for reference only.

First, since there is no specialization in Rust, I would remove impl<T: ToVariant> OwnedToVariant for T. After removing them, there are two possible designs.

Implement separately

Require users to implement ToVariant and OwnedToVariant separately.

#[derive(ToVariant, OwnedToVariant)]
struct Foo {}

Pros

  • Library code is easy to implement.
  • The meaning of each trait is clear.

Cons

  • User codes are redundant.
  • Care should be taken to maintain implementation consistency for ToVariant and OwnedToVariant.

Standard library approach

The same approach is used to implement the standard library in From (as Into). The define of ToVariant is changed as follows, and OwnedToVariant is removed.

trait ToVariant {
    // Note that there is no & in self.
    fn to_variant(self) -> Variant;
}

In the implementation to the trait, separate implementations are made for T corresponding to OwnedToVariant and &T corresponding to the old ToVariant. (String in the standard library is helpful)

impl ToVariant for Foo {
     fn to_variant(self) -> Variant {
        /* Implementation in move (or copy) semantics. */
     }
}

impl ToVariant for &'_ Foo {
     fn to_variant(self) -> Variant {
        /* Implementation in clone semantics. */
     }
}

Pros

  • Users can implement only what they need.
  • Ensure extensibility of library code.
  • Standard library implementations can be helpful.

Cons

  • The meaning of trait is implementation-dependent.

What I feel

I think it is silly to make breaking changes to solve small issues that have workarounds. So better to resolve this issue in conjunction with #808 and related issues.

@Bromeon
Copy link
Member

Bromeon commented Mar 16, 2022

I'm not even sure how many users manually implement ToVariant, OwnedToVariant etc. As an uneducated guess, I'd say most people are happy with the conversions that Ref, Instance and the core types provide.

I agree that we shouldn't break the code for 0.10, so I'll leave this open for later. One option might also be that we allow

#[derive(ToVariant)]`
struct MyStruct { ... }

which would use OwnedToVariant.

@Bromeon Bromeon added this to the v0.11 milestone Aug 25, 2022
@Bromeon
Copy link
Member

Bromeon commented Aug 25, 2022

Assigned to 0.11, but honestly not sure if this can be solvable at all.
If we don't get any ideas in reasonable time, I'd tend to close this.

Maybe there can be some takeaways for GDExtension w.r.t. how to design those traits.

@chitoyuu
Copy link
Contributor

I think #869 (comment) is the approach one would have taken if the traits were to be designed from scratch. This is the same way serde and co does it.

The OwnedToVariant trait was only created to avoid changing the signature of the earlier ToVariant, IIRC.

I don't think there are a lot of people who write their own ToVariant implementations, outside of a few specific cases that the macro doesn't handle yet like #546 which I'm working on. Once that's dealt with I don't think the impact of the change would be as negative if at all.

@chitoyuu chitoyuu added the breaking-change Issues and PRs that are breaking to fix/merge. label Nov 30, 2022
@chitoyuu chitoyuu modified the milestones: unplanned, v0.12.0 Nov 30, 2022
@chitoyuu
Copy link
Contributor

Made an attempt at this, but unfortunately ran into a rustc bug with impls on references: rust-lang/rust#39959

Seems like this will have to be delayed until the upstream bug is fixed, as there isn't an obvious workaround that can be reliably generated.

@chitoyuu chitoyuu added the status: upstream Issue that originates in an upstream project and can't be dealt with here. label Jan 10, 2023
@chitoyuu chitoyuu modified the milestones: v0.12.0, unplanned Jan 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change Issues and PRs that are breaking to fix/merge. c: core Component: core (mod core_types, object, log, init, ...) quality-of-life No new functionality, but improves ergonomics/internals status: upstream Issue that originates in an upstream project and can't be dealt with here.
Projects
None yet
Development

No branches or pull requests

3 participants