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

A way to update value using the previous one #100

Closed
quendimax opened this issue Mar 3, 2024 · 2 comments
Closed

A way to update value using the previous one #100

quendimax opened this issue Mar 3, 2024 · 2 comments

Comments

@quendimax
Copy link

quendimax commented Mar 3, 2024

Hello. I've not found a way to update Left(prev_value) to Right(new_value) in case when I need the previous value to create the new one. In Option we have the method take that replaces an old value with None, and returns the old one to us. It would be nice to have something like this:

pub fn morph(&mut self, f: F, g: G) -> Either<L, R>
where
    F: FnOnce(L) -> R,
    G: FnOnce(R) -> L

Now to do this, I have to use Option wrapping Either to be able to have the third None state.

struct Data {
    member: Option<Either<L, R>>
}

impl Data {
    fn update_member(&mut self) {
        self.member = self.member.take().map(
            |member| member.map_either(
                |old_value| create_new_value(old_value),
                |old_value| create_new_value(old_value)
            ).flip()
        );
    }
}

But actually I don't need it, and it makes me write more code for checking the option's state later. I just want to have a member with two correct states: L and R.

Thanks

@cuviper
Copy link
Member

cuviper commented Mar 4, 2024

This is a generally difficult thing to do, taking values from &mut for replacement -- see:
https://smallcultfollowing.com/babysteps/blog/2018/11/10/after-nll-moving-from-borrowed-data-and-the-sentinel-pattern/

Either can't really make this any easier itself, as it would face all the same limitations, with no knowledge of what's safe or desirable for any given L or R. Using Option::take is an example of that "sentinel" pattern in the blog, but maybe in your particular case, L or R might have a cheap empty state that you could use as a temporary instead.

@quendimax
Copy link
Author

Thank you for the link.

It looks like now it can't be implemented in a reasonable way. Actually it possible to implement a struct wrapper that hides None sentinel from the user:

struct EitherEx<L, R> {
    value: Option<Either<L, R>>
}

impl<L, R> EitherEx<L, R> {
    pub fn get(&self) -> &Either<L, R> {
        value.as_ref().unwrap()  // or even unchecked, because we should guarantee correctness
    }
    pub fn morph(...) {...}  // now it is possible to implement this like in the example above
}

Also I think it would be possible to implement this if we could add a private enum element that the user can't get access to. I found some pages about this: one, two. Perhaps one day we'll see it in rust :)

@quendimax quendimax closed this as not planned Won't fix, can't repro, duplicate, stale Mar 4, 2024
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

No branches or pull requests

2 participants