<div dir="ltr"><br><br><div class="gmail_extra"><div class="gmail_quote">On Fri, Mar 29, 2013 at 3:35 PM, Alain Frisch <span dir="ltr"><<a href="mailto:alain.frisch@lexifi.com" target="_blank">alain.frisch@lexifi.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I'd write it as:<br>
<br>
let add_register e body =<br>
let_in [pany, app (evar "ExceptionHandling.register") [e]] body<br>
<br>
which does not look so bad. This relies on the following definitions, which could go e.g. in a Ast_helper.Convenience module:<br>
<br>
let evar s = E.ident (mknoloc (Longident.parse s))<br>
let let_in l body = E.let_ Nonrecursive l b<br>
(* maybe with an optional argument for the recursive case *)<br>
let pany = P.any ()<br>
let app f args = apply f (List.map (fun a -> "", a) args)<br></blockquote><div><br></div><div>That is better indeed. I can only encourage you to add these kind of conveniences in the E submodule (or maybe somewhere else) as usage suggests that they are useful. I originally planned to report on that through proper (?) channels, but that got lost in the noise of things to do, sorry.<br>
<br></div><div>I'm still not sure that quasi-quotations are not a better approach, because the problem here is that the user has to learn a new interface to describe code fragments instead of using the syntax he's already familiar with. You have convincingly argued that the OCaml syntax cannot always be used to describe AST fragments (even in Camlp4, if you use the classic syntax in quotations some ambiguities force you to revert to plain AST constructors from time to time), and I hear the argument about fitting lots of small pieces together instead of inserting large chunks of code. I still have the intuition that those arguments are more relevant to the expert extension writer, and that for a large set of use cases that concern *simple* extensions and beginner extension writers, quasiquotations are still noticeably easier to use. That this feeling appears to be reflected by Xavier Clerc, which is one of the other early-triers of -ppx, gives me a hint that it may have some objective qualities.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
The rest of the code is interesting as well:<br>
<br>
Camlp4:<br>
<br>
value rec map_handler =<br>
let patvar = "__exn" in<br>
fun<br>
[ <:match_case@_loc< $m1$ | $m2$ >> -><br>
<:match_case< $map_handler m1$ | $map_handler m2$ >><br>
| <:match_case@_loc< $p$ when $w$ -> $e$ >> -><br>
<:match_case@_loc<<br>
($p$ as $lid:patvar$) when $w$ -> $add_debug_expr _loc patvar e$ >><br>
| m -> m ];<br>
<br>
value filter = object<br>
inherit Ast.map as super;<br>
method expr = fun<br>
[ <:expr@_loc< try $e$ with [ $h$ ] >> -><br>
<:expr< try $e$ with [ $map_handler h$ ] >><br>
| x -> super#expr x ];<br>
end;<br>
<br>
<br>
PPX:<br>
<br>
method expr e =<br>
let e = super#expr e in<br>
{ e with pexp_desc =<br>
match e.pexp_desc with<br>
| Pexp_try (body, handler) -><br>
let instrument_case (pat, body) =<br>
let patvar_str = "__exn" in<br>
let patvar = Location.mknoloc (Longident.parse patvar_str) in<br>
let pat = { pat with ppat_desc =<br>
Ppat_alias (pat, Location.mknoloc patvar_str) } in<br>
(pat, add_register patvar body) in<br>
Pexp_try (body, List.map instrument_case handler)<br>
| other -> other<br>
}<br>
<br>
<br>
This might be a matter of taste, but I prefer the PPX version, which I can read only by knowing about the Parsetree (which is required anyway to write any such code), a normal OCaml library. The quotation and anti-quotations in the Camlp4 version look very noisy, and it relies on a syntax I'm not familiar with (revised syntax) and syntactic extensions (quotations/antiquotations), with their own conventions ("<:match_case<", $lid:$). Since I'm not writing extensions every day, I really prefer having to learn how to use simple OCaml data types and libraries (Parsetree, Ast_helper) rather than to learn new syntax and new concepts. Also, I'd write the code above as:<br>
<br>
(* --> in Ast_helper.Convenience *)<br>
let palias p x = P.alias p (mknoloc x)<br>
let evar s = E.ident (mknoloc (Longident.parse s))<br>
...<br>
<br>
method expr e =<br>
let e = super#expr e in<br>
match e.pexp_desc with<br>
| Pexp_try (body, handler) -><br>
let instrument_case (pat, body) =<br>
(palias pat "__exn", add_register (evar "__exn") body)<br>
in<br>
{e with pexp_desc = Pexp_try (body, List.map instrument_case handler)}<br>
| e -> e</blockquote><div><br><br></div><div>I used this example specifically to discuss the quasiquotation feature, not as a general comparison of -ppx and Camlp4's extension writing facilities. I do agree that, in this example, the AST traversal framework of -ppx is in fact better than Camlp4's. This is related to the fact that the AST structure is simpler and more closely reflect the way I logically think about pieces of OCaml code: match only takes a (pattern * expr) list instead of being a recursive expression of nested branches. That's a plus for ppx's design (and I like your approach of improving the upstream AST description to make it even better, at least while we don't have extension writers with code that breaks when we change it).<br>
</div><div><br></div><div>That said, I think you're also a bit quick to jump to conclusions here. The question of whether the extension uses classical or revised syntax is largely orthogonal to the design of the extension itself (except occasionally with quotation ambiguities concerns), and I could have used the classic syntax to write the Camlp4 extension just as well. What happened in practice is that I looked at the set of old Camlp4 extensions I had lying around, copy-pasted the code of the one that looked most closely like what I was looking for (traversing the "match" structure), and spent the rest of the time wondering which output code to produce (the "add_register" function I quoted, plus the pattern-alias stuff).<br>
</div><div><br>So the bottleneck in practice was in the code production part. It was just as true for the -ppx version (the traversal part was easy to write), but my experience producing code in the -ppx version was much less gratifying. Of course, it was my first use of your Ast_mapper.E interface, so there was some learning cost to take into account. But then I had type errors, I had to look at the documentation again, and it was a bit painful. Finally, I only handle Camlp4 extensions about once a year, so I have time to forget most details about how they work, in particular I *always* look at the documentation for the concrete AST constructor names in the (rare) cases where I need them. I found that there was no such re-learning curve with quasiquotations, they just work out of the box -- once you've been rebrained, once and forall, to see those <:stuff< >> as structured code rather than ASCII noise.<br>
<br></div><div>I think the small tool you just introduced (translating OCaml code into AST-building ocaml code) may have made this "code production" part easier, but I'm not fond of the idea of pasting auto-generated code in my own code. In any case, it would be better if it produced code using the nice high-level interface, rather than the hard-to-read AST definitions, but that may be much more painful to implement so I'm not really asking for that. <br>
</div><div><br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
But maybe we<br>
can have quasiquotations with the current extension mechanism?<br>
<br>
let add_register patvar body =<br>
[%quote<br>
let _ = ExceptionHandling.register [%anti patvar] in [%anti body]<br>
]<br>
</blockquote>
<br></div>
Implementing this "quote" expander is not very difficult, just a little bit tedious (and this can be automated by parsing the definition of the Parsetree).</blockquote><br></div><div>Isn't that essentially the same thing as the tool you implemented for Xavier above? (Can you reuse code between both?)<br>
If I understand correctly, this is also the "Meta" operation of Camlp4, turning the AST for the expression <foo> into the AST for the OCaml expression representing the AST for <foo>. When you say "automated by parsing the definition of the Parsetree", do you have a realistic design in mind for such boilerplate code generators, or do you plan in practice to implement them by hand?<br>
<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Note that nothing forces to use [%anti x] for antiquotations. We could very well decide on a more lightweight convention, like prefixing identifiers, or using a dedicated operator: </blockquote>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
[%quote<br>
let _ = ExceptionHandling.register __patvar in __body<br>
]<br>
<br>
[%quote<br>
let _ = ExceptionHandling.register !!patvar in !!body<br>
]<br></blockquote><div><br></div><div>Same old battle-horse: I dislike the idea that [%quote ] would change the meaning of syntactically valid OCaml code such as __patvar or !!patvar. I think I would with [%anti ] for now, or maybe just [%a ] if need be -- in any case this is not part of the eventually-crowded extension namespace as they really are only markers to be rewritten by the implementation of %quote.<br>
</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
But this approach would work nicely only for writing expressions or patterns on OCaml expressions, not on other syntactic categories (because the content of an extension node is an expression). The problem is that AST-manipulating code tend to require to work a lot with many different categories (like "match cases") even to build expressions.<br>
</blockquote><div><br></div><div>That's a good point.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Quasi-quotations would be useful if the expanders had to generate big fragments of mostly static code, with only a few "dynamic" placeholders. In my experience, this is rarely the case: you assemble the resulting OCaml code by combining many small fragments generated programmatically. For these cases, a nice library of "AST constructors" seems better to me.<span class="HOEnZb"><font color="#888888"><br>
</font></span></blockquote><div><br></div><div>Maybe we need both, but if we eventually get nice constructor names for the AST definitions (I know that doesn't depend on you) I think if we only had time/energy/maintenance for two among (1) AST definitions (2) AST combinator library and (3) quasiquotation mechanism, I would suggest we keep (1) and (3) rather than (1) and (2).<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="HOEnZb"><font color="#888888">
<br>
<br>
<br>
-- Alain<br>
</font></span></blockquote></div><br></div></div>