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

splatting in tuple construction #4869

Closed
stevengj opened this issue Nov 20, 2013 · 27 comments
Closed

splatting in tuple construction #4869

stevengj opened this issue Nov 20, 2013 · 27 comments
Assignees
Labels
kind:breaking This change will break code

Comments

@stevengj
Copy link
Member

I was surprised to discover that this doesn't work:

(3,4,(5,6)...)

I was expecting (3,4,5,6), but got type: apply_type: in Vararg, expected Type{T<:Top}, got (Int64,Int64)

Even more surprising,

(3,4,()...)

works, but outputs (3,4,()...) instead of (3,4), with (3,4,()...)[3] being a somewhat mysterious ()... object of type DataType.

I understand that some special magic has to occur here in order to be able to define tuple types like (Int, Bool, Float64...), but the behavior above seems odd.

@timholy
Copy link
Sponsor Member

timholy commented Nov 20, 2013

Interesting timing; what's probably the same issue came up just today in JuliaIO/HDF5.jl#55. Similarly to your last example:

julia> immutable Dim{N}; end

julia> (Dim{3}, Dim{4}, (Dim{5}, Dim{6})...)
(Dim{3},Dim{4},(Dim{5},Dim{6})...)

@JeffBezanson
Copy link
Sponsor Member

This is a very, very old "feature" which makes ... inside a tuple syntax for a vararg tuple type. One has to call tuple explicitly to splat. In hindsight this was probably a mistake, since splatting things in various ways is much more common than constructing tuple types. I am tentatively willing to change this, since probably very few places depend on the current behavior.

@StefanKarpinski
Copy link
Sponsor Member

I'm all for changing this. Where are we even using this at this point?

@JeffBezanson
Copy link
Sponsor Member

There are a very small number of uses in the inference and promotion code. Of course we'd need a new syntax for the current meaning; one thing that works now is (Vararg{Int},) which is probably ok since it doesn't have to be pretty.

@StefanKarpinski
Copy link
Sponsor Member

Yup, that seems just fine.

@JeffBezanson
Copy link
Sponsor Member

I started looking for all the uses of this, and one place this syntax is nice is inside argument lists, for example

function f(d::(Int...))

I wonder if that should be a special case.

@toivoh
Copy link
Contributor

toivoh commented Nov 23, 2013

I remember suggesting to use postfix ... for splatting and prefix ... for varargs construction. How would you feel about

function f(d::(...Int))

etc? I hope that we wouldn't have to make a special case for this. I'm glad that this issue has been lifted because I've been bothered about the current special case.

@JeffBezanson
Copy link
Sponsor Member

That's a very good idea; I think it might be workable.

@StefanKarpinski
Copy link
Sponsor Member

I do like that idea.

@stevengj
Copy link
Member Author

+1

1 similar comment
@johnmyleswhite
Copy link
Member

+1

@staticfloat
Copy link
Sponsor Member

I ran into this today. :P

I'd love to see the prefix/postfix separation. +1

@JeffBezanson
Copy link
Sponsor Member

{...Int} is a good idea but it looks a little weird to me. Instead I'll propose {Int, ...}. That also has the interesting property that you can write {Xs..., ...}, which splats but also makes the type vararg by repeating the last element of Xs.

@nalimilan
Copy link
Member

I agree that @JeffBezanson's proposal looks more natural.

@StefanKarpinski
Copy link
Sponsor Member

So in the proposed syntax {Int, ...} is the type of Int tuples of zero or greater? Whereas {Int...} would attempt to splat Int when constructing a tuple type object?

@mbauman
Copy link
Sponsor Member

mbauman commented Mar 23, 2015

I like the look of {Int, ...}, but it seems to strongly suggest that the first element would be required (i.e., one-or-more ints).

@StefanKarpinski
Copy link
Sponsor Member

Despite the nice analogy between {A,B} is to T{A,B} as (a,b) is to f(a,b), I'm still not entirely convinced that we need such a convenient syntax for tuple types.

@JeffBezanson
Copy link
Sponsor Member

It could become more important in the future, e.g. with function types {A,B}->C. It also opens up other syntactic space for types. We could consider something like T.{Array{T}} for "UnionAll" types.

@mbauman good point that {Int, ...} looks like "one or more". I think I can live with that though.

@JeffBezanson
Copy link
Sponsor Member

Actually the syntax for UnionAll types could be {T<:S}(Array{T}), exactly how they're currently written for method signatures.

@StefanKarpinski
Copy link
Sponsor Member

Using parens in {T<:S}(Array{T}) seems inconsistent with using {...} for tuple types. The prospect of making this work nicely for existential union types is appealing. That's something we do very much need a good syntax for.

@JeffBezanson
Copy link
Sponsor Member

Yes, I suppose it conflicts with the ability to "call" a tuple type. This currently works:

julia> (Int,Int)((1.0,2.0))
(1,2)

{T<:S}{Array{T}} is also available for existentials though.

Going back to function types briefly, if we really want I guess we could have {A,B}->C but use Tuple{A,B} for tuples otherwise.

@StefanKarpinski
Copy link
Sponsor Member

We could also use (A,B)-->C as planned in ancient history.

@JeffBezanson
Copy link
Sponsor Member

The downside is that it wouldn't fit with writing T-->C where T is a tuple type already. Actually that's also why we'd need --> and couldn't use -> as I've been writing. But that part's easy.

@StefanKarpinski
Copy link
Sponsor Member

I don't get that bit – can you elaborate?

@JeffBezanson
Copy link
Sponsor Member

You want to be able to do

T = (A,B)
ftype = T-->C

so that there can be a single variable that represents all of the arguments. You want to be able to pull out any subexpression into a variable. Of course it's possible to have (A,B)-->C be equivalent to

T = Tuple{A,B}
T-->C

but I think pretty suboptimal.

@mauro3
Copy link
Contributor

mauro3 commented Apr 8, 2015

How does this fit with the discussion over in #6984 where {T<:S}->Array{T} was suggested for what Jeff wrote above {T<:S}(Array{T})?

@JeffBezanson
Copy link
Sponsor Member

fixed by #10380

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:breaking This change will break code
Projects
None yet
Development

No branches or pull requests

10 participants