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] Unpack tuple in block arguments #2603

Closed
asterite opened this issue May 17, 2016 · 6 comments
Closed

[RFC] Unpack tuple in block arguments #2603

asterite opened this issue May 17, 2016 · 6 comments

Comments

@asterite
Copy link
Member

asterite commented May 17, 2016

Right now dealing with tuples yielded to a block is cumbersome:

a = [{1, "one"}, {2, "two"}]
a.each do |tuple|
  int, string = tuple
  # do something
end

In Ruby the unpacking is done automatically:

a = [[1, "one"], [2, "two"]]
a.each do |int, string|
  # do something
end

One can also use explicit unpacking, which seems to be similar:

a = [[1, "one"], [2, "two"]]
a.each do |(int, string)|
  # do something
end

I'm not sure in Crystal we'd like to have automatic unpacking, specially because each above could resolve to different methods, one that yields tuple and the other not, so it's not clear how would variables be bound. We also tend to prefer explicitness.

However, we can add explicit unpacking:

# This time this is Crystal
a = [{1, "one"}, {2, "two"}]
a.each do |(int, string)|
  # do something
end

This should be trivial to implement, the compiler would rewrite the above to this:

a = [{1, "one"}, {2, "two"}]
a.each do |temp|
  int, string = temp
  # do something
end

We could maybe use {...} instead of (...) as the syntax for unpacking, though I'm not sure. This will also be valid:

# Note that this is now an array of arrays
a = [[1, "one"], [2, "two"]]
a.each do |(int, string)|
  # here both int and string are of type Int32 | String
end

That's because you can currently unpack an array because it's just rewritten to temp[0], temp[1], etc., so maybe using parentheses is good because it means "unpacking", not "tuple".

I think this is a very small addition to the language, but it removes the need to declare temporary useless variables in some cases, and leads to more readable code.

Thoughts?

@jhass
Copy link
Member

jhass commented May 17, 2016

Big +1 and yeah, let's keep using parenthesis.

Related to #105 #132

@refi64
Copy link
Contributor

refi64 commented May 17, 2016

Oooh, this looks cool!

@spalladino
Copy link
Contributor

The only think I dislike about this is that 0.17 has just been released, and now I'll have to wait to 0.18 to get this.

@ozra
Copy link
Contributor

ozra commented May 17, 2016

+1 for explicit unpacking/destructuring!

@wrq
Copy link

wrq commented May 18, 2016

Definitely agree with ozra that explicit unpacking and destructuring would be rad.

I'd love to have this feature regardless, but I think it'd be great if we could choose whether or not it should happen.

I would think that the unpacking syntax should a bit noiser than just (...) to indicate that something is happening there, rather than just appearing to be a group of something.

Perhaps #(...) or #{...} or maybe |: :| to indicate that block parameters unpack.

a = [{name: 'hayden'},{cool: 'yeah'}]

a.each do |: sym, str :| # obviously indicative that something special is happening
  # do stuff
end

@asterite
Copy link
Member Author

I'll try to implement this for 0.17.1, together with some other bugfixes and improvements.

@wrq I think parens are just fine, there's nothing dangerous when unpacking tuples/arrays, and in any cae you either get a compile or runtime error for index out of bounds. It's also syntax known to Ruby users.

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

6 participants