Specialization/Inheritance


#1

A large part of my project depends on how specialization and inheritance turn out, so I am keen to hear how things are likely to go. Specifically if specialization is allowed, you could do something like this which mimics inheritance, still using fat pointers:

struct Monster<T>
{
    x : i32,
    y : i32,
    hit_points : u32,
    
    monster_data : T
}

struct Demon<U>
{
    rage_level : u32,
    mana : u32,
    
    demon_data : U
}

struct Imp
{
    num_fireballs : u32
}

trait MonsterTrait
{
    fn attack(&mut self);
}

impl<T> MonsterTrait for Monster<T>
{
    fn attack(&mut self)
    {
        println!("Standard attack");
    }
}

impl<U> MonsterTrait for Monster<Demon<U>>
{
    fn attack(&mut self)
    {
        println!("Standard demon claw");
        self.monster_data.rage_level += 1;
    }
}

impl MonsterTrait for Monster<Demon<Imp>>
{
    fn attack(&mut self)
    {
        println!("Imp throws fireball");
        self.monster_data.rage_level += 1;
        self.monster_data.demon_data.num_fireballs -= 1;
    }
}

This is very close to C++, where Demon inherits from Monster and Imp inherits from Demon, with downcasting and fat pointers a more Rusty approach.

Currently I’m just implementing a new Impl for every monster type, less elegant, I would like to delete some of my code.

Waiting for the dust to settle, I am interested whether this feature will be added in some form.

Steve


#2

You don’t actually want inheritance at all. It’s a bad way to solve the problem in this case. So is Rust’s trait system in this case. Because you don’t want static typing to define your composition of monster abilities; you don’t want code to do it at all. Make your monsters and their abilities data-driven. A monster is a monster, and the differentiating factors are data like its name, hit points, armor, list of special attacks, etc.

Move your monsters into external data files and out of your code. All you should have a single core Monster type and the corresponding traits that define how monsters interact with the rest of your game. Move the special abilities into another trait that defines what the ability is, how it’s used, etc. and an implementation of the trait for each ability. Create a factory for the abilities that can be used by the Monster loading function to fill in the ability list.

Even better, don’t even have a Monster type at all. You still end up getting painted into a corner by the type system. That kind of design leads into problems like having distinct Monster and Item types which can turn into a problem with e.g. making a Mimic monster that is also an item (contrived example, but you get the point). Monsters, items, players, treasure chests, doors… they’re all just game objects. The only thing that should differentiate them is the data that describes what they look like and how you interact with them. Again, Rust traits still aren’t the right solution here because you shouldn’t be hard-coding game objects into your game; make them fully data-driven and dynamic.

tl;dr: you don’t need Rust’s specialization/inheritance solution for your problem because any form of language type system is the wrong solution for said problem.