0

Why does casting a value declaration instead of a function argument result in different behavior?

The following operation hangs:

let duration = uint32 500
...
brick.DirectCommand.TurnMotorAtPowerForTimeAsync(motors, power, duration, breakEnabled) |> ignore

The following operation succeeds:

brick.DirectCommand.TurnMotorAtPowerForTimeAsync(motors, power, uint32 500, breakEnabled) |> ignore

What's the difference?

Code:

let volume = 100
let frequency = uint16 1000
let duration = uint32 500
let power = 100
let motors = OutputPort.B ||| OutputPort.C
let breakEnabled = false

let moveAsync = async {

    let brick = Brick(UsbCommunication())

    brick.ConnectAsync() |> ignore
    brick.DirectCommand.TurnMotorAtPowerForTimeAsync(motors, power, duration, breakEnabled) |> ignore

    }

Async.RunSynchronously moveAsync
Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118
  • I know it's a new day when you ask a new question. Are you going for the badge with one positive question a day for x days? – Guy Coder Feb 21 '16 at 12:40
  • 1
    @ Guy Coder - Nope. Some people vote down my questions. I just really want to increase my worth. The more I learn, the more I practice, the more I demonstrate, the more I'm worth... – Scott Nimrod Feb 21 '16 at 12:43

1 Answers1

2

What you're doing is rather strange, you should read up on how to use async workflow. That said, what I would expect - provided that your functions indeed return Async<'a> - is something like this:

let moveAsync = 
    async {
        let brick = Brick(UsbCommunication())

        do! brick.ConnectAsync() |> Async.Ignore
        let! _ = brick.DirectCommand.TurnMotorAtPowerForTimeAsync(motors, power, duration, breakEnabled)
    }

You want to use let! or do! to compose async workflows - if you have an Async<'a> and don't care about the return value, you can also use Async.Ignore to turn it into Async<unit> (rather than plain ignore).

Edit: To clarify why I gave this answer - I cannot even imagine a scenario where you would face the problem as stated.

But the code you posted clearly has problems that in my opinion make it impossible to really reason about what is going on. Like returning Tasks (that may have been started or not) inside an async workflow without waiting for them to complete. If what this code does meets your expectations, I feel it's only by coincidence.

My intuition is that once you sort out these problems, you'll see that whichever way you pass in the duration argument is fine.

scrwtp
  • 13,437
  • 2
  • 26
  • 30
  • Thanks @scrwtp - However, I get the following build error: 'Task' is not compatible with 'Async<'a>' – Scott Nimrod Feb 21 '16 at 13:01
  • Well - in that case those functions return .NET `Tasks` rather then F# `Asyncs`, and you can't compose them directly. – scrwtp Feb 21 '16 at 13:07
  • 1
    Check this thread how to do deal with it: http://stackoverflow.com/questions/8022909/how-to-async-awaittask-on-plain-task-not-taskt – scrwtp Feb 21 '16 at 13:08
  • @ scrwtp - Thank you for providing me guidance on recommended practices. I have updated my code to reflect your guidance. However, I still am not aware of the answer regarding the subject of the question. I can post a separate question for you to post the above answer to give you credit if you'd like. – Scott Nimrod Feb 21 '16 at 13:35
  • 1
    Now that would clearly be putting the cart before the horse. Also, check the edit. – scrwtp Feb 21 '16 at 13:55