6

I'm creating a type in F# that inherits from a C# class that exposes a method that returns Task<T> in C#. I'm trying to work out what'd be the best way to do that in F#

Say my C# looks like this:

public class Foo {
    public TextWriter Out { get { return Console.Out; } }

    public virtual Task<SomeEnum> DoStuff() {
        return Task.FromResult(SomeEnum.Foo);
    } 
}

public enum SomeEnum {
    Foo,
    Bar
}

My first pass of inheriting that type in F# looks like so:

type Bar() =
    inherits Foo()

    override this.DoStuff() =
        this.Out.WriteLineAsync("hey from F#") |> ignore

        System.Threading.Task.FromResult(SomeEnum.Bar)

But a) it doesn't feel like it's actually async and b) it just feels not-F#.

So how would I go about inheriting the Foo class and implement the DoStuff method that expects to return a Task<T>?

Aaron Powell
  • 24,927
  • 18
  • 98
  • 150
  • 1
    Is your actual method really just returning a constant? Because it doesn't make sense to do that in a way that's "actually async". If that is the case, `Task.FromResult()` is the right solution both in C# and F#. – svick Jun 12 '15 at 01:59
  • We can assume that the value to be returned will be based off some logic. – Aaron Powell Jun 12 '15 at 02:16
  • But is that logic doing any inherently asynchronous work (e.g. accessing the file system or the network)? Or could it take relatively long time (say, more than 50 ms)? – svick Jun 12 '15 at 02:21
  • Yep, file system, network, db, etc could be the async stuff that is done here. The base class also does expose a `TextWriter` to write to the output stream (console, network stream, etc) which is why I used it in my example there. – Aaron Powell Jun 12 '15 at 03:44
  • [slightly] Related: http://stackoverflow.com/questions/25605130/testing-f-async-workflows-with-xunit-nets-task-support – Ruben Bartelink Jun 12 '15 at 09:06

3 Answers3

13

You can use Async.StartAsTask:

type Bar() =
    inherit Foo()
    override this.DoStuff() =
        async { return SomeEnum.Bar } |> Async.StartAsTask

Async.StartAsTask takes Async<T> as input, and returns a Task<T>.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
2

The F# way of doing async is using asynchronous workflows. Unfortunately, they don't support awaiting non-generic Tasks. But using one of the workarounds from the above question, your code could look like this:

override this.DoStuff() =
    async {
        do! this.Out.WriteLineAsync("hey from F#") |> Async.AwaitVoidTask
        return SomeEnum.Bar
    } |> Async.StartAsTask
Community
  • 1
  • 1
svick
  • 236,525
  • 50
  • 385
  • 514
-1

I believe the FSharp way of wrapping over tasks is to use

var a = Async.AwaitIAsyncResult(somecsharpreturningtask) |> ignore
Craig Bruce
  • 674
  • 1
  • 8
  • 18