views:

143

answers:

6

When a function returns a boolean you can easily

if (task()){
   // it worked!
}else{
   // it failed.
}

But when it returns multiple different values it gets messier

var status = task();
if (status == 1){
   // hmm
}else if (status == 2){
   // hmmmmm
}else if (status == 3){
   // hmmmmmmmm!
}

..is there a neater way of handling it?

Edit: In response to the answers that recommend switch statements, yes I know about those. I was asking for something neater than even that?

+1  A: 

Most languages have a switch statement, something like:

switch (task()) {
   case 1: // do stuff
      break;
   case 2: // other stuff
      break;
   /// etc.
   default: // what?!
      Error("Unhandleable status code");
}
Mark Rushakoff
+4  A: 

I can't tell what language you are using (JavaScript?) but I generally write code like this:

var result = task();

switch (result)
{
    case 1:
        handleStatus1();
        break;
    case 2:
        handleStatus2();
        break;
    default:
        handleEverythingElse();
        break;
}
bobbymcr
+1 for separating into single-purpose routines
Rex M
A: 

If you're talking about an integer or other primitive return type, the best approach I know is the switch statement.

switch (status)
{
case 1:
  // hmm
  break;
case 2:
  // hmmm
  break;
}

However, if you're returning an object that defines the behavior following the method call things become much neater.

Say you have an interface ISomething and two (or more) objects that implement that interface (ASomething and BSomething). If the method's return type is ISomething, the code becomes:

ISomething result = task();
result.DoSomething();
Eric J.
+1  A: 

Depends on a language's possibilities, but I'd do something like this in JavaScript:

var handle_task_1 = function () {
    // handle task 1
};

var handle_task_2 = function () {
    // handle task 2
};

var tasks = {
    1: handle_task_1,
    2: handle_task_2,

    "default": function() {},
};

tasks[task()]();

// Or, with a default action. But it may be too much for some people :)
(tasks[task()] || tasks["default"])();
Ionuț G. Stan
This is very brittle code - it requires Task() to stay synchronized with an external, static sequence. If you want Task() to yield its resultant action, you might as well have it return the handle_task function. If not, the switch statement is more appropriate, as it decouples the two.
Rex M
+1 - You lookup an object of functions, based upon the task()'s return value, then call the returned function. Simply brilliant!
Jenko
"to stay synchronized with an external, static sequence" -- does one care?
Jenko
@Rex M, is just a like a switch statement, except it doesn't have a default branch. That's the single thing missing from it. Everything else is mere code formatting :)
Ionuț G. Stan
...although there are solutions to provide default actions even in this case.
Ionuț G. Stan
Not at all LOLThis is very used when building client/server protocols, where this tasks[] array would be an array of all possible "block type" coming from the peer, and you easily deliver it to the proper handle. Right after checking if its a valid type, of course.
Havenard
Note this is commonly done in Python, which doesn't have switch statements. And it's not `task()` that depends on `tasks`, it's `tasks` that depends on `task()`.
outis
@Ionut it's not quite the same as switch - it's an object structure instead of program flow. There's more than a semantic difference there.
Rex M
+1  A: 

If you have many chained if commands each executing a unique block of code, you might consider using a map of simple functor classes. Ideally, the application's startup would populate that map and you can just call the actions from an instance of that map

The code would look like this

Action action = (Action) contextMap.get(task());
action.do();

This has the advantage that adding new tasks requires only defining a new class for that task and adding it to the contextMap on startup.

There are some other nice things about this approach

  1. taskA() and taskB() can share the same contextMap and even some of the same Actions so you have less code duplication
  2. Actions can be unit tested more easily (usually)
  3. Sharing of code between actions will be easy without ending up with spaghetti code or complex if(status > 2 && status !=7 ) statements

And of course, interfaces, varargs and other syntactic sugar helps here.

sal
A: 

Maybe you are looking for exceptions?

Then you don't need to clutter your code for the successful case, and for the various error cases you can throw different exceptions as necessary.

starblue
A novel solution. Never thought of that one :)
Jenko