Notes from Swift core team 2016-03-15 design discussion


(Alex Martini) #1

To help keep proposals moving forward, the Swift core team has set aside some time specifically for design discussions of upcoming proposals. Below are some rough notes from the yesterday's discussion.

These are informal comments, intended to guide the proposals in directions that draw constructive feedback. You are welcome to ignore the feedback, agree with it, or disagree with it. As always, the formal decision doesn't happen until after the review period ends.

SE-0047 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0047>
This is about switching the polarity of @warn_unused_result and renaming it to @discardable as something on the return type.

Is there a subtype conversion? Is Void -> Int a subtype or supertype of Void -> Void? No, it’s not; we just have a special rule for closures.

If we put this in the type system, we would want it to be a function attribute rather than a declaration attribute. It’s not obvious why it’s a bad idea to have this in the type system... It’s a little bit outside the bounds of what the type system normally does; it’s not that important of a semantic property.

It looks like the proposal has an error in the second to last line before “Mutating Variants” – it should either be a hard error or nothing. Also the case below:

let x = f
x()
c = x()
In the more general case, if x is a closure...

How many cases are there where you want to mark the result as discardable so you don’t have to write _ = foo() to explicitly silence the warning about an unused result?

We almost certainly don’t want to allow overloading based on this. Does the propagation even work? If you have a compose operator that takes T -> U and U -> V and try to pass it a T -> discardable U you won’t get a discardable V unless we make it a full qualifier in the type system.

Ok... if we don’t make it part of the function type, where would we want the attribute to go? This is similar to how we place inout. It would be similar to how we place @autoclosure but that attribute is currently not quite right.

It would be consistent to put it on the function declaration. There are other places though where we might want attributes on the function type that are understood to not effect the actual function type, such as some kind of ownership rules.

func f () -> @discardable Int // we're saying this is valid
let x: () -> @discardable Int // but we wouldn't let you write this

func g() -> @convention(block) () -> () {...} // we wouldn't allow this either
In that last case, you can put attributes on types. We like how putting the @discardable on the type because of how it reads, but it’s not on the type.

Counterpoint: It’s actually more semantically part of the function. You don’t have a “discardable integer”, you have a function whose result is discardable.

SE-0042 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0042>
Right now if you access an instance method on a type, you get this curried thing that accepts “self” and then the members. It’s not useful for the standard library because they want flattened functions. And for mutable methods, because of how the in-out duration lasts, we end up with a miscompile that scribbles over random memory.

Looking to the future, we can get operators on the type. Then operators would have the same type in both cases.

We probably don’t need migration. If you wrote #selector(foo as Bar) before, the Bar part will change. But that’s not very common and #selector is still pretty new.

SE-0043 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0043>
This seems like a simple generalization of our rules. People coming from the ML family would just expect this to work. It’s a resonable expectation.

SE-0048 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0048>
This is straightforward and 95% implemented. The contentious point is that it starts simple: you can’t add constraints to the type alias.

We want to avoid type-based metaprogramming.

Unclear if this would work:

typealias StringDictionary<T> = Dictionary<String, T>
It need to infer that T must be hashable. Maybe it’s only 85% implemented.

SE-0049 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0049>
In short, @noescape and @autoclosure are attributes on the parameter. We got away with it before, but now that we’re requiring you to manually uncurry, you can’t write things that you used to be able to write. None of this makes sense; we should only accept these attributes in the type position.


(Douglas Gregor) #2

Clarification here: the example is

typealias DictionaryToStrings<T> = Dictionary<T, String>

Either we infer T to require Hashable, or we call this ill-formed and require the user to write

typealias DictionaryToStrings<T: Hashable> = Dictionary<T, String>

  - Doug

···

On Mar 16, 2016, at 5:27 PM, Alex Martini via swift-evolution <swift-evolution@swift.org> wrote:

To help keep proposals moving forward, the Swift core team has set aside some time specifically for design discussions of upcoming proposals. Below are some rough notes from the yesterday's discussion.

These are informal comments, intended to guide the proposals in directions that draw constructive feedback. You are welcome to ignore the feedback, agree with it, or disagree with it. As always, the formal decision doesn't happen until after the review period ends.

SE-0048 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0048>
This is straightforward and 95% implemented. The contentious point is that it starts simple: you can’t add constraints to the type alias.

We want to avoid type-based metaprogramming.

Unclear if this would work:

typealias StringDictionary<T> = Dictionary<String, T>
It need to infer that T must be hashable. Maybe it’s only 85% implemented.


(Michael Gottesman) #3

In the future, can you make each SE-**** into a link to the github page of the proposal?

Michael

···

On Mar 16, 2016, at 5:27 PM, Alex Martini via swift-evolution <swift-evolution@swift.org> wrote:

To help keep proposals moving forward, the Swift core team has set aside some time specifically for design discussions of upcoming proposals. Below are some rough notes from the yesterday's discussion.

These are informal comments, intended to guide the proposals in directions that draw constructive feedback. You are welcome to ignore the feedback, agree with it, or disagree with it. As always, the formal decision doesn't happen until after the review period ends.

SE-0047 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0047>
This is about switching the polarity of @warn_unused_result and renaming it to @discardable as something on the return type.

