Skip to content

Instantly share code, notes, and snippets.

@kyleheadley
Created January 4, 2018 03:21
Show Gist options
  • Select an option

  • Save kyleheadley/6c8860d8fea67c1da2ab18abc6d556b8 to your computer and use it in GitHub Desktop.

Select an option

Save kyleheadley/6c8860d8fea67c1da2ab18abc6d556b8 to your computer and use it in GitHub Desktop.

Revisions

  1. kyleheadley created this gist Jan 4, 2018.
    135 changes: 135 additions & 0 deletions inherit.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,135 @@
    //! Demo of static "inheritance"
    //!
    //! Use trait objects to get dynamic inheritance,
    //! but casting to a subtype is not explored here
    ////////////////////////////////////////////////////////
    // Define Base type, interface, and what is overloadable
    ////////////////////////////////////////////////////////

    /// The main type that will be extended
    struct Basetype<E:BaseExtend> {
    data: usize,
    ext: E,
    }
    /// Additional data and overloadable functions for subtypes
    trait BaseExtend : Sized {
    /// the "overloadable" function from the base interface
    fn sub_info(s:&Basetype<Self>) -> String { String::from("None") }
    }
    /// Convenience for code clarity
    ///
    /// allows: fn foo<B:BaseInterface>(b:B) {}
    /// instead of: fn foo<E:BaseExtend>(b:Basetype<E>) {}
    trait BaseInterface {
    fn get_data(&self) -> usize;
    fn sub_info(&self) -> String;
    }
    impl<E:BaseExtend> BaseInterface for Basetype<E>{
    /// not overloadable, always inherited
    fn get_data(&self) -> usize { self.data }
    /// call the overloadable version
    fn sub_info(&self) -> String { E::sub_info(self) }
    }

    impl BaseExtend for () {
    // not including functions uses the default defined above
    }
    /// non-extended version of the base type
    type Base = Basetype<()>;
    impl Base {
    /// function unique to the base type
    fn new(a:usize) -> Base {Basetype{ data:a, ext:()}}
    }

    /////////////////////////////////////////////////////////////////
    // Define some subtypes and their overloaded and unique functions
    /////////////////////////////////////////////////////////////////

    /// additional fields in the subtype
    struct Subtype1{ thestring: String }
    impl BaseExtend for Subtype1 {
    fn sub_info(s:&Basetype<Self>) -> String { s.ext.thestring.clone() }
    }
    /// a subtype of the base type
    type Sub1 = Basetype<Subtype1>;
    impl Sub1 {
    /// function unique to this sub type
    fn new(a:usize,b:String) -> Sub1 { Basetype{ data: a, ext: Subtype1{thestring:b}} }
    }

    /// additional fields in the subtype
    struct Subtype2{thenum:usize}
    impl BaseExtend for Subtype2 {
    fn sub_info(s:&Basetype<Self>) -> String { s.ext.thenum.to_string() }
    }
    /// a subtype of the base type
    type Sub2 = Basetype<Subtype2>;
    impl Sub2 {
    /// function unique to this sub type
    fn new(a:usize,b:usize) -> Sub2 { Basetype{data: a, ext: Subtype2{thenum:b}} }
    }

    ////////////////////////
    // Define a Sub-Sub type
    ////////////////////////

    struct Subtype<E:SubExtend>{
    data: usize,
    ext: E,
    }
    impl<E:SubExtend> BaseExtend for Subtype<E> {
    fn sub_info(s:&Basetype<Self>) -> String { format!("Sub{}: {}", s.ext.data, E::subsub_info(s)) }
    }
    trait SubExtend : Sized {
    /// No default means this requires an implementation
    fn subsub_info(s:&Basetype<Subtype<Self>>) -> String;
    fn say_more(s:&Basetype<Subtype<Self>>) -> String { String::from("more!") }
    }
    impl<E:SubExtend> Basetype<Subtype<E>> {
    // `fn subsub_info` is not part of the interface
    fn say_more(&self) -> String { E::say_more(self) }
    }

    impl SubExtend for () {
    fn subsub_info(s:&Basetype<Subtype<Self>>) -> String { String::from("None") }
    }
    impl Basetype<Subtype<()>>{
    fn new() -> Self { Basetype{data:0,ext:Subtype{data:1,ext:()}} }
    }

    struct Defiant{msg:String}
    impl SubExtend for Defiant {
    fn subsub_info(s:&Basetype<Subtype<Self>>) -> String { s.ext.ext.msg.clone() }
    fn say_more(s:&Basetype<Subtype<Self>>) -> String { String::from("I don't want to!") }
    }
    impl Basetype<Subtype<Defiant>> {
    fn new() -> Self { Basetype{data:51256,ext:Subtype{data:9289,ext:Defiant{msg:String::from("blah, blah")}}} }
    }

    /////////////////////////
    // Show that it all works
    /////////////////////////

    /// function that takes any base or sub type
    ///
    /// alternately, it could be defined more specifically:
    /// fn get_sub<E:BaseExtend>(b:Basetype<E>) -> String {b.sub_info()}
    /// which would allow a where clause to restrict E further
    fn get_sub(b:&BaseInterface) -> String {b.sub_info()}

    fn main() {
    let a = Base::new(2);
    println!("a base data: {}",a.get_data());
    println!("a ext data: {}",get_sub(&a));
    let b = Sub1::new(2,String::from("yes"));
    println!("b base data: {}",b.get_data());
    println!("b ext data: {}",get_sub(&b));
    let c = Sub2::new(2,3);
    println!("c base data: {}",c.get_data());
    println!("c ext data: {}",get_sub(&c));
    let e = Basetype::<Subtype<Defiant>>::new();
    println!("e base data: {}",e.get_data());
    println!("e ext data: {}",get_sub(&e));
    println!("e, say more: {}", e.say_more());
    }