Three quick(ish) generics enhancements; *maybe* phase 1


(David Sweeris) #1

I want to revisit some specific generics idea that, IIRC, were generally well-recieved at the time, but the conversation died down and nobody got around to writing formal proposals. I want to revisit them now (as opposed to in phase 2) because I don’t know how much “growing room” there is in the ABI for generics to gain features. It’d be a shame to close the door on these simply because nobody said anything. Anyway...

1) Allow generic parameters to have optional labels: struct Array <Element T> {…} //`let x = Array<Element: Double>` Not the best example, though, since I’d definitely argue against adding a label here
2) Allow literals as generic arguments: struct Array <T, Length: Int> {…} //Allows for `let x = Array<Double, Length: 10>()`
3) Allow generic parameters to have default values: struct Array <T, Length: Int, FixedSize: Bool = false> {…} //The `let x…` from above still works, as well as `let y = Array<Double, Length: 10, FixedSize: true>()`

In addition to concerns regarding binary backwards compatibility, there’s one part where it might affect source code compatibility, too… If generic arguments get optional labels, would we need to use a `_` like with function arguments to indicate that we don’t intend for a label? Personally, I think a better solution would be to just make the labels be the same as the parameter name and have their use be optional altogether (except for parameters with default values — those would always need labels in case the type has several and you skip some), but perhaps others will feel differently.

Anyway, if this is phase 1 material, I’ll cheerfully get a informal proposal written up to kick off the discussion thread. If not, I’ll shelve them until phase 2.

- Dave Sweeris


(Tino) #2

My personal theory of the whole phase-one construct is that it's just a way to calm everyone down, so that there is more time to actually do some work on the code :wink:

Afair, the conversation about this didn't fade out slowly, but was stopped by someone saying "that addition is to big to be considered now".
I'm to lazy to fight with the medium to find a reference, but there is a draft for a proposal:
https://github.com/SwiftInofficialEvolution/Home/wiki/compile-time%20parameters

I think the idea is quite useful, but it might be confusing for some people that they can create Vector<Int, size: 4> but not Vector<Int, size: myIntValue>.
The issue with the latter is obvious when you fully understand the concept, but if myIntValue is known to be a constant at compile time (or a fixed case of an enum…), it's harder to decide wether the compiler should accept it.

In some aspect, the parameters have requirements that are opposite to "inout" — but that's a very fresh thought, and I've no idea if that duality might help.

- Tino


(Dave Abrahams) #3

I want all the features you've listed... someday. They're purely
additive, so there's no urgency to discuss them now, IMO.

···

on Thu Dec 22 2016, David Sweeris <swift-evolution@swift.org> wrote:

I want to revisit some specific generics idea that, IIRC, were
generally well-recieved at the time, but the conversation died down
and nobody got around to writing formal proposals. I want to revisit
them now (as opposed to in phase 2) because I don’t know how much
“growing room” there is in the ABI for generics to gain features. It’d
be a shame to close the door on these simply because nobody said
anything. Anyway...

1) Allow generic parameters to have optional labels: struct Array
<Element T> {…} //`let x = Array<Element: Double>` Not the best
example, though, since I’d definitely argue against adding a label
here
2) Allow literals as generic arguments: struct Array <T, Length: Int>
{…} //Allows for `let x = Array<Double, Length: 10>()`
3) Allow generic parameters to have default values: struct Array <T,
Length: Int, FixedSize: Bool = false> {…} //The `let x…` from above
still works, as well as `let y = Array<Double, Length: 10, FixedSize:
>()`

--
-Dave


(David Sweeris) #4

How so? I agree that variadic tuples could replace the third example (quite well, actually), but I don't see how they or @pure (alone or in combination) have the same functionality in general. With default generic parameters, you could effectively have partial sub-typing of non-reference types. You wouldn't be able to add any non-computed properties, but every function and computed property could have a different implementation depending on the value of the generic parameter in question. Of course, we could do this now, but it'd be quite annoying to have to specify, say, 5 configuration every parameter when most of the time they have the same value (and it'd be quite easy to make a mistake in their order without the labels reminding you what goes where).

Is your claim that, regardless of whether their functionality exactly overlaps, for any given use case for 2&3, there's a semantically (as opposed to syntactically) equivalent way to do it with the existing language plus @pure or variadic generics/tuples? Strictly speaking, I'm not sure I can disprove that. It seems to me, though, that it'd be easier to have an 'Array<T, Length: 3, FixedSize: true>' interoperate with the rest of the stdlib than it would a '(T, T, T)'. (Don't misunderstand me, though, I'm still very much in favor of enhancing tuples... they solve different problems.)

- Dave Sweeris

···

On Dec 23, 2016, at 04:08, Антон Жилин <antony.zhilin@gmail.com> wrote:

On 2) and 3), I feel like @pure and variadic generics/tuples would cover most of the use cases.


(David Sweeris) #5

Yes, that's one of the proposals I was thinking of!

I think if the type was specifically an "IntegerLiteral", the restriction would be more obvious. 'IntegerLiteralType' would be better, but it's just typealiased to 'Int', so maybe not better enough.

It occurs to me that it might be possible to create a 'Vector<Int, size: myIntValue>' by considering 'Vector<Int, size:_>' to be a kind of "implicit protocol" (and one with a generic parameter, "Int", no less!) to which all concrete instances of Vector would conform. Then we could write "func foo(x:Int)->Vector<Int, Size:_> {...}" and it'd just work. I think... maybe not... I haven't thought about it longer than it's taken to write out.

