How can I have a compile-time error in cases like this?

Given I want to use a data-oriented approach I'm using this code:

pub struct Store {
    pub players: BTreeMap<uuid::Uuid, Player>,
    pub coach_by_player_id: HashMap<uuid::Uuid, uuid::Uuid>,
    pub skills_by_player_id: HashMap<uuid::Uuid, Vec<uuid::Uuid>>,
}

instead of using the OOP approach with struct like:

pub struct Player {
    id: uuid::Uuid,
    // other fields here
    coach: Box<Coach>
    skills: Vec<Skill>
}

An issue I'm having is that sometimes I forget to push some object to the store but that object is needed to create another object that needs to read it from the store, like this example:

let store = &mut Store::default();

let team = Team::new();

let player = Player::new(team.id, "Bob", store);

impl Player {
    pub fn new(
        team_id: uuid:Uuid,
        name: &str,
        store: &mut Store,
    ) -> Self {
        if let Some(team) = store.get_team(team_id) {
            // use team here
        };

        // create player here
    }
}

Since I forgot to push the team before creating the new player I get an error at run-time and not at compile-time.

How can I have a compile-time error in cases like this?

I need a way to find out at compile-time that I do not pushed an object in the store.

Would it work to make the Team::new constructor also require &mut Store, so that you can only access the Team.id after Team added itself to the store?

2 Likes

The opposite is somewhat simply: Create a type that only Store is able to return, iff you have stored the Object properly:

mod store {
    pub struct StoredTeamId(uuid::uuid);

    impl StoredTeamId {
        pub fn uuid(&self) -> uuid:uuid {
            self.0
        }
    }

    pub struct Store { ... }

    impl Store {
        pub fn store_team(team: Team) -> StoredTeamId {
             let uuid = team.uuid.clone();
             todo!("store team in some collection");
             StoredTeamId(uuid)
        }
    }
}

pub struct Player { ... }

impl Player {
    pub fn new(team_id: StoredTeamId, ...) {
        ...
    }
}

You can also implement From-trait etc.

1 Like

Can you write a small example, please?

For what?