7

It is sometimes necessary to try/catch exceptions inside the "if" condition, but not the body that follows. In C#, this is really rather cumbersome, requiring locals and code that isn't entirely obvious, at a glance, as to its operation.

It is also sometimes necessary to write "switch" statements, which, unlike "if", have more than two possible outcomes, although in C# this requires the use of a fairly unpopular syntax.

Here's an idea for combining these.

Merging switch with try/catch

First, we change the fundamental syntax of "switch" to be close to that fairly popular replacement, but without the extra curlies:

switch (condition)
    case 1 { }
    case 2 { }
    default { }

Next, we make it possible to catch exceptions in the condition. Under the hood, this inserts an appropriate try/catch block only when at least one catch is present:

switch (condition)
    catch FileNotFoundException e { } // use "e"
    catch ArgumentException { }
    catch { }
    case 1 { }
    case 2 { }
    default { }

Now we make it easier to chain several such statements akin to if/else chaining, by moving "default" one level up, and renaming it to "else":

switch (condition1)
    catch FileNotFoundException { }
    case 1 { }
    case 2 { }
else switch (condition2)
    case "abc" { }
    case "def" { }
else
    { }

And so we have a switch merged with try/catch!

Combining with 'if'

Both switch and if now have else clauses, so why not allow you to mix them as you please:

if (bool-condition1)
    { }
else if (bool-condition2)
    { }
else switch (string-expr)
    catch FileNotFoundException { }
    case "thing" { }
else
    { }

(thanks ach_l!)

Further improvements

Switching on a list or range of values has been proposed and can be easily incorporated:

switch (int-expression)
    case 1 { }
    case 2, 5 { }
    case 10..50 { }
else switch (string-expression)
    case "abc" { }
    case "def" { }
else if (boolean-condition3)
    { }
else
    { }

In this case it could be really convenient to be able to reference the value in the condition clause. This can be easily incorporated by allowing one to declare a single variable in this clause the same way C#'s using allows:

switch (var z = int-expression)
    case 2, 5 { return z == 2 ? "two" : "five"; }
    case 10..50 { return (z * 10).ToString(); }

Benefits

Among other benefits, one can now express a common error-handling scenario concisely, and yet not WTFy:

switch (bool-condition)
    catch FileNotFoundException e { }
    case true { }
    case false { }

Would this solve any real-life coding difficulties you have encountered? Are there any tweaks you would apply to this?

2
  • 2
    I have blogged about this before and how cumbersome the differences between if and switch are. I like the way you did it, personally
    – Earlz
    Apr 17, 2011 at 4:14
  • I've removed the final step of making if/switch the same statement, and instead incorporated ach_l's idea of allowing one to use them interchangeably. Apr 17, 2011 at 10:59

1 Answer 1

4

Personally I would leave if as evaluating a boolean argument with a true path and optional false else path, whereas switch could evaluate other objects for equality, membership of a set, etc. It may not be a good reason, but this is the behaviour of if in many other languages. To change that definition I think we would risk confusing new programmers.

But I could definately see this syntax of catch blocks being handy, and the ability to chain together ifs and switches might also have a use case.

Personally I tend to like a style where the name of the argument is defined by the block, Additionally, if the value of a condition is being evaluated, we could optionally provide it to the case blocks as well!

Perhaps this example may shed light on the scope of what I'm thinking building on this:

if(<boolean>condition1)
    catch Exception { e -> /* exception referenced by e */ } 
    { /*true*/ } 
else switch(<any>condition2) 
   catch FileNotFoundException { /* I don't care about this exception*/ }
   case 1 {  /* I don't need condition2's value */  }
   case 2, 5, 10 .. 20 { v -> /* v is condition 2 value */ } 
   case <50 { x -> /* x is condition 2's value, this would only be evaluated if other branches are not */}
else 
   { /* !condition1 and no case evaluated in condition 2 */ }
4
  • Regarding the first paragraph: perhaps I didn't make it clear enough, but in this proposal, standard "if"s look exactly the same as before. As for the rest of it - how about the keyword value can be used to access the condition's value, just like in C#'s property setter. Apr 16, 2011 at 18:45
  • 2
    @romkyns: Then value can only ever refer to the innermost nested block. Then you’d need extra locals if you need to refer to an outer one, which would be annoying.
    – Timwi
    Apr 16, 2011 at 18:51
  • Good point, @Timwi, that would be annoying. if (var z = <condition>) then? Apr 16, 2011 at 18:51
  • I like the idea of if/switch in else. It's less controversial and also makes more sense: instead of allowing one to collapse case true just keep if separate. Updated the description. (I'm not so sure about allowing catch on if: if you want that it may be more readable to simply use switch with a catch and a case true clause). Apr 17, 2011 at 10:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.