Giter Club home page Giter Club logo

Comments (4)

KodrAus avatar KodrAus commented on July 20, 2024 1

provided methods should be overwritten by the generated impls by default, with a way for the user to opt-out and instead use the provided body.

👍 Hmm, this sounds like the best way to go to me.

So if we think about what the result of this attribute is, instead of writing a generic impl that forwards to our inner type we explicitly retain the default impl as specified on the trait. Omitting this default method from the impl has the same observable behaviour as inlining it with the same body. Given that, I think framing the attribute around using the default impl rather than as not including the method in the generated impl makes more sense to me.

The Rust book calls methods on a trait with a body default implementations so maybe keep_default_for(list, of, types)?

#[auto_impl(keep_default_for(&, Box))]
fn provided(&self) {
    // ...
}

from auto_impl.

KodrAus avatar KodrAus commented on July 20, 2024

Ah interesting, can you think of a reason we wouldn't just want to always forward the provided method to the underlying T since it might have been given a different implementation? I think that's a good default behaviour, but it also seems worthwhile to build out some infrastructure to handle attributes on methods too and deal with cases where they're not valid. Maybe for syntax we could stick a bit closer to standard attributes:

#[auto_impl(include_for(&, Box))]
fn provided(&self) {
    // ...
}

What do you think?

from auto_impl.

LukasKalbertodt avatar LukasKalbertodt commented on July 20, 2024

Syntax wise: absolutely, include_for(&, Box) is way better ^_^

Regarding the "why not always just implement default methods?": because Self bounds -- discussed in #11 . That's something I encountered in a code base of mine when I tried to use auto_impl. That's why I created these two issues. Maybe I should not have split them...

I can't come up with a simple but useful example right now, so here is a simple useless one:

trait Foo {
    fn one(&self);
    
    fn two(&self)
    where
        Self: Clone
    {
        println!("buzzah!");
    }
}

This trait would allow us to generate this impl:

impl<'a, T> Foo for &'a T {
    fn one(&self) {
        (**self).one()
    }
}

Since we don't need to implement two(), we don't need a T: Clone bound (again, as discussed in #11). This means that the trait can be implemented for more types automatically. So I think it's worth to not implement provided methods sometimes.

Of course, the difficult question is: opt-in or opt-out? include_for or exclude_for?

Being opt-in means that generated impls are more generic (less bounds) by default, but it could also be a surprise for the user. I'm not quite sure what a user would assume what would happen. I guess we should go the path of least surprise. Maybe I can ask random people the next few days what they would expect.

from auto_impl.

LukasKalbertodt avatar LukasKalbertodt commented on July 20, 2024

Of course, the difficult question is: opt-in or opt-out? include_for or exclude_for?

I talked to two friends (who know Rust) about this and I thought about it a bit more. We think that opt-out is better. As in: by default, provided methods are generated and delegated to T.

A user could reasonably assume that &T behaves like T. Not overwriting the method can lead to dangerous surprises. For example, the Iterator trait has the method size_hint which is a provided impl. It returns (0, None) by default -- the most conservative size hint. If we #[auto_impl(&mut)] the Iterator trait, then &mut std::slice::Iter should better return the same from size_hint as std::slice::Iter and not (0, None).

The other way around, I cannot imagine someone assuming that &T would keep the default method and not behave like T. And I cannot come up with a real-world example where this might lead to something bad.

So: IMO, provided methods should be overwritten by the generated impls by default, with a way for the user to opt-out and instead use the provided body.


So now bike-shedding the attribute. I am not completely happy with exclude_for yet. I think we agree that it should have the form auto_impl(foo(list, of, types)). So what should foo be?

  • exclude_for
  • keep_default
  • keep_provided
  • no_overwrite

Any opinions?

from auto_impl.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.