Is there a subtype conversion? Is Void -> Int a subtype or supertype of Void -> Void? No, it’s not; we just have a special rule for closures.

If we put this in the type system, we would want it to be a function attribute rather than a declaration attribute. It’s not obvious why it’s a bad idea to have this in the type system... It’s a little bit outside the bounds of what the type system normally does; it’s not that important of a semantic property.

It looks like the proposal has an error in the second to last line before “Mutating Variants” – it should either be a hard error or nothing. Also the case below:

let x = f
x()
c = x()
In the more general case, if x is a closure...

How many cases are there where you want to mark the result as discardable so you don’t have to write _ = foo() to explicitly silence the warning about an unused result?

We almost certainly don’t want to allow overloading based on this. Does the propagation even work? If you have a compose operator that takes T -> U and U -> V and try to pass it a T -> discardable U you won’t get a discardable V unless we make it a full qualifier in the type system.

Ok... if we don’t make it part of the function type, where would we want the attribute to go? This is similar to how we place inout. It would be similar to how we place @autoclosure but that attribute is currently not quite right.

It would be consistent to put it on the function declaration. There are other places though where we might want attributes on the function type that are understood to not effect the actual function type, such as some kind of ownership rules.

func f () -> @discardable Int // we're saying this is valid
let x: () -> @discardable Int // but we wouldn't let you write this

func g() -> @convention(block) () -> () {...} // we wouldn't allow this either
In that last case, you can put attributes on types. We like how putting the @discardable on the type because of how it reads, but it’s not on the type.

Counterpoint: It’s actually more semantically part of the function. You don’t have a “discardable integer”, you have a function whose result is discardable.

SE-0042 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0042>
Right now if you access an instance method on a type, you get this curried thing that accepts “self” and then the members. It’s not useful for the standard library because they want flattened functions. And for mutable methods, because of how the in-out duration lasts, we end up with a miscompile that scribbles over random memory.

Looking to the future, we can get operators on the type. Then operators would have the same type in both cases.

We probably don’t need migration. If you wrote #selector(foo as Bar) before, the Bar part will change. But that’s not very common and #selector is still pretty new.

SE-0043 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0043>
This seems like a simple generalization of our rules. People coming from the ML family would just expect this to work. It’s a resonable expectation.

SE-0048 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0048>
This is straightforward and 95% implemented. The contentious point is that it starts simple: you can’t add constraints to the type alias.

We want to avoid type-based metaprogramming.

Unclear if this would work:

typealias StringDictionary<T> = Dictionary<String, T>
It need to infer that T must be hashable. Maybe it’s only 85% implemented.

SE-0049 <file:///Users/alexmartini/DevPubs%20Git%20Repositories/Swift%20Language%20Review/_build/html/LR_MeetingNotes/MeetingNotes-03-15-2016.html#se-0049>
In short, @noescape and @autoclosure are attributes on the parameter. We got away with it before, but now that we’re requiring you to manually uncurry, you can’t write things that you used to be able to write. None of this makes sense; we should only accept these attributes in the type position.

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


(Thorsten Seitz) #4

I actually do prefer the explicit variant without type inference as I find it much clearer to see what the typealias requires.

-Thorsten

···

Am 23.03.2016 um 17:38 schrieb Douglas Gregor via swift-evolution <swift-evolution@swift.org>:

Clarification here: the example is

typealias DictionaryToStrings<T> = Dictionary<T, String>

Either we infer T to require Hashable, or we call this ill-formed and require the user to write

typealias DictionaryToStrings<T: Hashable> = Dictionary<T, String>


(Douglas Gregor) #5

I actually do prefer the explicit variant without type inference as I find it much clearer to see what the typealias requires.

As do I. Also, we don’t currently have any place in the language where we infer constraints from the *definition* of an entity.

  - Doug

···

On Mar 23, 2016, at 10:36 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

-Thorsten

Am 23.03.2016 um 17:38 schrieb Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

Clarification here: the example is

typealias DictionaryToStrings<T> = Dictionary<T, String>

Either we infer T to require Hashable, or we call this ill-formed and require the user to write

typealias DictionaryToStrings<T: Hashable> = Dictionary<T, String>


(Shawn Erickson) #6

I strongly favor being explicit.

-Shawn

···

On Wed, Mar 23, 2016 at 10:42 AM Douglas Gregor via swift-evolution < swift-evolution@swift.org> wrote:

On Mar 23, 2016, at 10:36 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

I actually do prefer the explicit variant without type inference as I find
it much clearer to see what the typealias requires.

As do I. Also, we don’t currently have any place in the language where we
infer constraints from the *definition* of an entity.


(Chris Lattner) #7

Thanks, I agree, I modified the proposal to include that.

-Chris

···

On Mar 23, 2016, at 10:57 AM, Shawn Erickson via swift-evolution <swift-evolution@swift.org> wrote:

On Wed, Mar 23, 2016 at 10:42 AM Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Mar 23, 2016, at 10:36 AM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

I actually do prefer the explicit variant without type inference as I find it much clearer to see what the typealias requires.

As do I. Also, we don’t currently have any place in the language where we infer constraints from the *definition* of an entity.

I strongly favor being explicit.