Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I return failure details from a method without using exceptions and optionally include a value?

First some background:

I already have a Result class that I've implemented to carry result information. They were implemented particularly for failures, a success result generally carries no additional information. I use them in public methods at the outside of a core API in one of my projects, or in methods one or two layers deep where I need to carry detailed information back up to the public API. This API is consumed in-container and a command line client and was previously very checked exception happy. The alternative was adding this failure context information to the exceptions, and adding several more distinct exception classes, where they just didn't belong. I guess this reflects my general approach:

http://blogs.atlassian.com/2011/05/exceptions_are_bad

Result has a supporting enum and interface:

  1. ResultStatus: SUCCESS, FAILURE, CONDITIONAL_SUCCESS etc. Holds int return codes and generic messages (eg "Operation was successful")
  2. ResultCode: Empty interface for tagging enum result codes, FILE_NOT_FOUND, FILE_INVALID, FILE_INCOMPATIBLE. These are mostly for unit and functional testing, but are also used for online help (Maven's help on failure is functionally similar to what I'm doing)

Result provides static factory methods for the status, and builder methods to set the other key fields and is immutable. Here's what building a result looks like:

Result.success().withCode( ResultCode ).withMessage( "" );

And evaluating the returned Result:

result.isSuccessful();
result.hasCode( ResultCode );
result.getMessage();

My problem:

The approach has been very successful, particularly making functional tests a breeze, however I have one major gap: while in the majority of cases I only care about the Result, in some critical areas I need to return a value with the result.

I'm not happy with my first attempt: ResultPair<T> which contains the result and the value where T is the value's type. Unless I duplicate all of the Result methods, using the class is verbose and clumsy: get a Result, add it to a ResultPair, and fish the result and value out before evaluating. At first glance, inheritance won't work because of the builder pattern and I can't quite think of a way of getting clear, clean code that Result allows without duplicating the Result class completely.

Ideally, the approach would allow Result to return a value optionally, but I can't think of a way of doing it in a type safe way that ensures method signatures clearly indicate the type of the value, but avoids having a meaningless generic parameter everywhere I don't return a value.

I really don't mind having two classes and it's not the end of the world to duplicate the Result builder and evaluation code, it just feels wrong and I feel like a lack of experience is getting the better of me and I'm missing an (obvious or not so obvious) solution. I'm using Guava and I'll want to disallow null values in a friendly way, so may additionally wrap all values in a Optional, but I'd still need generic parameters (and compose it into the class to avoid result.value().get()... Okay, I'm thinking out loud now. I should ask a question...).

Is there a way of meeting these apparently mutually exclusive requirements?

like image 299
Danny Thomas Avatar asked Jan 13 '12 23:01

Danny Thomas


1 Answers

You could create your ResultPair<T> as a base class to the void result class:

public class Result extends ResultPair<Void> { ... }

All relevant methods would be declared in ResultPair<T>.

UPDATE:

Better yet, have just one type Result<T>, and use Result<Void> whenever you don't want to have a return value. Or rather, if using Void as a type argument looks weird to you, create a new uninstantiatable (or singleton) type that means "there's no result", and use it instead: Result<Unit>, for example.

like image 83
Jordão Avatar answered Sep 30 '22 02:09

Jordão