{"action":"created","issue":{"url":"https://api.github.com/repos/ocaml/ocaml/issues/278","labels_url":"https://api.github.com/repos/ocaml/ocaml/issues/278/labels{/name}","comments_url":"https://api.github.com/repos/ocaml/ocaml/issues/278/comments","events_url":"https://api.github.com/repos/ocaml/ocaml/issues/278/events","html_url":"https://github.com/ocaml/ocaml/pull/278","id":114832132,"number":278,"title":"Add an imperative if construction","user":{"login":"trefis","id":118852,"avatar_url":"https://avatars.githubusercontent.com/u/118852?v=3","gravatar_id":"","url":"https://api.github.com/users/trefis","html_url":"https://github.com/trefis","followers_url":"https://api.github.com/users/trefis/followers","following_url":"https://api.github.com/users/trefis/following{/other_user}","gists_url":"https://api.github.com/users/trefis/gists{/gist_id}","starred_url":"https://api.github.com/users/trefis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trefis/subscriptions","organizations_url":"https://api.github.com/users/trefis/orgs","repos_url":"https://api.github.com/users/trefis/repos","events_url":"https://api.github.com/users/trefis/events{/privacy}","received_events_url":"https://api.github.com/users/trefis/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":79,"created_at":"2015-11-03T14:45:28Z","updated_at":"2015-11-05T14:09:39Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/ocaml/ocaml/pulls/278","html_url":"https://github.com/ocaml/ocaml/pull/278","diff_url":"https://github.com/ocaml/ocaml/pull/278.diff","patch_url":"https://github.com/ocaml/ocaml/pull/278.patch"},"body":"A classic source of bugs in ocaml programs is related to the precedence of if statements relative the the precedence of semicolons.\r\nBy that I mean that:\r\n\r\n```ocaml\r\nif E then\r\n  E;\r\n  E\r\n```\r\nis parsed as `(if E then E); E` and not as `if E then (E; E)` in spite of what the indentation seem to imply.\r\n\r\nIt is an error we too often encounter at Jane Street, consider for example the situation where one refactors\r\n\r\n```ocaml\r\nif condition then\r\n  begin match x with\r\n  | stuff -> blah (); Deferred.unit\r\n  end\r\n  >>= fun () ->\r\n  other_stuff ();\r\n  foo ()\r\n```\r\n\r\ninto\r\n\r\n```ocaml\r\nif condition then\r\n  begin match x with\r\n  | stuff -> blah ()\r\n  end;\r\n  other_stuff ();\r\n  foo ()\r\n```\r\n\r\nThis kind of error happens often enough (among newcomers to the language, as well as veterans -- see https://github.com/mshinwell/ocaml/commit/843ea4d23794e23425c56af412b4239f168fbcf9#diff-f51c83f68b1c1139bb40787fec5d5ec2L425 ) that we would like compiler support to avoid them.\r\n\r\nProposition\r\n-----------\r\n\r\nThe problem arising when using the open-ended if construction in presence of semicolons, we propose introducing a \"terminated\" version of `if`.\r\n\r\nSingle branch if statements would look like this :\r\n```ocaml\r\nif CONDITION do EXPRESSION done\r\n```\r\nand the ones with several alternatives look like this\r\n```ocaml\r\nif CONDITION do\r\n  EXPRESSION\r\ndone else if CONDITION do\r\n  EXPRESION\r\ndone else do\r\n  EXPRESSION\r\ndone\r\n```\r\n\r\nIn addition to this construction a warning (off by default) is added which triggers when the \"traditional\" open-ended `if .. then .. else ..` construction is present in an *imperative context*, by which we mean: on the left hand side of a semicolon or inside a `do .. done` block.\r\n\r\nThe choice of `do .. done` as delimiters for this new if construction comes from the similarity of this form with the other constructions of the language traditionally associated with imperative programming (`for` and `while` loops).\r\nIndeed as is the case with loops, this construction insists that the content of the branches be of type unit.\r\n\r\nImplementation summary\r\n----------------------\r\n\r\n- a new `Pexp_ifdo` construction is added to the parsetree.\r\n- the grammar is updated to recognize the new `if .. do .. done` form\r\n- a new warning (57) is introduced, it is disabled by default\r\n- the stdlib is updated to use this new construction wherever the warning was raised\r\n\r\nI am not particularly attached to the current name and message of the new warning; any proposition to improve it is welcomed.\r\n"},"comment":{"url":"https://api.github.com/repos/ocaml/ocaml/issues/comments/154067639","html_url":"https://github.com/ocaml/ocaml/pull/278#issuecomment-154067639","issue_url":"https://api.github.com/repos/ocaml/ocaml/issues/278","id":154067639,"user":{"login":"alainfrisch","id":3305274,"avatar_url":"https://avatars.githubusercontent.com/u/3305274?v=3","gravatar_id":"","url":"https://api.github.com/users/alainfrisch","html_url":"https://github.com/alainfrisch","followers_url":"https://api.github.com/users/alainfrisch/followers","following_url":"https://api.github.com/users/alainfrisch/following{/other_user}","gists_url":"https://api.github.com/users/alainfrisch/gists{/gist_id}","starred_url":"https://api.github.com/users/alainfrisch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alainfrisch/subscriptions","organizations_url":"https://api.github.com/users/alainfrisch/orgs","repos_url":"https://api.github.com/users/alainfrisch/repos","events_url":"https://api.github.com/users/alainfrisch/events{/privacy}","received_events_url":"https://api.github.com/users/alainfrisch/received_events","type":"User","site_admin":false},"created_at":"2015-11-05T14:09:39Z","updated_at":"2015-11-05T14:09:39Z","body":"> match E with begin | ... with end\r\n\r\nHow is this better than:\r\n\r\n begin match E with\r\n | ...\r\n end\r\n\r\nwhich is already supported?"}}