Skip to content

RFC: allow delegating some methods from an trait impl to a field of a struct #7773

Closed
@huonw

Description

@huonw

This would allow one to emulate conventional OO inheritance (to some degree) automatically, instead of requiring a lot of boilerplate, e.g.

trait A {
  fn foo(&self);
  fn bar(&self);
  fn baz(&self);
}

struct Basic {
   some_field: int
}

impl A for Basic {
  fn foo(&self) {}
  fn bar(&self) {}
  fn baz(&self) {}
}

struct Extended {
   inner: Basic,
   extra: int
}

#[delegate_to(inner)]
impl A for Extended {
  fn foo(&self) {} // new version of `foo`
}
/* automatically created:
  fn bar(&self) { self.inner.bar() }
  fn baz(&self) { self.inner.baz() }
*/

This isn't possible as a syntax extension, since the methods in a trait are not known at expansion time. And methods returning Self would have to be implemented by hand.

I guess this is similar to default methods. I think it would allow traits to replace the closures-in-structs pattern entirely (e.g. the ast visitor), since currently it's not easily possible to write Visitor { visit_expr: |e, (a,v)| { ... }, .. some_non_default_visitor } (i.e. replacing only the visit_expr method of a visitor defined elsewhere, which is not the default_visitor()) in terms of default methods only (this came up in my attempt to replace the struct visitors in rustc::middle::lint with @Aatch's trait+default-methods based one).

Related:

A super-wishlist behaviour would be turning any recursive method calls (i.e. calling a method from the same trait) on the base type into calls on the extended type, so:

impl A for Base {
   fn foo(&self) {
       if some_condition { self.bar() }
   }
   fn bar(&self) {}
}

struct Extended { base: Base }

#[delegate_to(base)]
impl A for Extended {}

// is equivalent to

impl A for Extended {
   fn foo(&self) {
       if some_condition { self.bar() }  
       // different to plain self.inner.bar(), which is `if some_condition { self.base.bar() }`
   }
   fn bar(&self) { self.base.bar() }
}

(This is possibly possible by recording "a trait-self" against which to call methods from the same trait, I don't know.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-attributesArea: Attributes (`#[…]`, `#![…]`)A-trait-systemArea: Trait system

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions