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

[RFC] Block arguments autosplatting #105

Closed
kostya opened this issue Mar 12, 2014 · 5 comments
Closed

[RFC] Block arguments autosplatting #105

kostya opened this issue Mar 12, 2014 · 5 comments

Comments

@kostya
Copy link
Contributor

kostya commented Mar 12, 2014

./bin/crystal -e '[{1,2}].each{ |a, b| p({a, b}) }'
{{1, 2}, nil}

expected {1, 2}

@asterite
Copy link
Member

You are correct, it should behave that way. But since tuples are so recent it's a feature we didn't implement yet.

However, if you yield arrays they won't be automatically unpacked.

@PragTob
Copy link
Contributor

PragTob commented Aug 16, 2015

Walking across the paths of wanting to make Hash an Enumerable (like #798 as I just noticed) I just bumped into this. I would LOVE to have this feature nor only for the Hash reason but others as well :)

In trying it out I also wrote a couple of specs:

require "spec"

describe "destructuring" do
  it "destructures arrays" do
    a, b = [1, 2]
    a.should eq 1
    b.should eq 2
  end

  it "destructures tuples" do
    a, b = {1, 2}
    a.should eq 1
    b.should eq 2
  end

  pending "it does not work" do
    it "destructures arrays in blocks" do
      [[1, 2]].each do |a, b|
        a.should eq 1
        b.should eq 2
      end
    end

    it "destructures tuples in blocks" do
      [{1, 2}].each do |a, b|
        a.should eq 1
        b.should eq 2
      end
    end
  end

end

@asterite
Copy link
Member

I'm not sure I like Ruby's magic here, the thing that it automatically destructures arrays. I usually like explicit more than implicit.

What we can do is to make this:

foo do |(x, y)|
  body
end

be rewritten by the parser to this:

foo do |temp|
  x, y = temp
  body
end

In this way you can do:

[[1, 2], [3, 4]].each do |(x, y)|
  puts x, y
end

At least the lack of this feature bothers me because I have to assign the block argument to a temporary value and then extract its values in a separate line. This change is very simple to implement (just a parser rewrite) and makes it clear that we are unpacking the values. As a bonus, it works with Array, Tuple or any other class that supports #[], unlike Ruby which only supports arrays.

Of course the general case can also be easily supported, like method do |x, (y, z), (a, b, c)|... probably no nested destructuring for now.

What do you think?

@PragTob
Copy link
Contributor

PragTob commented Aug 16, 2015

I like it 👍

if you make the commit can you please reference it here (I know you usually do). I just spent the last couple of hours digging through the compiler code to figure out where I can do something like this (well without the ( )) all the way down to codegen and also up in type_inference and couldn't figure the correct place out.

Just doing it in the parser is a lot simpler of course (from what I can grasp - my knowledge of parsers/compilers is based on a couple of conference talks) - would like to see how it plays out. :)

edit: of course I could only do that because crystal is implemented in crystal - that's so awesome - was a lot of fun digging through it :) Thanks!

@jhass
Copy link
Member

jhass commented May 18, 2016

In #2603 we decided to have explicit unpacking only.

@jhass jhass closed this as completed May 18, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants