﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Ayende @ Rahien</title><link>http://ayende.com</link><description>Ayende @ Rahien</description><copyright>Copyright (C) Ayende Rahien  2004 - 2021 (c) 2026</copyright><ttl>60</ttl><item><title>Mauricio Scheffer commented on It uses async, run for the hills (On .Net 4.0)</title><description>Oren: what I mean is using Async.Catch ( http://msdn.microsoft.com/en-us/library/ee353899.aspx ) to wrap the exception into a Choice type. The F# async API offers this and makes exception handling really easy (even though the computation expression can already handle exceptions on its own, you can write a regular try/with within the async block to do it the imperative way). Examples: https://gist.github.com/3188428

I'm not aware of any similar function in the TPL API, probably because the TPL team didn't want to introduce a public Either (or Choice) ADT.

Yes, an unhandled exception will pop up in another thread as you explain. More reason to wrap exceptions in an Either type! :) Avoiding partial functions just makes programming in general much easier.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment20</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment20</guid><pubDate>Fri, 27 Jul 2012 15:03:10 GMT</pubDate></item><item><title>Ayende Rahien commented on It uses async, run for the hills (On .Net 4.0)</title><description>Mauricio,
Um, no, it isn't the case.
The issue is how do you handle an exception in an async task whose return value wasn't observed.
For example, what would happen here in the case of an error
				
			let fetchAsync (name, url:string) =
			    async {
			        let uri = new System.Uri(url)
			        let webClient = new WebClient()
			        let! html = webClient.AsyncDownloadString(uri)
			        printfn "Read %d characters for %s" html.Length name
			    } |&gt; Async.Start
