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

Feature request: typed splats #291

Closed
sferik opened this issue Dec 3, 2014 · 10 comments
Closed

Feature request: typed splats #291

sferik opened this issue Dec 3, 2014 · 10 comments

Comments

@sferik
Copy link
Contributor

sferik commented Dec 3, 2014

I would like to be able to define the following methods:

# Fetch multiple users by their IDs
def find_users(*ids : Int32)
end

# Fetch multiple users by their usernames
def find_users(*usernames : String)
end

such that:

find_users(1, 2, 3) # dispatches to the first version of the method
find_users("erik") # dispatches to the second version of the method
find_users(1, "erik") # error: no overload matches 'find_users' with types Int32, String

Essentially, I want the ability to define a method with an arbitrary number of parameters of a specific type. Of course, this is possible with an array but it should be possible to invoke the method without square braces (e.g. find_users([1, 2, 3])).

Basically, I’d like a splat of type T to be syntactic sugar for Array(T) when it appears as a parameter in a method definition? Do you think that would be possible?

@asterite
Copy link
Member

asterite commented Dec 4, 2014

After some thought, I think that if you are able to do:

def find_user(id : Int32)
end

def find_user(username : String)
end

Then it makes sense to want to extend this concept to "one or many". Using Arrays you can do it but you have to write the array literal, and it allocates unnecessary memory if you know which ids/usernames to fetch.

I also like the syntax you propose: since it's a splat the type must be a tuple, and this will check all of that tuple's type.

I'll try to implement it, I don't think it's too hard. Just note that this will work:

find_user(1, 2, 3) # ok
find_user("foo", "bar", "baz") # ok

ids = {1, 2, 3}
find_user *ids

usernames = {"foo", "bar", "baz"}
find_user *usernames

But this won't work for now until we implement multi-dispatch over tuple types:

values = some_condition ? {1, 2, 3} : {"foo", "bar", "baz"}
find_user *values # error for now...

@asterite
Copy link
Member

asterite commented Dec 4, 2014

On second thought, after discussing this with @waj, we decided we won't implement it.

This looks nice in example code, but in practice you will get an array of ids or usernames from somewhere and pass it to the API. You won't hardcode ids/usernames in real code, only in specs and samples, so passing an array in those cases is not that terrible.

@sferik
Copy link
Contributor Author

sferik commented Dec 4, 2014

Okay, just a suggestion for some syntax sugar. No big deal to me.

@asterite
Copy link
Member

I'm reopening because we'll probably finally implement this

@asterite asterite reopened this Apr 21, 2015
@sferik
Copy link
Contributor Author

sferik commented Apr 21, 2015

\o/

@vendethiel
Copy link
Contributor

👍 sounds really good :-).

@asterite
Copy link
Member

Oh, with this I (initially) mean that you'll be able to put a type restriction, not to have overloaded splats. We have to think a bit more about the overload case, specially because of the empty-tuple case.

@asterite
Copy link
Member

On second thought, I think we can also implement typed splats. In fact I have this in a stash :-)

The idea would be that typed splats don't match empty tuples. For the empty-tuple case use another overload. So:

# Fetch multiple users by their IDs. Requires at least one ID.
def find_users(*ids : Int32)
end

# Fetch multiple users by their usernames. Requires as least one username.
def find_users(*usernames : String)
end

# Maybe return all of them? (just for demo)
def find_users
end

find_users(1, 2, 3)       # matches first
find_users("a", "b", "c") # matches second
first_users               # matches third

Of course, without the third overload the last call would give a compile-time error.

Multi-dispatch over tuple types is still a different issue, so implementing this won't magically make #223 work (but in the future it might).

Thoughts?

@sferik
Copy link
Contributor Author

sferik commented Apr 30, 2015

\o/

@vendethiel
Copy link
Contributor

Great :).

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

3 participants