That "opposite of inout" thought is quite interesting... I'll have to think about it for a while.

- Dave Sweeris

···

On Dec 23, 2016, at 03:13, Tino Heth <2th@gmx.de> wrote:

My personal theory of the whole phase-one construct is that it's just a way to calm everyone down, so that there is more time to actually do some work on the code :wink:

Afair, the conversation about this didn't fade out slowly, but was stopped by someone saying "that addition is to big to be considered now".
I'm to lazy to fight with the medium to find a reference, but there is a draft for a proposal:
https://github.com/SwiftInofficialEvolution/Home/wiki/compile-time%20parameters

I think the idea is quite useful, but it might be confusing for some people that they can create Vector<Int, size: 4> but not Vector<Int, size: myIntValue>.
The issue with the latter is obvious when you fully understand the concept, but if myIntValue is known to be a constant at compile time (or a fixed case of an enum…), it's harder to decide wether the compiler should accept it.

In some aspect, the parameters have requirements that are opposite to "inout" — but that's a very fresh thought, and I've no idea if that duality might help.


(Xiaodi Wu) #6

Fixed-size arrays have been discussed on this list in the past; the core
team settled on a syntax of `4xInt` (Int array of length 4), which is
apparently already the spelling that's used in LLVM. Not sure what happened
to that discussion; I seem to recall that it was just a matter of not
having enough engineering resources to implement.

Default values and constants in generics are already listed on the Generics
Manifesto; I assume that means the core team thinks they're fine ideas, and
they'll be proposed and implemented if engineering resources permit...

···

On Fri, Dec 23, 2016 at 11:56 David Sweeris via swift-evolution < swift-evolution@swift.org> wrote:

On Dec 23, 2016, at 03:13, Tino Heth <2th@gmx.de> wrote:

My personal theory of the whole phase-one construct is that it's just a
way to calm everyone down, so that there is more time to actually do some
work on the code :wink:

Afair, the conversation about this didn't fade out slowly, but was stopped
by someone saying "that addition is to big to be considered now".
I'm to lazy to fight with the medium to find a reference, but there is a
draft for a proposal:

https://github.com/SwiftInofficialEvolution/Home/wiki/compile-time%20parameters

I think the idea is quite useful, but it might be confusing for some
people that they can create Vector<Int, size: 4> but not Vector<Int, size:
>.
The issue with the latter is obvious when you fully understand the
concept, but if myIntValue is known to be a constant at compile time (or a
fixed case of an enum…), it's harder to decide wether the compiler should
accept it.

In some aspect, the parameters have requirements that are opposite to
"inout" — but that's a very fresh thought, and I've no idea if that duality
might help.

Yes, that's one of the proposals I was thinking of!

I think if the type was specifically an "IntegerLiteral", the restriction
would be more obvious. 'IntegerLiteralType' would be better, but it's
just typealiased to 'Int', so maybe not better enough.

It occurs to me that it *might* be possible to create a 'Vector<Int,
size: myIntValue>' by considering 'Vector<Int, size:_>' to be a kind of
"implicit protocol" (and one with a generic parameter, "Int", no less!) to
which all concrete instances of Vector would conform. Then we could write
"func foo(x:Int)->Vector<Int, Size:_> {...}" and it'd just work. I think...
maybe not... I haven't thought about it longer than it's taken to write out.

That "opposite of inout" thought is quite interesting... I'll have to
think about it for a while.

- Dave Sweeris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Chris Lattner) #7

My personal theory of the whole phase-one construct is that it's just a way to calm everyone down, so that there is more time to actually do some work on the code ;-)

Your theory isn’t exactly wrong: it turns out while the majority of people on swift-evolution want to talk about new features, that a large majority of Swift *users* don’t actually care about new features: they want the existing compiler to work better with its current feature set.

As such, the Swift team is focused on making the compiler crash less, compile faster, and add critical features necessary for ABI stability (a long term strategic goal). This does lead to some new features that are demanded by the standard library (e.g. conditional conformances), but the majority of the focus is on reducing technical debt and improving the quality of the compiler.

Afair, the conversation about this didn't fade out slowly, but was stopped by someone saying "that addition is to big to be considered now".
I'm to lazy to fight with the medium to find a reference, but there is a draft for a proposal:
https://github.com/SwiftInofficialEvolution/Home/wiki/compile-time%20parameters

I think the idea is quite useful, but it might be confusing for some people that they can create Vector<Int, size: 4> but not Vector<Int, size: myIntValue>.
The issue with the latter is obvious when you fully understand the concept, but if myIntValue is known to be a constant at compile time (or a fixed case of an enum…), it's harder to decide wether the compiler should accept it.

I would love to see this happen some day, but it is one of MANY things that I think need to happen over the next “10" years. The concept of "Swift 4 stage 1” is to cause an intense focus on the most important issues, and this is one of many that can be added later. As such, we should wait until we have the ability to properly consider additive features, and weigh them against each other to determine which is the most critical in the short term. While there are a ton of really great things that can be added now, I am personally super focused on ensuring that new things build towards Swift being a great language in 20 years.

I’m happy to sacrifice cool new features in the short-term to ensure that Swift has a fantastic long-term future.

-Chris

···

On Dec 23, 2016, at 3:13 AM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:


(Georgios Moschovitis) #8

I’m happy to sacrifice cool new features in the short-term to ensure that Swift has a fantastic long-term future.

While I totally I agree with prioritising for the long-term, I find a 20-year horizon impractical.
I hope Swift will converge to a fantastic general-purpose language much sooner :slight_smile: