Ppx: add support for begin%lwt e1; e2; end in ppx extension#525
Ppx: add support for begin%lwt e1; e2; end in ppx extension#525kandu wants to merge 7 commits intoocsigen:masterfrom
Conversation
|
Don't mind the AppVeyor failure, that is because I tried this branch locally, but it doesn't seem to generate correct code: let () =
let p : unit Lwt.t =
begin%lwt
Lwt_unix.sleep 1.;
Lwt.return ()
end
in
Lwt_main.run pThis doesn't wait for one second. However, deleting the Is this similar to #307, "Support ;%lwt as sequence syntax -- backwards incompatible in some cases?" I am assuming that |
|
I rechecked the code and some tests(including your 'sleep 1 sec' code). It works properly. let pl= Lwt_io.printl
let pi= Lwt_io.printf "%d\n"
let pe= print_endline
let t=
begin%lwt
pl "1";
pi 1;
begin
begin%lwt
pl "2";
pi 2;
end |> ignore;
pe "s1";
pl "s2";
end;
pl "3";
endexpands to let pl = Lwt_io.printl
let pi = Lwt_io.printf "%d\n"
let pe = print_endline
let t =
Lwt.bind (pl "1")
(fun () ->
Lwt.bind (pi 1)
(fun () ->
Lwt.bind
((Lwt.bind (pl "2") (fun () -> pi 2)) |> ignore;
pe "s1";
pl "s2") (fun () -> pl "3")))and for let () =
let p : unit Lwt.t =
begin%lwt
Lwt_unix.sleep 1.;
end
in
Lwt_main.run pexpands to let () =
(* the new mapper doesn't expand non-sequence expr and the old style [%lwt ...] wrap works *)
let p : unit Lwt.t = Lwt.catch (fun () -> Lwt_unix.sleep 1.) Lwt.fail in
Lwt_main.run pit's mostly the same as #307 except that it expands all immediately nested sequences at once. begin%lwt
e1;
e2;
e3;
e4;
endand for compatibility. Maybe the scheme that for all unmatched Pexp_, we just wrap it with a Lwt.catch is not a good idea since it brakes furthuer extension or new introduced syntax. For such compatibility, we may break it as soon as possible(in a major version) to prevent the costs from increasing in the future. #307 and this pr are dealing with the same problem, as you mentioned, talk could continues in that thread. |
|
You're right, it works. I must have forgotten This PR is nice, but a thing that bothers me a little is that with this PR, e1;%lwt
e2;
e3;propagates the effect of It also defeats this advantage of #307:
I'm not sure how important that is, @hcarty? I just did a revdeps search in opam. Interestingly, I found I'd say the effects on users from changing this will be pretty small, but let's discuss a bit. |
|
Hm, I wonder if it's possible to reliably check for |
distinguish the help msg from cmd args by inserting a space before.
…e expansion
{| begin%lwt e1; e2; ... end |} expands all immediately nested sequences while {| e1;lwt e2 |} only takes effect between e1 and e2
…wt.ppx works in compatible mode. i.e. Lwt.catch all [%lwt ...] expressions
|
To write code that combines regular sequence and lwt sequence, As you suggested, When After the trigger, |
|
But I still think that mixing non-lwt and lwt sequence with ;%lwt is not a good idea. We don't take too much advantage of it. ;%lwt looks messy and is likely to cause messy buggy code when refactoring code. let t=
unit;
unit;%lwt
unit;
unit;%lwt
unit;
'a lwtcompiles, let t=
unit;%lwt
unit;
unit;
unit;%lwt
unit;
'a lwtstill compiles with no warning。 In fact, ;%lwt allow you to write whatever you want in any sequence since it has no clean boundary, (in other words, it automatically make a boundary between former and later statements, which hides logical error silently) I doubt if It is worth introducing the ;%lwt syntax. |
|
shall we add -semicolon-sequence to cmd args? by default is turned off. |
aantron
left a comment
There was a problem hiding this comment.
It looks pretty good. I'd like to wait for @hcarty's opinion as well, as he had submitted #307. Concerning compatibility, given that 3.2.0 was just released, we can probably sneak in an extra announcement that we are going to disable [%lwt ...] (#527). We can then adjust the PPX so that if anything other than sequence, let, etc., is found under [%lwt ...], it will be an error. This should be enough to catch all mistaken uses of it, and force them to be changed.
We can then unconditionally enable begin%lwt ... ; ... end and ;%lwt.
I'm not sure what you mean by that sequence code compiling without warnings – I wouldn't expect it to compile at all. Doesn't all the stuff before ;%lwt have to be of type unit Lwt.t, not just unit? Maybe I am not reading the pseudocode correctly.
| "-log", Set log, " enable logging"; | ||
| "-no-log", Clear log, " disable logging"; | ||
| "-no-sequence", Clear sequence, " disable sequence operator"; | ||
| "-no-strict-sequence", Clear strict_seq, " allow non-unit sequence operations"; |
There was a problem hiding this comment.
Thanks for doing this. I just tried looking at the PPX output, ouch.
|
ah yes, the pseudocode needs some tweaking let t=
unit;
unit Lwt.t;%lwt
unit;
unit Lwt.t;%lwt
unit;
'a Lwt.te.g. open Lwt
let t=
ignore ();
return ();%lwt
ignore ();
return ();%lwt
ignore ();
return "bug"
let main ()=
t >>=
Lwt_io.printl
let ()= Lwt_main.run @@ main () |
Errk, I'm sorry, this is a deal breaker, as far as semantics goes. It's just completely non-sensical. If that's the case, You are better off removing I'll get a look at things in more details later, but that particular semantics is just plain wrong. |
|
@Drup, @kandu fixed that behavior in a subsequent commit. In its current form, the PR detects whether the |
|
@aantron errors may occur in the logical flow, to be specific, critical section. The sequence nested in It's more convenient using semicolon-sequence was enabled by default, given the above, commit Ppx: -semicolon-sequence to trigger ;%lwt expansion was submitted in order that lwt users can choose their coding style themselves. And by defaut, the As for |
Not sure what you mean here, but with
I'm not sure about this, the only parts of the code that aren't executed atomically are exactly at the places where On that subject, we should probably make And, I think Lwt users can choose the coding style by simply choosing to use |
|
Also, cc @paurkedal due to work on ocaml/ocaml#1474. |
I know what you mean here. lwt sequence is interruptable semantically. And what I was concerning about is regular sequence, which is seen as semantically atomic in a lwt thread. coding style 1 open Lwt
let t=
begin%lwt
do_lwt 1;
do_lwt 2;
begin
do_atomic 1;
do_atomic 2;
return ();
end;
do_lwt 3;
do_lwt 4;
endcoding style 2 open Lwt
let t=
do_lwt 1;%lwt
do_lwt 2;%lwt
do_atomic 1;
do_atomic 2;
do_lwt 3;%lwt
do_lwt 4;They are logically equivalent. In the former style, lwt sequence is forbidden in the In the later style, users are allowed to insert, e.g. thread 1 In vim or spacemacs editor, we just type the keybord three times, humans make mistakes. I suggest keeping the ppx option there. Or we can give users some tips about it in the doc. |
|
Yes, I think we agree that inserting But I don't see why we should add |
|
Also the point about no warnings is a bit odd. It is visible to the user that the user is adding |
|
One thing about the begin%lwt
let foo = bar in
blah;
blah;
endThis seems undesirable. I think this kind of change is pretty common. I make it often. In fact, this makes me think that we should take the location check in this PR, that distinguishes between I'm not fully sure about this, discussion welcome. @Drup, what do you think? |
|
A slightly curious thing is that with the location check in this PR, |
This commit still doesn't detect [%lwt let ...], etc. That is currently being discussed in #525.
|
I think there is merits to the arguments for begin%lwt.serial
let a = ... in
let%lwt b = ... in
blah;
blah;
endOne might analogously have a I think the main weakness of using |
|
Introducing more extension point IDs, the let t =
[%lwt.serial
do_lwt 1;
do_lwt 2;
[%lwt.atomic
do_atomic 1;
do_atomic 2;
return ()
];
do_lwt 3;
do_lwt 4
] |
I agree. Commit 74f2aae is reverted
It's an endogenous issue from the implementation of the OCaml compiler, that |
|
Honestly, I think using locations to distinguish how ppx nodes are placed is a horribly broken idea. It's very brittle to code transformation tools, other ppxs, or simply other syntaxes like reason. It's basically begging to be broken. The fact that In essence, this pr/discussion is about introducing a do notation specialized for lwt. Adding a new ppx keyword for this seems perfectly acceptable to me, and it's going to be a lot more robust than whatever you can cook by playing with locations. There are multiple ppx do notations around that we can take inspiration from, or we could just bless one in particular. |
|
At this point, I agree with @Drup
and @paurkedal
This PR is going to be closed if no objection. The location info may help in other ways:
After looking into the parsetree, I think It could be done by simply comparing the location of and pos_exp= exp.pexp_loc.Location.loc_start.Lexing.pos_cnum after eba5ec0#diff-caac464b5d25fba7598ee925a51b5c01R239 and because let lwt_expression mapper exp attributes (trigger_loc:Location.t)=we can distinguish |
We should probably take a survey of them. So the proposal is:
@kandu I think we want to move away from comparing locations completely :) |
|
I'm just starting to look at this after being away from a computer for a while. I think If we do keep [%lwt
Lwt_io.printl "Hello";
Lwt_io.printl "world"
]Lwt_io.printl "Hello";%lwt
Lwt_io.printl "world"These would be equivalent as well: [%lwt
Lwt_io.printl "Here we go";
match i'm_a_promise with
| Some x -> Lwt.return x
| None -> Lwt.fail Exit
]Lwt_io.printl "Here we go";%lwt
match%lwt i'm_a_promise with
| Some x -> Lwt.return x
| None -> Lwt.fail ExitI don't know if that's a good change to make. The explicit |
|
@aantron I agree with the proposal. :) Let's just drop " |
@hcarty Without location-hacks, that would mean that the |
|
@paurkedal Ah, of course - thank you for pointing that out. Then I take back that suggestion as it is even worse than I originally though. |
An alternative for the old >> sequence operator.