Randoom a Michael Friis production

Posted
14 October 2008 @ 11pm

Categories
C#, LINQ

You're reading Randoom, a Michael Friis production

Smuggling exceptions out of try-catches with IEnumerable

The code in this post is from a talk by Erik Meijer, I claim no credit.

Take a look at this screenshot:

Exception thrown from try-catch

Pretty wacky huh? Visual Studio has broken into debug mode even though the division is clearly wrapped in a try-catch. Take a guess at what’s going on before reading on.

Here’s the full code listing:

static void Main(string[] args)
{
    var xs = new[] { 1, 2, 3, 0 };
    IEnumerable q = null;

    try
    {
        q = from x in xs select 1 / x;
    }
    catch { }

    foreach (var z in q)
    {
        Console.WriteLine(z);
    }
}

The obvious expectation is that division-by-zero will be caught by the try-catch. Alas, the division does not happen in the scope of the try statement. Instead, due to the deferred execution paradigm of IEnumerable, it happens on a by-need basis in the for-loop. From there the exception can propogate unopposed to the top af the stack. Haskell, where lazy evaluation dominates, avoids exceptions (and other messy side effects) alltogether, partly for reasons demonstrated by this example.

UPDATE: As Wayne points out, fixing this is as easy as extending the try to cover the enumeration. The point of this post was mainly to poke fun at the Visual Studio debugger and to point out that lazy evaluation can bite you if you’re not careful.


3 Comments

Posted by
Antoine
23 October 2008 @ 8pm

In my Haskell interpreter:

> 1 `div` 0
*** Exception: divide by zero

For working with exceptions in Haskell:

http://haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html


Posted by
Jonathan Allen
24 October 2008 @ 12am

You know, 99% of the time you don’t want to hold onto the query anyways. Evaluating it as a list as soon as possible is almost always the right thing to do, especially if there is a chance you need the data more than once.


Posted by
Wayne
24 October 2008 @ 4am

You wouldn’t write code like that if you understood that your query is actually evaluated on enumeration, not on assignment.

you would write:

try
{
q = from x in xs select 1 / x;

foreach (var z in q)
{
Console.WriteLine(z);
}
}
catch{ }


Leave a Comment