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] Customization point for array-like splat expansions #10427

Open
HertzDevil opened this issue Feb 20, 2021 · 0 comments
Open

[RFC] Customization point for array-like splat expansions #10427

HertzDevil opened this issue Feb 20, 2021 · 0 comments

Comments

@HertzDevil
Copy link
Contributor

This issue is extracted from #3718 (comment).

Currently, splat destructuring in multiple assignment works if and only if a type implements #[](Int). This has unintended consequences:

a, b, c = "12345"                        # okay?
a, b, c = {0 => 'x', 1 => 'y', 2 => 'z'} # okay??
a, b, c, d, e = Pointer(UInt8).malloc(1) # ?????

There should be a #to_array_splat method that is called on the RHS expression whenever 1-to-n multiple assignment occurs, and also whenever a splat expression is expanded inside a container literal in #3718. (This is analogous to #to_ary in Ruby, although Ruby uses #to_a instead for the latter case.) Then we could reject code like above by simply not defining the method in Hash and String and so on, while at the same time supporting splat expansion of custom data types:

record Point, x : Int32, y : Int32 do
  def to_array_splat
    {@x, @y}
  end
end

x, y = Point.new(x: 1, y: 2)

# the above is equivalent to:
__temp = Point.new(x: 1, y: 2).to_array_splat
x = __temp[0]
y = __temp[1]

Standard library that could define #to_array_splat are Indexable, Regex::MatchData, and Class (to support expansion of Tuple metaclasses).

This doesn't change the semantics of other splat expansions where an exact Tuple type is expected; the naming makes it clear that the splat only works for array-like contexts (otherwise it might have been to_tuple_splat or to_single_splat). For example:

def foo(x, y)
end

foo(*Point.new(x: 1, y: 2)) # not allowed

def bar
  yield *Point.new(x: 1, y: 2) # not allowed
end

Likewise, there could be a #to_hash_splat customization point for hash-like double splats, which the language currently doesn't support yet, but might due to #3718 (comment). (Similar to the array case, calling a method with ** requires an exact NamedTuple type so doesn't count.)

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

2 participants