Code review: Simple template string parser


#21

An inconvenient with "%{print_user}{user}a" is that the format string is no longer serializable easily, which can make it harder to translate them by reading an on-disk translation file for instance.


#22

If we think of template syntax as shuffling the argument application order (I think that the most reasonable semantics is to evaluate the template arguments in-order to values, at the moment the format string itself is evaluated), then I think that "%a" would be an equivalent format string to serialize.

Edit: I had in mind a rewrite at the type-checking stage, but I think that this cannot work before the format consumer is known, so now I see that this would require adding new information to the format structure; in that case it may be that the equivalence proposed above doesn’t work. More thinking required!


#23

Could this be implemented as a syntactical transformation at the AST level?

"Hello %{user.name}s, your account is %{account_number user}d."

to

Printf.sprintf "Hello %s, your account is %d" user.name (account_number user)

#24

I think this transformation is quite feasible, though it might be reasonable, if types are present, to simply guess that the first, since it is a string, should be interpolated as is, and the second, since it is an integer, should be turned into a string. Then you don’t need the s and d at all. Types are great things.


#25

The format conveys more than the type. Consider %5.2f and %5LX.


#26

So, sometimes you want to express things like %5.2f but mostly you don’t. The default case should let you be lazy (and simple) while still allowing complicated things. Perhaps:

"Hello %{user.name}, your account is %{account_number user}."

and to allow full formatting to be expressed:

"Hello! This float is %&5.2f{some_float}"

Though the specifics of that syntax need to be worked out, that looks slightly off.


#27

Except all this doesn’t work with type inference, unless you use modular implicits. Consider the function let f x = Format.printf "Foo %{x}". What’s the type of x ? No, you can’t “fall down” to string without breaking lot’s of other properties in the typesystem.
You can do it with modular implicits by assuming a Printable signature, then you get f : {P:Printable} => P.t -> unit.

Also, good luck writing a reliable type-directed transformation like that without basically putting it in the typechecker. :wink:

As for the rest, people here might be interested by https://github.com/janestreet/ppx_custom_printf


#28

Yah, true. I hadn’t been thinking clearly. Yet another thing that you need Modular Implicits for. :frowning: