[ANN] First Release of ppx_pyformat 0.1.1

Hello everyone!

I am very glad to announce the first release of ppx_pyformat!

ppx_pyformat is a ppxlib based rewriter inspired by Python string format() . This rewriter allows the user to do complex variable substitutions and value formatting. The format string syntax of ppx_pyformat is closely modeled after that of Python3.10 (with several enhancements). Most Python format strings should be compatible with ppx_pyformat with minor modifications. And the behavior is also very similar. So Python users should be able to quickly pick up this rewriter.

The rewriter takes a required format string following with optional input arguments. The rewriter will parse the format string, substitute/format the replacement fields and finally return everything as a single string.

For more details about this package, please check the README.md.

Here is some sample code

let _ =
  let hello = "Hello" in
  let world = "world" in
  print_endline [%pyformat "{hello} {world}!"]
(*Hello world!*)

let _ =
  print_endline [%pyformat "pi = {Float.pi:.10f}"]
(*pi = 3.141592653*)

let _ =
  let string_of_tuple (a, b) = "("^a^", "^b^")" in
  print_endline [%pyformat "{!string_of_tuple}"; ("foo", "bar")]
(*(foo, bar)*)

let _ =
  print_endline [%pyformat "the answer to life the universe and everything {0:#020_b}"; 42]
(*the answer to life the universe and everything 0b000_0000_0010_1010*)

Hope this plugin can make logging/debugging in OCaml a bit easier. Feel free to leave any feedback! Thanks.

12 Likes

How is this better than printf?
Printf.prinf and Scanf.sscanf are very powerful things, once you know them a little.

Yes, they are very powerful but I found them hard to use when you have multiple inputs. Having the variable name inside the string is much more intuitive and easy to track/debug. It also allow to do different alignment, grouping (1,000 instead of 1000) and other formatting.

4 Likes

Thank you, this is lovely! I’ve always wished for Python-style formatting primitives in OCaml. Sometimes they’re not right; but sometimes they are.

3 Likes

Using ^ for concatenation for each elements looks inefficient. Generating a call to String.concat "" should be more efficient and quite comparable in term of complexity for the code generator.

1 Like

Thanks for the great suggestion! I will definitely test the performance of ^ vs concat. This is only the first version, so it’s not very polished performance wise :wink:.

Looks similar to GitHub - janestreet/ppx_string: ppx extension for string interpolation. There might be some ideas you could borrow.

3 Likes

Regarding performance, you could also use a Buffer.t, this what i use in GitHub - EmileTrotignon/embedded_ocaml_templates.

It seems Buffer.t is wrapped around Bytes.t. So I think it is more efficient to just use bytes directly. Especially, you can also get access to some low-level API i.e. caml_blit_string etc.

You cannot append stuff at the end of a Bytes.t, that’s what Buffer.t is for.