{"action":"closed","issue":{"url":"https://api.github.com/repos/CausalityLtd/ponyc/issues/291","labels_url":"https://api.github.com/repos/CausalityLtd/ponyc/issues/291/labels{/name}","comments_url":"https://api.github.com/repos/CausalityLtd/ponyc/issues/291/comments","events_url":"https://api.github.com/repos/CausalityLtd/ponyc/issues/291/events","html_url":"https://github.com/CausalityLtd/ponyc/issues/291","id":103636976,"number":291,"title":"No way to have an error-free block that depends on a `try`.","user":{"login":"jemc","id":4623870,"avatar_url":"https://avatars.githubusercontent.com/u/4623870?v=3","gravatar_id":"","url":"https://api.github.com/users/jemc","html_url":"https://github.com/jemc","followers_url":"https://api.github.com/users/jemc/followers","following_url":"https://api.github.com/users/jemc/following{/other_user}","gists_url":"https://api.github.com/users/jemc/gists{/gist_id}","starred_url":"https://api.github.com/users/jemc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jemc/subscriptions","organizations_url":"https://api.github.com/users/jemc/orgs","repos_url":"https://api.github.com/users/jemc/repos","events_url":"https://api.github.com/users/jemc/events{/privacy}","received_events_url":"https://api.github.com/users/jemc/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/CausalityLtd/ponyc/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":7,"created_at":"2015-08-28T02:53:10Z","updated_at":"2015-09-03T15:44:02Z","closed_at":"2015-09-03T15:44:02Z","body":"Here is one common pattern for using `try` blocks:\r\n\r\n```pony\r\ntry\r\n  let res = fetch_result_or_error()\r\n  do_something_with_result(res)\r\n  do_something_else_with_result(res)\r\nelse\r\n  could_not_fetch_res()\r\nend\r\n```\r\n\r\nAnother variation on this pattern uses `as`:\r\n\r\n```pony\r\ntry\r\n  let res = foo as Result\r\n  do_something_with_result(res)\r\n  do_something_else_with_result(res)\r\nelse\r\n  could_not_fetch_res()\r\nend\r\n```\r\n\r\nThe point is that the `try` block is often composed of an initial \"risky\" operation (one that could `error`), followed by other \"safe\" operations that depend on the successful completion of the \"risky\" operation.  \r\n\r\nThanks to Pony's awareness of partial function bodies and partial function signatures, the developer is forced to make sure that all \"risky\" operations are inside a `try` block (or a partial function body).  This is great for refactoring, because you can be sure you are at least aware of all `error`s as you work - except in cases like the one above (and I think this pattern is actually quite common).\r\n\r\nThe problem is that if one of the \"safe\" operations within a `try` block suddenly becomes \"risky\" (one of the calls becomes a partial function through refactoring), the compiler doesn't complain because it's already in a `try` block, even though it was in the conceptually \"safe\" part of the `try` block that the developer was using because the operations depended on the \"risky\" part.  And in this situation, in many cases the new behavior will lead to a subtle bug in which the initial \"risky\" operation completes, but only part of the assumed \"safe\" operations will be executed (in addition to the `else` block, if any).\r\n\r\nIn the examples above, if the `do_something_with_result` function suddenly became partial, it creates a code path where the execution goes:\r\n```pony\r\nlet res = fetch_result_or_error()\r\ndo_something_with_result(res) // error!\r\ncould_not_fetch_res()\r\n```\r\n\r\nTo guard against such a case, as a developer it would be nice to have a mechanism for marking a block that depends on the `try` block, but is considered fully safe - no errors are possible there, or it causes a compile error.\r\n\r\nI know `then` already has a different meaning for `try` blocks, but I think it actually makes a lot more sense here than its current use (and issue ticket #290 mentions possibly changing the name of the `try`-always block to something like `always` or `finally`).  Actually, I think the current use of `then` with `try` is not that useful, and not that related to `error`s - it only helps in cases like executing a cleanup block before `return` or `break`, so it actually has more to do with loops and function bodies than `error`s and `try`s.  Anyway, here's how I envision `try`-`then` being used in the example above:\r\n\r\n```pony\r\ntry let res = fetch_result_or_error() then\r\n  do_something_with_result(res)\r\n  do_something_else_with_result(res)\r\nelse\r\n  could_not_fetch_res()\r\nend\r\n```\r\n\r\nAs you can see, this is very close to how `if`-`then` works, just with `error` branching instead of boolean branching.\r\n\r\nIf another keyword is found to be better suited to this, that's fine, but I think something like this feature is needed to avoid these subtle bugs.  Currently the only way I can think of to mark such a \"safe\" zone would be to create a (non-partial) function and call that from within the `try` block, although that can be rather annoying for otherwise succinct operations.\r\n"}}