Skip to content

Conversation

mikemedina
Copy link
Contributor

This is my biggest pet peeve with Result! I regularly have to use this awful workaround when I want to return an err result with a SUCCESS_TYPE that doesn't match. Here's a real-world example that I obfuscated:

  public static Result<ExamplePrivilegeEgg, ExampleError> fromUrn(String urn) {
    Result<Long, ExampleError> tryId = Optional
      .ofNullable(Longs.tryParse(urn.split()[1]))
      .map(Result::<Long, ExampleError>ok)
      .orElseGet(() -> Result.err(ExampleError.INVALID_PRIVILEGE_ID));
    if (tryId.isErr()) {
      // This works around Result<Long, ExampleError> not matching the 
      // method's return type Result<ExamplePrivilegeEgg, ExampleError>
      // even though we've confirmed it's an error and the error types match
      return tryId.mapOk(null);
    }

A slightly more honest but even uglier alternative is this more common approach:

  public static Result<ExamplePrivilegeEgg, ExampleError> fromUrn(String urn) {
    Result<Long, ExampleError> tryId = Optional
      .ofNullable(Longs.tryParse(urn.split()[1]))
      .map(Result::<Long, ExampleError>ok)
      .orElseGet(() -> Result.err(ExampleError.INVALID_PRIVILEGE_ID));
    if (tryId.isErr()) {
      // This works around Result<Long, ExampleError> not matching the 
      // method's return type Result<ExamplePrivilegeEgg, ExampleError>
      // even though we've confirmed it's an error and the error types match
      return Result.<ExamplePrivilegeEgg, ExampleError>err(tryId.unwrapErrOrElseThrow());
    }

With this new Result::coerceErr utility method, the example becomes:

  public static Result<ExamplePrivilegeEgg, ExampleError> fromUrn(String urn) {
    Result<Long, ExampleError> tryId = Optional
      .ofNullable(Longs.tryParse(urn.split()[1]))
      .map(Result::<Long, ExampleError>ok)
      .orElseGet(() -> Result.err(ExampleError.INVALID_PRIVILEGE_ID));
    if (tryId.isErr()) {
      return tryId.coerceErr();
    }
image

Copy link
Member

@zklapow zklapow left a comment

Choose a reason for hiding this comment

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

I think this might need a different name or at least better docs? From the name it wasnt clear to me what this did (actually I assumed it was gonna do some weird casting on the error type) when in fact this seems interested mainly in coercing to a different OK type when the OK value is not set?

@kmclarnon
Copy link
Member

kmclarnon commented May 7, 2025

I believe that it's trying to solve the same problem as #49

@mikemedina
Copy link
Contributor Author

Yeah Kevin's right -- both PRs were doing the same thing. I went with coerceErr over propagate because the intention was for coerce the OK type of the Result into compliance when you know the Result is an ERROR and has no OK value. Nothing is really being propagated

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.

3 participants