5

After exposing to Windows App Store development for a month, I begin to feel that async / await programming model does more harm than good. It makes simple thing complicated.

Take an example, folder creation. In Java or Desktop .NET, I can simply do

Java

public Constructor()
{
    new File("c:\\folder").mkdirs();
    System.out.println("I am pretty sure c:\\folder is ready now");
}

Desktop .NET

Constructor()
{
    System.IO.Directory.CreateDirectory("c:\\folder");
    Console.WriteLine("I am pretty sure c:\\folder is ready now");
}

But when comes to

Windows App Store .NET

Constructor()
{
    // Damm it! Another async function? I don't need aysnc!
    Windows.Storage.ApplicationData.Current.LocalFolder.CreateFolderAsync("c:\\folder", CreationCollisionOption.OpenIfExists);
    // I am not sure c:\\folder is ready right now!
    // OK. I know I can use ContinueWith. No no no. I don't want.
    // Why I have to use ContinueWith with such a simple operation?
}

So, my question is, do you find the newly introduced async / await programming model in Windows App Store,

  • Improve your productivity?
  • Make programming life easier?

For me, I don't! Perhaps I have been missing out certain useful techniques.

I know, Microsoft says, it helps us to write responsive UI code.

But I would say, No thanks! Hey look, my code is already in non-UI code!

Most of my current operation code is fast enough and doesn't block UI. When my operation code is not fast enough, I am pretty comfortable in making those slow operation code run in separate Thread/ Task.

Forcing me to use async / await which I do not need, only makes my code more complicated.

Message to Microsoft : May I beg to you, besides async functions, can you provide a same set of non-async functions, please? I already build up my habit of running code in non-UI thread. I promise I will continue make your Windows App perform as smooth as iOS :)

7 Answers7

13

The problem here isn't the async/await keywords but the fact that many WinRT APIs are only offered in an async form. In the past, APIs have been offered in a blocking form, or your choice of blocking and non-blocking, and developers were supposed to make sure the UI didn't hang. Well guess what? Developers didn't bother. I've waited multiple minutes for a Print dialog in an Office product to finish timing out on contacting whatever printer I used last time, before I could specify that I don't want that printer, usually because that printer is now thousands of miles from me. The vast majority of applications were written the easy way for the developer even though that might create a bad experience for the user.

So the new API has no blocking form. You have to learn how to do it asynchronously, like it or not. You could set up a completed handler and then start the process, or you could use the new C# keywords. Your choice. But developers will no longer be trusted to keep the promise you offer to make. And rightly so, since almost no-one did.

Kate Gregory
  • 17,495
10

You're probably holding it wrong (just some context for the statement).

Unfortunately I haven't had a chance to play with Win8 yet, but based on code examples I've seen, your code should look more like

Constructor()
{
    // Damm it! Another async function? I don't need aysnc!
    var result = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFolderAsync("c:\\folder", CreationCollisionOption.OpenIfExists);
    // by the time your code gets to this line, the folder will have been created
}

The other option (if you can't make your method async) is to block the thread until async opertation completes by calling GetResults. Probably something along the lines of

Constructor()
{
    // Damm it! Another async function? I don't need aysnc!
    var result = Windows.Storage.ApplicationData.Current.LocalFolder.CreateFolderAsync("c:\\folder", CreationCollisionOption.OpenIfExists);
    result.GetResults();
    result.Close(); // According to documentation, you should call this when done
    // Voila, 
}

Though it looks like you're doing file IO inside a constructor and you probably can't have async constructors, so the first option is out. I assume this this is just some contrived example and not representative of your code, but my feeling is if you find yourself doing IO inside a constructor and you're not writing a framework class (like FileInfo), you should take a second look at your design. I generally don't expect newing up a class to start creating/locking system resources.

There are a couple of related questions on StackOverflow regarding constructors and async

Roman
  • 761
5

I think, in something of a departure for Microsoft, they have thought about what makes for the best user experience rather than what makes for the easiest developer experience.

Certainly adopting the async model requires more work on the part of the developer, but just maybe gives that developer a better chance of producing something that will be responsive to the user.

You only need to use Outlook to see how bad the user experience can be if you follow a synchronous programming model too much.

Martin
  • 521
  • 2
  • 10
2

await was introduced with .NET v4.5 and is actually a way to break the pure asynchronous approach. So it's there as a way to simplify coding with asynchronous methods / calls.

It can also be abused if you put await on every single one of your calls. At that point, you're back to "traditional" coding styles where you have to wait for all actions to return.

Asynch is a useful approach when you're making calls across a network or when other actions can continue while awaiting the results of the call. It's equivalent to using a background thread to handle some form of data processing. The rest of the app continues along until the task is done.

As you noted in your example, there are some cases where you simply have to wait until a call completes before operations can continue. That's where the await keyword comes in handy. An alternative was to have a callback method that the performed the rest of the processing. Honestly, that alternative is less than elegant, and I'm glad that await was offered up.

So, just like with any other tool:

  • Use asynchronous methods as appropriate for the calls your app is making.
  • Use the await keyword judiciously when there are calls that really must block the rest of the operations. Don't overuse the keyword as that will hamper your application.
2

Actually, Async/Await makes an unnecessarily complicated thing much simpler. (Just imagine if you had to do all that without Async/Await!) The unnecessarily complicated part is Microsoft's decision to make all those APIs async-only, instead of leaving it up to the discretion of the developers.

Mason Wheeler
  • 83,213
2

I see that the problem here is that you can't use await in a constructor and that GetResult won't work. But have you tought about using a static helper method to create your object?

class AsyncCreated
{
    public static async Task<AsyncCreated> CreateWithFolder()
    {
        var folder = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFolderAsync("c:\\folder", CreationCollisionOption.OpenIfExists);

        return new AsyncCreated(folder); // There you do the usual stuff
    }

}

// elsewhere in your code

var myObject = await AsyncCreated.CreateWithFolder();

The added bonus is that now it's more explicit that some work is being done while you initialise the type.

1

It might.

But what's probably really happening is that it is keeping complicated things complicated.

Creating a file is complicated. It can be over a network share. It can already exist. The hard drive might be slow. It might be a RAM disk. Point is, it can take different amounts of time, or might outright fail.

Jeff Atwood wrote a great post about this 8 years ago. He basically said that we should embrace multithreading and asyncronous code, but most developers aren't prepared to deal with it because it's a very complex topic, and the tools at the time weren't suitable to make it easy enough to write asynchronous code.

The async and await keywords (along with other tools, like the thread-safe collections) are Microsoft's answer to his request to improve the tools to bring easy async programming to the unwashed masses. My opinion is that they have mostly succeeded. In that a majority of cases, you can use the async APIs in WinRT as if they were not asynchronous, then just pepper in a few async and await keywords, compile and bask in the glow of responsive, non-blocking code.

Constructors, as well as a few more things, are where the limitations of the tools appear and trip up even the average programmer, who is just trying to write a program to do his job.

Jeff also commented that one reason why BeOS failed to attract developers was because, like WinRT, the entire OS API was asyncronous, and writing anything beyond a utility was torture. I think for the most part it's a small learning curve, but the tools are much more approachable than they were 8 years ago. We'll see how Microsoft fares in the future.