Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser: allow anonymous block args #8117

Merged
merged 1 commit into from
Sep 5, 2019

Conversation

asterite
Copy link
Member

@asterite asterite commented Aug 25, 2019

Related to #7157

In addition to being able to write this:

def foo(x, y, &block)
end

Now you can write it like this:

def foo(x, y, &)
end

That is, you can omit the block name.

Of course it also works with a type signature:

def foo(x, y, & : Int32 -> Int32)
end

It might look more obscure but there's a reason we might go this way.

Why?

Right now the compiler infers a few things based on the signature and method definition:

  • If a method has yield inside it the compiler knows it receives a block
  • If a method mentions the block argument then the compiler considers the block is captured and it will form a closure over it when invoked

This is nice but it has a few disadvantages:

  • because you can just use yield and omit the block argument it's not immediately clear from the method signature whether a method accepts a block or not
  • you must use &block if you want to say you receive a block, even if you don't plan to yield (Nil#try does this) so it's a bit asymmetric that sometimes you need to write it and sometimes not
  • if yield is generated through a macro then you are again forced to specify the block argument
  • if the block argument is mentioned inside a macro then the compiler doesn't know it actually forms a closure (Block argument isn't seen inside macro code #2992) and one has to mention the block argument somewhere outside the macro code as an ugly workaround

So the idea would be:

  • Just & means a non-captured block argument: because it doesn't have a name there's no way to capture it
  • &block means a captured block argument, and the compiler will verify that it's used in the semantic phase (because it might be mentioned inside a macro)
  • &block without a mention will give a compile error suggesting to either change it to & to avoid a closure or to mention it somehow
  • if you yield and the method signature doesn't have & the compiler will tell you

Now, this PR is just the beginning direction: there's no breaking change here, just the possibility to omit the block argument name.

@asterite asterite merged commit b9c989e into crystal-lang:master Sep 5, 2019
@asterite asterite deleted the anonoymous-block-arg branch September 5, 2019 16:07
@asterite asterite added this to the 0.31.0 milestone Sep 5, 2019
dnamsons pushed a commit to dnamsons/crystal that referenced this pull request Jan 10, 2020
kimburgess added a commit to place-labs/responsible that referenced this pull request Oct 15, 2020
kimburgess added a commit to place-labs/responsible that referenced this pull request Oct 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants