Struct Append

I came up with an idea for structs where you can basically re-use an existing struct to define another. The motivation revolves around Copy types moving to non-Copy types, and not having to refactor existing code. That way, the fields in the new struct (created by appending fields) stay in sync with the existing struct. It's not inheritance. It's more like prototyping on top of a type (thinking javascript). That way, you can use your new type as a non-copy in the module where it's needed without causing a refactor in other modules. maybe "append" could be a keyword. struct MyNewStruct append ExistingCopyStruct{ my_new_field: String }

Typically, such use cases would be solved by using composition. I.e. you just define

struct MyNewStruct {
    base: ExistingCopyStruct,
    my_new_field: String,
}

Rust even supports more transparent access to fields of the “base” (the name is irrelevant) field’s struct fields if you implement the Deref/DerefMut traits, which can presumably be quite useful, even though this kind of useage was not necessarily the main intended use-case of those traits.

impl std::ops::Deref for MyNewStruct {
    type Target = ExistingCopyStruct;
    fn deref(&self) -> &ExistingCopyStruct { &self.base }
}

impl std::ops::DerefMut for MyNewStruct {
    fn deref_mut(&mut self) -> &mut ExistingCopyStruct { &mut self.base }
}

fn test(s: &mut MyNewStruct) {
    s.some_existing_struct_field += 1;
}

Rust Playground


By the way, I don’t really understand at all your concerns regarding Copy, I think you’ll have to elaborate on that to make your point clear.


The composition approach outlined above has only few disadvantages over an approach of “copying over” all the field definitions (be it in a manual or automatic manner): the main one I can come up with being that the layout of the fields might be slightly less optimal, since the ExistingCopyStruct fields are still kept together in one ExistingCopyStruct struct, and cannot be re-ordered with any new fields like my_new_field. Of course, this also comes with some advantages, e.g. you can get a true &ExistingCopyStruct reference from your &MyNewStruct, and thus use existing API for ExistingCopyStruct also on MyNewStruct (with the Deref impl, this conversion between references is even available as an implicit coercion).

Notably, compared to other more “high-level” languages such as javascript, composition by including a struct as a field in another will not have the downside of introducing any additional indirection or heap allocations.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.