Beginner async question

Hi,

Trying to get the hang of async.

open Async
open Core

let out = Lazy.force Writer.stdout 
let inn = Lazy.force Reader.stdin 

let readOrTimeOut =
    Deferred.any
    [ (after (sec 3.0) >>| fun () -> "Timeout")
    ; Reader.read_line inn >>| (fun s -> match s with | `Eof -> "Empty" | `Ok str -> str)    
    ]

let run _ =
    upon (
    let rec loop () =
        readOrTimeOut >>=
        fun str ->
        Writer.write out ("You typed: " ^ str ^ "\n");
        Writer.flushed out
        >>= fun () -> loop()
    in loop () )
    (fun _ -> ())



let () =
  run ();
  never_returns (Scheduler.go ())

My question:

When I run the program, if I let it timeout, it will continuously display “You typed Timeout” as opposed to waiting for a timeout or input every time. Why i this happening?

readOrTimeOut has type string Deferred.t. Once a Deferred.t becomes determined with a value, that value never changes.

In your loop, calling readOrTimeout >>= <function> doesn’t cause a new Deferred.t to be created. It just keeps reading the value out of the same Deferred.t.

You probably want to make readOrTimeout be a function unit -> string Deferred.t instead, so that you can call this function and bind on a new deferred each time through the loop.

Thanks a lot! Now I am facing a different issue.
I get an exception, If I let it timeout, the program throws an exception stating that the reader is already in use. How can I prevent this error? How can I force the Reader,read_line to be “determined” even if the timeout case is hit?

I think this is the same issue that you encountered in a previous thread:

I’m not super familiar with async IO stuff, but Pipe.read_choice does sound like it’s designed for use cases just like yours.

Yes, thanks Pipe.read_choice did it for me.

open Async
open Core

let out = Lazy.force Writer.stdout 
let inn = Lazy.force Reader.stdin 

let stdinPipe = Reader.pipe inn

let readInput () =

  Deferred.choose
    [ Pipe.read_choice_single_consumer_exn stdinPipe [%here] |> Deferred.Choice.map ~f:Either.first
    ; Deferred.choice (after (sec 3.0)) (fun _ -> ()) |> Deferred.Choice.map ~f:Either.second
    ]  >>= function
  | First data -> 
    (match data with
    | `Eof -> return None
    | `Ok data -> return (Some data) )
  | Second _ -> return None    


let run _ =
    upon (
    let rec loop () =
        readInput () >>=
        function
        | None -> Writer.write out "You timed out!\n"; Writer.flushed out  >>= fun () -> loop()
        | Some s -> Writer.write out ("You typed: " ^ s ^ "\n"); Writer.flushed out  >>= fun () -> loop()
    in loop () )
    (fun _ -> ())



let () =
  run ();
  never_returns (Scheduler.go ())