</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment19</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment19</guid><pubDate>Fri, 27 Jul 2012 14:21:37 GMT</pubDate></item><item><title>Mauricio Scheffer commented on It uses async, run for the hills (On .Net 4.0)</title><description>What you really want here is to bring the exceptions *into* the type system, modeling it as an algebraic data type like everyone else (F#, Scala) does. Then you can easily manipulate the result of each computation through a functor, applicative or monad, without any surprises. 
The TPL team tried to hard to avoid ADTs in their API and these are the consequences. Luckily it's quite easy to wrap exceptions into an Either type.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment18</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment18</guid><pubDate>Fri, 27 Jul 2012 13:54:04 GMT</pubDate></item><item><title>Jerome Laban commented on It uses async, run for the hills (On .Net 4.0)</title><description>I wouldn't have said "run for the hills" only for .NET 4.0... Unfortunately, there is the similar pitfall in .NET 4.5, with async void. This can bring down the process the same way.

(Sorry for the plug, but I think it's relevant: http://www.jaylee.org/post/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.aspx)</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment17</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment17</guid><pubDate>Tue, 24 Jul 2012 12:25:12 GMT</pubDate></item><item><title>Carsten commented on It uses async, run for the hills (On .Net 4.0)</title><description>This must be why in 4.5 there is switch do silently swallow those Exceptions on the finalizer thread (well they did because of async/await) and it's even default if I remember correctly.

BTW: here is a good explanation of the thought that got into this: http://blogs.msdn.com/b/pfxteam/archive/2009/05/31/9674669.aspx
I think he is not wrong there.

We are programmers: we should know our tools and their limitation.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment16</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment16</guid><pubDate>Tue, 24 Jul 2012 04:37:28 GMT</pubDate></item><item><title>Aaron Murray commented on It uses async, run for the hills (On .Net 4.0)</title><description>This is the part where pervasive method chaining (thanks jQuery/desire for convenience) is just perpetuating bad practices in places where it has no business. That style is only prudent within a context that understands that failure handling is baked into those methods and when the return type doesn't get affected.

"Foo Bar".ToLower().Trim().ToUpper().TrimEnd() ... should never fail given the appropriate initial input (non-null string).

The example posted is just far too complicated to expect to have actually work in every case. I think Ayende's point is that the fun new convenience options were secretly masking a *new* very bad worst-case scenario that nobody's applications were created to handle (new exception case). 

This is just poor form by the .NET team...and they've been delivering tons of great stuff for the past few years, which makes the problem harder to swallow because it hurts so bad. 

</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment15</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment15</guid><pubDate>Mon, 23 Jul 2012 18:28:22 GMT</pubDate></item><item><title>tobi commented on It uses async, run for the hills (On .Net 4.0)</title><description>I want to stress that ignoring a tasks exception, disregarding the type of the exception, is equal to "catch {}". I abhor that practice because it tends to mask real bugs.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment14</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment14</guid><pubDate>Mon, 23 Jul 2012 17:16:43 GMT</pubDate></item><item><title>tobi commented on It uses async, run for the hills (On .Net 4.0)</title><description>I think the UnobservedExcetpion event is the right solution for this. You need to log those exceptions anyway.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment13</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment13</guid><pubDate>Mon, 23 Jul 2012 11:22:16 GMT</pubDate></item><item><title>tobi commented on It uses async, run for the hills (On .Net 4.0)</title><description>I kind of disagree with the fact that it is ok to intentionally have unobserved exception. That should only happen due to a bug, and should be logged. It should not bring down the process you certainly don't want to ignore exceptions.

Because that is just a "catch {}" which is clearly not acceptable.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment12</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment12</guid><pubDate>Mon, 23 Jul 2012 11:21:18 GMT</pubDate></item><item><title>Luke commented on It uses async, run for the hills (On .Net 4.0)</title><description>@Ayende: I agree completely. But if you want to do fire-and-forget async stuff on .NET4 then you don't have much option. Either handle UnobservedTaskException globally or handle the exceptions on a per-call basis. Although I guess that's the whole point of your original post: you need to be careful doing fire-and-forget async stuff on .NET4 :)</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment11</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment11</guid><pubDate>Mon, 23 Jul 2012 10:04:29 GMT</pubDate></item><item><title>Jesús commented on It uses async, run for the hills (On .Net 4.0)</title><description>I use something like this:

        public static Task&lt;TResult&gt; ObservedContinueWith&lt;TResult&gt;(this Task task, Func&lt;Task, TResult&gt; continuationFunction, TaskContinuationOptions continuationOptions)
        {
            return task.ContinueWith(t =&gt;
            {
                if (t.Status == TaskStatus.Faulted)
                {
                    throw t.Exception;
                }
                return continuationFunction(t);
            }, continuationOptions);
        }</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment10</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment10</guid><pubDate>Mon, 23 Jul 2012 10:02:58 GMT</pubDate></item><item><title>Luke commented on It uses async, run for the hills (On .Net 4.0)</title><description>And, of course, if you write a custom extension method you can use TaskCompletionSource behind-the-scenes so that you can return a plain Task rather than needing to call Unwrap on the Task&lt;Task&gt; that ContinueWith would return in my example above (not that it really makes any difference in this particular case).</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment9</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment9</guid><pubDate>Mon, 23 Jul 2012 10:01:46 GMT</pubDate></item><item><title>Ayende Rahien commented on It uses async, run for the hills (On .Net 4.0)</title><description>Luke,
The problem?
It is semantically the same as saying, what is the problem with those memory leaks? Just call free() on every alloc(), done.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment8</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment8</guid><pubDate>Mon, 23 Jul 2012 10:00:33 GMT</pubDate></item><item><title>Luke commented on It uses async, run for the hills (On .Net 4.0)</title><description>@Ayende: Good point, I didn't test before posting. The crux of it still stands though: something like .ContinueWith(task =&gt; { if (task.IsFaulted) LogExceptionOrSimplyIgnoreIt(task.Exception); return task; }) would do the trick, although it'd be preferable to wrap that into it's own extension method to keep everything clean.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment7</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment7</guid><pubDate>Mon, 23 Jul 2012 09:58:30 GMT</pubDate></item><item><title>Ayende Rahien commented on It uses async, run for the hills (On .Net 4.0)</title><description>Geert,
Because doing something like:

   var _ = task.Exception;

Will generate a warning about unused variable.
GC.KeepAlive is a no op, and it makes the compiler happy</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment6</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment6</guid><pubDate>Mon, 23 Jul 2012 09:48:52 GMT</pubDate></item><item><title>Ayende Rahien commented on It uses async, run for the hills (On .Net 4.0)</title><description>Luke,
If that will NOT fail, you'll get an error about unobserved cancelled task</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment5</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment5</guid><pubDate>Mon, 23 Jul 2012 09:48:12 GMT</pubDate></item><item><title>Geert Baeyaert commented on It uses async, run for the hills (On .Net 4.0)</title><description>Ayende,

Just curious, why do you use GC.KeepAlive?</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment4</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment4</guid><pubDate>Mon, 23 Jul 2012 09:47:45 GMT</pubDate></item><item><title>Luke commented on It uses async, run for the hills (On .Net 4.0)</title><description>Or -- if you feel that TaskScheduler.UnobservedTaskException is too much of a blunt instrument -- you could deal with errors on a per-call basis by tacking something like .ContinueWith(task =&gt; LogExceptionOrSimplyIgnoreIt(task.Exception), TaskContinuationOptions.OnlyOnFaulted) as the final continuation in the chain.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment3</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment3</guid><pubDate>Mon, 23 Jul 2012 09:43:14 GMT</pubDate></item><item><title>Mark commented on It uses async, run for the hills (On .Net 4.0)</title><description>Possibly a dirty hack, but is there any issue with just handling the TaskScheduler.UnobservedTaskException event to stop your process from crashing?</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment2</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment2</guid><pubDate>Mon, 23 Jul 2012 09:20:03 GMT</pubDate></item><item><title>Ali Kheyrollahi commented on It uses async, run for the hills (On .Net 4.0)</title><description>Well, ContinueWith without checking the exception or accessing .Result is suicide.

I suppose that code would be safe if you had used webRequest.GetResponseAsync().Result... assuming the method returns a task.</description><link>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment1</link><guid>http://ayende.com/157154/it-uses-async-run-for-the-hills-on-net-4-0#comment1</guid><pubDate>Mon, 23 Jul 2012 09:16:39 GMT</pubDate></item></channel></rss>