{"action":"created","issue":{"url":"https://api.github.com/repos/manastech/crystal/issues/420","labels_url":"https://api.github.com/repos/manastech/crystal/issues/420/labels{/name}","comments_url":"https://api.github.com/repos/manastech/crystal/issues/420/comments","events_url":"https://api.github.com/repos/manastech/crystal/issues/420/events","html_url":"https://github.com/manastech/crystal/issues/420","id":57841373,"number":420,"title":"[RFC] break, next and return and blocks","user":{"login":"jhass","id":141294,"avatar_url":"https://avatars.githubusercontent.com/u/141294?v=3","gravatar_id":"","url":"https://api.github.com/users/jhass","html_url":"https://github.com/jhass","followers_url":"https://api.github.com/users/jhass/followers","following_url":"https://api.github.com/users/jhass/following{/other_user}","gists_url":"https://api.github.com/users/jhass/gists{/gist_id}","starred_url":"https://api.github.com/users/jhass/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jhass/subscriptions","organizations_url":"https://api.github.com/users/jhass/orgs","repos_url":"https://api.github.com/users/jhass/repos","events_url":"https://api.github.com/users/jhass/events{/privacy}","received_events_url":"https://api.github.com/users/jhass/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/manastech/crystal/labels/proposal","name":"proposal","color":"009800"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-02-16T19:15:24Z","updated_at":"2015-02-19T15:10:48Z","closed_at":null,"body":"Currently the rules for those keywords are dramatically different depending on whether the block is captured or not.\r\n\r\n#### With a not captured block\r\n\r\n* `break` exits from the calling method, the argument provides the methods return value\r\n* `next` exits from the block, the argument provides the blocks return value\r\n* `return` exits from the method the block is defined in\r\n\r\n#### With a captured block\r\n\r\n* `break` is disallowed\r\n* `next` is disallowed\r\n* `return` exits from the block, the argument provides the blocks return value\r\n\r\n### Proposal\r\n\r\nI think it would be more consistent to swap the meanings for `next` and `return` in the captured block case. This way, if the library decides to not capture the block or vice versa, less code on the caller side is affected. More importantly the caller doesn't need to think about whether the block is captured or not in order to understand what the `return` inside a block is doing."},"comment":{"url":"https://api.github.com/repos/manastech/crystal/issues/comments/75067609","html_url":"https://github.com/manastech/crystal/issues/420#issuecomment-75067609","issue_url":"https://api.github.com/repos/manastech/crystal/issues/420","id":75067609,"user":{"login":"jhass","id":141294,"avatar_url":"https://avatars.githubusercontent.com/u/141294?v=3","gravatar_id":"","url":"https://api.github.com/users/jhass","html_url":"https://github.com/jhass","followers_url":"https://api.github.com/users/jhass/followers","following_url":"https://api.github.com/users/jhass/following{/other_user}","gists_url":"https://api.github.com/users/jhass/gists{/gist_id}","starred_url":"https://api.github.com/users/jhass/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jhass/subscriptions","organizations_url":"https://api.github.com/users/jhass/orgs","repos_url":"https://api.github.com/users/jhass/repos","events_url":"https://api.github.com/users/jhass/events{/privacy}","received_events_url":"https://api.github.com/users/jhass/received_events","type":"User","site_admin":false},"created_at":"2015-02-19T15:10:48Z","updated_at":"2015-02-19T15:10:48Z","body":"Mmh, tricky. Ruby differentiates whether it's Proc.lambda? apparently.\r\n\r\n```ruby\r\n# In Ruby\r\nproc { break :a; :b }.call # LocalJumpError\r\nproc { return :a; :b }.call # LocalJumpError\r\nproc { next :a; :b }.call # :a\r\ndef foo; proc {  break :a; :b }.call; :c; end; foo # LocalJumpError\r\ndef foo; proc {  return :a; :b }.call; :c; end; foo # :a\r\ndef foo; proc {  next :a; :b }.call; :c; end; foo # :c\r\ndef foo(a) a.call; :c; end; foo proc { break :a; :b } # LocalJumpError\r\ndef foo(a) a.call; :c; end; foo proc { return :a; :b } # LocalJumpError\r\ndef foo(a) a.call; :c; end; foo proc { next :a; :b } # :c\r\n\r\n-> { break :a; :b }.call # :a\r\n-> { return :a; :b }.call # :a\r\n-> { next :a; :b }.call # :a\r\ndef foo; -> {  break :a; :b }.call; :c; end; foo # :c\r\ndef foo; -> {  return :a; :b }.call; :c; end; foo # :c\r\ndef foo; -> {  next :a; :b }.call; :c; end; foo # :c\r\ndef foo(a) a.call; :c; end; foo -> { break :a; :b } # :c\r\ndef foo(a) a.call; :c; end; foo -> { return :a; :b } # :c\r\ndef foo(a) a.call; :c; end; foo -> { next :a; :b } # :c\r\n```\r\n\r\nSo the lambda is very close to an anonymous function but retains the block semantics of `break` and `next` too. Since in Crystal the literal is even closer to an anonymous function, I think it would be fair to disallow `next` and `break` and only allow `return` to exits the function itself.\r\n\r\nHowever that means Crystal would need to differentiate the `-> { }` literal and a captured block `def foo(&block)`, which I'm not sure it does atm. This also raises the question on what to do in the `foo(&-> { })` case, I'd argue retain the `-> { }` semantics since that's what the caller sees and knows.\r\n\r\nSo I'm not 100% sure, what do you think?"}}