3
\$\begingroup\$

I'm working through Build Your Own Text Editor, a walkthrough of the code to an extremely small text editor for a posix terminal in C, but I'm attempting to follow along in-the-spirit with OCaml.

I've put together a function that wraps an parameter function with termcap stuff to get the terminal into raw mode. This code works, but it feels ugly to me, specifically the let res stuff near the end. I feel like there should be a way to either get the second Unix.tcsetattr into a finally like block, or otherwise "wrap" the call to f ().

How could I make this code more idiomatic? I'm quite new to OCaml, so any suggestions for restructuring this code would be useful.

module TermIO = struct
  let in_raw_mode (f: unit -> _) =
    let termio  = Unix.tcgetattr Unix.stdin in
    let termio' = { termio with
                    Unix.c_echo   = false ;
                    Unix.c_icanon = false 
                  } in
    Unix.tcsetattr Unix.stdin Unix.TCSAFLUSH termio' ;
    let res = f () in
    Unix.tcsetattr Unix.stdin Unix.TCSAFLUSH termio  ;
    res
end
\$\endgroup\$
  • \$\begingroup\$ Welcome to Code Review! As we all want to make our code more efficient or improve it in one way or another, try to write a title that summarizes what your code does, not what you want to get out of a review. \$\endgroup\$ – Phrancis Apr 7 '17 at 5:58
  • \$\begingroup\$ @Phrancis'DROPTABLEUsers-- edited the title, although it's a little unwieldy now. Hope that's better :) \$\endgroup\$ – Jon Raphaelson Apr 7 '17 at 6:01
  • 1
    \$\begingroup\$ Here, how's this? :) \$\endgroup\$ – Phrancis Apr 7 '17 at 6:03
1
\$\begingroup\$

The sad fact is that your code should be even uglier. If f() throws an exception, you won't restore the resources correctly.

Idiomatic OCaml recommends that a recurring pattern can be described with a function. So you would define a function that takes:

  • a resource ('a)
  • a function to execute with the resource ('a -> 'b)
  • and a function to free the resource ('a -> unit)

The signature becomes:

val bracket : 'a -> ('a -> 'b) -> ('a -> unit) -> 'b

The bracket function would do the ugly let res = f() thing, but also wrap it with a try-catch.

UPDATE: The next version of OCaml (v4.08.0) looks like it will have a finally-type function added to the standard library: https://github.com/ocaml/ocaml/pull/1855

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.