0

I have been lately programming with the FSharpx library and especially its TaskBuilder. Now I wonder if it should be possible to define a function which takes parameters and takes a result. Such as

 let doTask(parameter:int) =
     let task = TaskBuilder(scheduler = TaskScheduler.Current)        
     task {
         return! Task.Factory.StartNew(fun() -> parameter + 1)
     } 

 match FSharpx.Task.run doTask(1) with
 | _ -> ()

Looking at the source code I see run expects a function taking no parameters and returning a Task<'a>. There doesn't look like being examples on FSharpx TaskTests either.

I'd appreciate if someone could advice how should I get a scenario like this going with FSharpx or if one isn't supposed to use the library like this for a reason I haven't quite grasped as of yet.

<edit: I believe I could wrap doTask as follows

 wrapperDoTask() = doTask(101)
 match FSharpx.Task.run wrapperDoTask with
 | _ -> ()

And it might work. I'm not with a compiler currently, so this is a bit of a handwaving. Does anyone have an opinion on any direction or did I just answer my own question? :)

<edit2: I think I need to edit this one more time based on MisterMetaphor's answer. Especially his P.S., I think, was well informing. I use FSharpx TaskBuilder to interop with C#, in which, as noted, tasks are returned as hot (with some minor exceptions), already running. This is in connection with my recent question Translating async-await C# code to F# with respect to the scheduler and in relation Orleans (I'll add some tags to beef up the context, maybe someone else is pondering these too).

When thinking in C# terms, what I try to achieve is to await the task result before returning, but without blocking. The behaviour I'm after is especially of that of await not .Result. The difference can be read, for instance, from

Trying to think which context or scheduler or behavior or something is going on in terms of C# is somewhat fuzzy for me. Unfortunatelly it looks like I can't ignore all the details when it comes to interop. :)

Veksi
  • 3,556
  • 3
  • 30
  • 69

1 Answers1

2

You need to use Task.run only if you want to wait for the task completion synchronously on the current thread. It takes a single parameter and you can consider that parameter a task factory -- i.e. a means to create a Task<_>. Unlike Async<_>, the Task<_> starts running as soon as it is created. That is not always a desirable behavior.

You could achieve similar results (a blocking wait for task completion) with (doTask 101).Result, but I think Task.run is more idiomatic to F#, in a way that it uses a Result return type to signal an error instead of raising an exception. It might be arguable which is better, depending on situation, but in my experience in simpler cases a special result type is more composable than exceptions.

Another point here is that you should avoid blocking waits (Task.run, .Wait(), .Result) as much as you can. (Ideally, you'd have one of those only at the top level of your program.)

P.S. This if out of scope of the question, but your doTask function looks funny. task { return! Task.Factory.StartNew( ... ) } is equivalent to Task.Factory.StartNew( ... ). What you probably wanted to do is task { return parameter + 1 }.

EDIT

So, in response to OP's question edit :) If you need the await behavior from C#, you just need to use let! .... Like this:

task {
    let! x = someTask 1 2 3
    return x + 5
}
MisterMetaphor
  • 5,900
  • 3
  • 24
  • 31
  • I'm not sure if I should elabore this on my question, but I'm using this library to interop with C# libraries and I suspect other new to F# have similar issues. Your *P.S.* gave me some *a-has* already! When it comes to threading, I'm "well familiar" with async-await (not an expert, the details seem to be aplenty always) and with regard to F# I've usually used the Async "as supposed to". This question stems from the C# land wherein some function returns a hot Task/Task<'a>, as you noted. I use ``TaskBuilder`` for interop and to collet results. Indeed, before returning, I'd like todo an "await" – Veksi Jul 27 '14 at 15:40
  • If you don't need sophisticated `TaskFactory` configuration, to interop with C# you probably can get away with just `Async.AwaitTask` and `Async.StartAsTask`. If that's the case, you can use plain `async` in your F# code. – MisterMetaphor Jul 27 '14 at 15:49
  • P.S. OK I've just noticed your [other](http://stackoverflow.com/questions/24813359/translating-async-await-c-sharp-code-to-f-with-respect-to-the-scheduler) question and I think you should stick with the FSharpx TaskBuilder :) – MisterMetaphor Jul 27 '14 at 15:52
  • Heh, indeed. I just edited my question. Maybe I've should done it the other way around. :) In any event, it's this *await* that's giving me some headache as that's the behavior I'd like to have and finding "mechanical patterns" so that I wouldn't need to mull this much of the details in my head. By the way, I need to think if there's something more to this story. If I don't come up with anything (or someone else), I'll accept this one. This "P.S." was a good one, thanks for taking the time to think and write it. – Veksi Jul 27 '14 at 15:59
  • Glad I could help. I've edited the answer and added response about `await`. – MisterMetaphor Jul 27 '14 at 16:04