These are fantastic proposals! With these in place, there would be precious 
little to envy Haskell. 

For example, regarding “counter-proposal against making generic parameters 
public”, the current behaviour of Swift is essentially a bug, as reported by 
Noah Blake (https://bugs.swift.org/browse/SR-1065 
<https://bugs.swift.org/browse/SR-1065>).

Then there is:

> (3) Using variadic patterns (shamefully borrowing the `...` notation from C++ 
> here to mean an arbitrary-length list of patterns to match or expressions to 
> expand):
> 
>     extension (T...) : Equatable where T : Equatable... {}
> 
>     func == <T...>(lhs: (T...), rhs: (T...)) -> Bool where T : Equatable... { 
> /* ... */ }


Not only that this would make certain Standard Library signatures less 
embarrassing, but would enable entirely new programming patterns. For example, 
the size of a fixed-length sequence could be type guaranteed like so:

    let v = Vector<_2,_0,_1,_6>(repeatedValue: 42)
    v.count // 2016

… wehere types like _2 and _6 may be caseless enums:

    enum _2 : DecimalDigitType { }

milos

> On 7 Apr 2016, at 09:44, Pyry Jahkola via swift-evolution 
> <[email protected]> wrote:
> 
> Jordan,
> 
> Your comments brought up a few more closely related ideas that have been 
> bubbling under.
> 
> To everyone,
> 
> Sorry for going beyond topic here. The discussion of the further proposals 
> below should be taken into their own threads if there's interest. I'm just 
> trying to motivate what else moving out the `where` clause would make 
> possible.
> 
> 1. My counter-proposal against making generic parameters public
> 
>> Another factor here is that we've been planning for a while for generic 
>> parameters to types to be exposed as implicit member typealiases, since they 
>> already conflict with the namespace for member typealiases. Therefore it's 
>> important to name generic parameters to types well, but less important to do 
>> so for generic parameters for functions. (They're also much less likely to 
>> be ad hoc for types; there has to be something that describes the relation 
>> between the Self type and the parameter, while the function might not have 
>> anything more interesting than "operand".)
> 
> I disagree with that. I think it's more natural to restrict generic type 
> parameters to the immediate local scope of the class/struct/enum definition 
> or extension, and simply allow making the type public with `typealias`. For 
> example, this would make `Element` a public member of `Array`:
> 
>     public enum Result<T, Error> {
>         public typealias Value = T // This makes `Value` public for 
> extensions and everyone
>     }
> 
> I would even allow publishing the otherwise local name by repeating it in 
> `typealias` like this:
> 
>     public struct Array<Element> { // This `Element` is only available in 
> (the missing) where clause and the scope below.
>         public typealias Element = Element // This line makes `Element` 
> available everywhere, see below.
>     }
> 
>     extension Array<T> { // <- Regardless of the pattern (`T`) used here,
>         var mid: Element? { // the type `Element = T` is available here
>             return ...      // because it was made public elsewhere.
>         }
>     }
>     extension Array<Optional<T>> { // <- An example of pattern matching (see 
> further below).
>         // Ditto, `Element = T?`
>     }
> 
>     typealias Ints = [Int]
>     let x: Ints.Element = ... // Int
> 
> Next, I propose how to extend this syntax with pattern matching. The above 
> thinking is a natural progression from the use of pattern matching for 
> introducing generic type parameters in type `extension`s.
> 
> 
> 2. Proposal to enable pattern matching of generic types in generic parameters
> 
>> This is also a minor point against declaring generic parameters for 
>> extensions, since they would have to match up. We also do need a syntax some 
>> day to represent new parameters:
>> 
>> // For expository purposes only:
>> extension <T> Array where Element == Optional<T>
>> 
>> But that deserves its own proposal. I just don't want us to paint ourselves 
>> into a corner.
> 
> I agree that we need that feature. But instead of your proposed syntax, I'd 
> take influence from the already existing pattern matching that we have at 
> value level, such that:
> 
> 1. any generic type expressions within the angle brackets `<...>` are taken 
> as patterns to match against  (e.g. `Array<Element>`, `Optional<Foo>`, 
> `Dictionary<S, S>`), and
> 2. all non-generic type identifiers in those expressions are taken as generic 
> parameters and not concrete types (`Element`, `Foo`, or `S`, respectively).
> 
> Your example would translate into the first of these two:
> 
>     extension Array<Optional<T>> { // extending [T?] doesn't even need any 
> `where` clause
>         func unwrapAll() -> [T] { ... }
>     }
> 
>     extension Dictionary<K, Dictionary<K, V>> { // This pattern match 
> requires the same `K` twice.
>         subscript(x: K, y: K) -> V { ... }
>     }
> 
> The generic parameters would shadow any existing names in the outer scope, 
> i.e. `extension Array<String>` would mean the same as `extension 
> Array<Element>`. But it would be a good idea to add a warning (or linter 
> error) at least when stdlib types such as `Swift.String` are shadowed like 
> that. I think the benefits from pattern matching outweigh the possible 
> confusion, especially since you can't use any members of `String` if you 
> mistakenly wrote `extension Array<String> { ... }` instead of `extension 
> Array<T> where T == String`.
> 
> With this syntax, we could also allow extending Array, Dictionary, and 
> Optional in their more natural notation:
> 
>     extension [T?] {
>         func unwrapAll() -> [T] { /* ... */ }
>     }
> 
>     extension [K: [K: V]] {
>         subscript(x: K, y: K) -> V { /* ... */ }
>     }
> 
> Here are a few more (somewhat realistically needed) examples with further 
> `where` clauses:
> 
>     extension [T] where T : Hashable { /* ... */ }
>     extension T? where T : Comparable { /* ... */ }
>     extension [K: V] where V : Equatable { /* ... */ }
>     extension [T] where T == String { /* ... */ }
> 
> I think pattern matching is a very expressive, intuitive, and readable 
> technique that works quite well for this purpose, better than what we 
> currently have.
> 
> 
> 3. Future directions
> 
> Brent already pointed out that the `where` constraint syntax could be used 
> for dependent types (i.e. type-level values as generic parameters). Four more 
> possible directions come to my mind:
> 
> (1) Adding conditional protocol conformances:
> 
>     extension [T]: Equatable where T : Equatable { /* ... */ }
>     extension [T]: Comparable where T : Comparable { /* ... */ }
>     extension [K, V]: Equatable where V : Equatable { /* ... */ }
>     extension Foo<X, Bar<Y>> : Bazzable where X : Baz, Y : Baz { /* ... */ }
> 
> (2) Extending non-nominal types:
> 
>     extension (A, B) { var tail: B { /* ... */ }}
>     extension (A, B, C) { var tail: (B, C) { /* ... */ }}
> 
> (3) Using variadic patterns (shamefully borrowing the `...` notation from C++ 
> here to mean an arbitrary-length list of patterns to match or expressions to 
> expand):
> 
>     extension (T...) : Equatable where T : Equatable... {}
> 
>     func == <T...>(lhs: (T...), rhs: (T...)) -> Bool where T : Equatable... { 
> /* ... */ }
> 
> (4) Since all type constraints with `:` fly out to of the generic parameter 
> list into the `where` clause, we could enable the use of colons to give 
> labels to generic parameters (and thus even make some of them have default 
> values):
> 
>     struct Parser<encoding: Encoding, input: Input>
>         where Encoding : EncodingProtocol /*, ... */
>     {
>         // ...
>     }
> 
>     let parser = Parser<encoding: UTF8, input: String>()
> 
> — Pyry
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to