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

First, a little background:

I already have a Result class that I implemented to transfer information about the results. They were implemented, in particular, for failures, the result of success, as a rule, does not contain additional information. I use them in public methods outside the main API in one of my projects or in methods located on one or two levels where I need to carry detailed information supported by the public API. This API is consumed in the container and the command line client and was previously a very proven exception. An alternative was to add this disclaimer context information to the exceptions and add a few more separate exception classes where they simply did not belong. I think this reflects my general approach:

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

The result has enumeration and interface support:

  • ResultStatus: SUCCESS, FAULT, CONDITIONAL_SUCCESS, etc. Holds return codes and general messages (for example, "Operation completed successfully")
  • ResultCode: empty interface for tagging result codes, FILE_NOT_FOUND, FILE_INVALID, FILE_INCOMPATIBLE. This is mainly for unit and functional testing, but also used for online help (Maven's help on failure is functionally similar to what I'm doing).

The result provides static factory methods for state and construction methods for setting other key fields and is immutable. Here what construction looks like this:

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

And evaluation of the return result:

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

My problem:

This approach was very successful, especially in order to make functional tests easy, but I have one main gap: while in most cases I care only about the results, in some critical areas I need to return the value with the result,

I am not happy with my first attempt: ResultPair<T> , which contains the result and value, where T is the type of value. If I donโ€™t duplicate all the Result methods, using the class is detailed and awkward: get the result, add it to ResultPair and knock out the result and value before evaluating. At first glance, inheritance will not work due to the builder pattern, and I canโ€™t think of a way to get a clear, clean code that produces a result without completely duplicating the result class.

Ideally, this approach would allow the Result to return a value optionally, but I cannot think of a way to make it a safe type, which ensures that method signatures clearly indicate the type of value, but avoids a meaningless general parameter everywhere I do not return a value.

I really do not mind having two classes, and this is not the end of the world to duplicate the results builder and evaluation code, it just feels wrong and I feel that lack of experience improves me, m there is no (obvious or not so obvious) solution. I use Guava and I want to disable null values โ€‹โ€‹in a friendly way, so I can optionally wrap all the values โ€‹โ€‹in Optional, but I still need general parameters (and put it in a class to avoid result.value (). Get () ... OK, Iโ€™m thinking out loud now. I have to ask a question ...).

Is there a way to satisfy these apparently mutually exclusive requirements?

+6
source share
1 answer

You can create your ResultPair<T> as a base class for the void result class:

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

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

UPDATE

Even better, use only one type of Result<T> and use Result<Void> whenever you do not want to have a return value. Rather, if using Void as a type argument looks strange to you, create a new uninstantiatable (or singleton) type that means "no result", and use it instead: Result<Unit> , for example.

+2
source

Source: https://habr.com/ru/post/905951/


All Articles