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

Add #[try_from(type[, err, err-constructor])] #430

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Davoodeh
Copy link

@Davoodeh Davoodeh commented Dec 14, 2024

It is briefly described in the docs and tests so I spare the duplicate information
open the discussion by means of an example.

I felt this is needed when working on an NLP library.

Assume a language has 2 set of characters like below:

enum SetA {
    A,
    B,
    C,
}

impl TryFrom<char> for SetA {
    fn try_from(v) -> Result {
        Ok(match v.to_lowercase() {
            'a' => A,
            ...
            _ => return Err(()),
        })
    }
}

enum SetE {
    E,
    F,
    G,
}

impl TryFrom<char> for SetE {
    fn try_from(v) -> Result {
        Ok(match v.to_lowercase() {
            'e' => E,
            ...
            _ => return Err(()),
        })
    }
}

The developer, for whatever reason, decides to also make a union set (not to be confused
with the unsafe union type) as written:

enum SetOfSets {
    A(SetA),
    E(SetE),
}

// #[derive(TryFrom)
// #[try_from(char)]
impl TryFrom<char> for SetOfSets {
    fn try_from(v) -> Result {
        if let Ok(b1) = SetA::try_from(v) {
            return Ok(SetOfSets::A(b1));
        }

        if let Ok(b1) = SetE::try_from(v) {
            return Ok(SetOfSets::E(b1));
        }

        Err(())
    }
}

This macro makes the latter implementation exactly as described.
The first field returning a valid answer to the try_from will be
set and used.

This is rather situational but I thought it's a good idea to share it
here even though this is my first contribution and I'm not really good
with the custom utilities and standards of this library and only read the
parts of code concerned with my own use case... so yeah, have it at that.

Regarding the previous behavior, only a slight compile_fail situation (tests/compile_fail/try_from/invalid_repr.stderr) is changed and the
rest is intact.

I'll be glad to have any suggestions and change requests...

  • Sincerely,...

P.S: If not reviewed rapidly, I'll do my best to clean up the code more
and update the docs (as I suspect some comments may be old or misleading as
this was my after-work little patch and I apologize for whatever shortcomings it has).

@JelteF
Copy link
Owner

JelteF commented Jan 3, 2025

First of all, I'm a bit confused. Your PR description seems to be about a completely different feature than the actual feature that's implemented in the code.

Secondly regarding this code snippet:

enum SetOfSets {
    A(SetA),
    E(SetE),
}

// #[derive(TryFrom)
// #[try_from(char)]
impl TryFrom<char> for SetOfSets {
    fn try_from(v) -> Result {
        if let Ok(b1) = SetA::try_from(v) {
            return Ok(SetOfSets::A(b1));
        }

        if let Ok(b1) = SetE::try_from(v) {
            return Ok(SetOfSets::E(b1));
        }

        Err(())
    }
}

I think an inherent problem, or at least surprising behaviour, of this code is what happens when SetA and SetE overlap in the characters that they can be derived from. With this code, it will always cast to A in that case. Is that really desirable?

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