views:

64

answers:

5

Suppose you have an method on an object that given the some input alters the objects state if the input validates according to some complex logic.

Now suppose that when the input doesn't validate, it can be due to several different things, each of which we would like to be able to deal with in different ways.

I'm sure many of you are thinking: That's what exceptions are for! I've thought of this also.

But my reservation against using exceptions is that in some cases there is nothing exceptional about the input not validating and I really would like to avoid using exceptions to control what is really just in the expected flow of the program.

If there were only one interpretation possible, I could simply choose to return a boolean value indicating whether or not the operation resulted in a state change or not and the respond appropriately when it did not.

There is of course also the option to return a status code which the client can then choose to interpret or not. I don't like this much either because there is nothing semantic about status codes.

The solution I have so far is to always check for each possible situation which I am able to handle before I call the method which then returns a boolean to inform the client if the object changed state. This leaves me the flexibility to handle as few or as many as the possible situations as I wish depending on the context I am in. It also has the benefit of making the method I am calling simpler to write. The drawback is that there is quite a lot of duplication in the client code wherever I call the method.

Which of these solutions do you prefer and why?

What other patterns do people use for providing meaningful feedback from functions? I know that some languages support multiple return values, and I if I had that option I would surely prefer it.

+1  A: 

The return value is not the only out value of the method, you can have "out" parameters, or pass other objects as references. For example, as well as the input to validate, you could for example pass an additional object to the method - a "tracker" which the method fills in with details of the validity of the input, and details of the state change.

You could still keep the boolean as a general success/fail flag. Some clients may not care for the details, and will pass a null reference for the tracker, relying only on the return value. Other clients may want all the details, and so will use only the tracker to determine if the state was changed.

Crucially, by allowing the client to pass in the tracker, the client can indicate how much detail to collect and decides what is done with the information. Some of it may be expensive to compute, or heavy on memory to keep around. Having the tracker as a parameter, and not just the return value, allows the client to provide the implementation that is most appropriate. The tracker class can include flags and other signals that the client sets, which indicate to the validator what information the client wants from the validation.

For convenience, you could also have a method that returns a tracker, but this is really syntactic sugar. E.g. (in psudo-java)

   interface ValidationResult  {
      List<ValidationError> validationErrors();  
      boolean isValid();      
      List<StateChange> stateChanges();
      boolean hasChanged();
   }

   public class AbstractValidationResult extends ValidationResult {
      // provides setters for properties. Make setter available to
      // the StateChangeValidator, but hides these from the ValidationResult
      // interface that general clients use.
      public void setValid(boolean valid) {
          this.valid = valid;
      }
   }

   class DefaultValidationResult : AbstractValidationResult {
       // default implementation
   }

   // your input validationg/state changing class
   class StateChangeValidator 
   {
        // convenience method
        public ValidationResult setState(Input intput)
        {
           return setState(input, new DefaultValidationResult());
        }

        // implementation allows clients to specify how the validation is handled.
        public ValidationResult setState(Input input, AbstactValidationResult result)
        {
           validate(input, result);
           changeState(input);
           return result;
        }

        // just validation - no actual state change
        public ValidationResult validate(Input input, AbstractValidationResult result)
        {
           result.setvalid(!hasErrors);
           return result;               
        }
   }

Which ever approach you choose, you should be able to avoid duplicating the validation behaviour outside of the class.

It can also be useful to separate out a "validate" method on your object that validates the input but doesn't actually make the state change. This pattern can be useful when prevalidating input, such as when enabling the OK button in a UI.

mdma
+1  A: 

I think this is a case of using primitives when you would be better off with objects. I handle this in my own code by returning status objects. These objects allow you to encapsulate both a simple 'it worked/didn't work' boolean flag, and provide additional information about why a failure occurred, or other relavant meta-data, such as a description of some state change.

This is similar to the 'tracker' idea described in mdma's answer. How deeply the status object is introspected is up to the client. A client that doesn't care about details can just check the status.was_successful() method. The difference is that I would return the 'tracker' directly, rather than pass it in as a reference. This keeps the calling interface much simpler.

Returning an object also effectively handles any need for multiple return parameters, since you can just encapsulate everything you need in the single status object.

ire_and_curses
A: 

Status code can be semantic if you don't use plain numbers and replace them with some sort of constants. For example, when dealing with file uploads in PHP, you deal with explicit constants like UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE and so on. Of course it gets messy when you use plain numbers such as 1, 2, 3 because you don't know what they mean right away. But constants provide an elegant way for the status code to mean something.

Savageman
A: 

why don't use one of Strategy or Template method patterns. I would choose Template method. Say your function has complex logic and input parameter is an interface with status and description properties.So after the function returns you get input object with filled Status and Description info. Moreover this ingerface may be implemented by different "input" classes.

Arseny
A: 

On think that could be used is lambda/closure (depending on what you need). In smalltalk here what you do.

dic at: #foo ifAbsent: [ 'do something interesting' ]

Here you can see that whenever you can't find something in your dictionary you evaluate the block. This could be apply to your problem.: Whenever you don't validate the input ask the sender what to do by evaluating a closure.

Simple, isn't it?

mathk