Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derived properties #53

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

k88hudson-cfa
Copy link
Collaborator

@k88hudson-cfa k88hudson-cfa commented Sep 30, 2024

This PR adds derived properties, for example:

define_derived_person_property!(
    MastersRunner,
    bool,
    [Age, IsRunner],
    |age, is_runner| age >= 40 && is_runner
);

The macro takes a list of dependent properties and a closure which computes the property from those dependencies.

Derived properties can be used as other properties (with get_person_property) etc.; they are recomputed whenever a dependency changes (and will also emit a change event).

As a side effect of needing to do some lazy registration of dependencies if the property is derived, I needed to introduce a wrapper around subscribing to person property changes, which I think is not ideal:

  context.subscribe_to_person_property_changed(
        DiseaseStatusType,
        |_context, person, current, previous| {
            println!("{person:?} changed disease status from {previous:?} to {current:?}");
        },
    );

In particular, I think it's probably pretty easy to mess up the order of current and previous.

Open to suggestions on how to handle this better

src/people.rs Outdated
@@ -60,6 +67,15 @@ macro_rules! define_person_property {
pub struct $person_property;
impl $crate::people::PersonProperty for $person_property {
type Value = $value;
fn is_derived() -> bool {
false
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could make this a default.

src/people.rs Outdated
}
fn dependencies() -> Vec<std::any::TypeId> {
panic!("Property not derived");
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can also be defaults.

impl $crate::people::PersonProperty for $derived_property {
type Value = $value;

fn calculate(context: &$crate::context::Context, person_id: $crate::people::PersonId) -> Self::Value {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that initialize and calculate are the same, why not just have initialize?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overloading the meaning of a single function seems not ideal to me, this is more explicit

src/people.rs Outdated

let person = context.add_person();
context.set_person_property(person, Age, 50);
context.set_person_property(person, IsRunner, false);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to stop people from externally calling set_person_property() on derived. I think I would do this by having a set_person_property_int() that is private but called by set_person_property()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants