> On May 25, 2016, at 2:22 PM, Brent Royal-Gordon <br...@architechies.com> 
> wrote:
> 
>> But if we are going to remove the ability to use typealiases bound to `Any` 
>> in constraints we need to introduce an alternative mechanism for factoring 
>> out constraints (hopefully a superior mechanism that can abstract over 
>> constraints that relate generic parameters to each other).
> 
> I could certainly imagine having, for instance, a `constraintalias` keyword:
> 
>       constraintalias HashableAndComparable = Hashable, Comparable
>       constraintalias CollectionOfConforming<ElementConstraint> = Collection 
> where .Element: ElementConstraint
> 
>       let value: Any<HashableAndComparable> = 123
>       
>       func sum<C: CollectionOfConforming<Integer>>(numbers: C) -> 
> C.Iterator.Element {
>               return numbers.reduce(0, combine: +)
>       }

If we do something specific to generic constraints I would prefer to see 
something that generalizes to support cases where you want to accept two types 
that both conform to `Sequence`, `Collection`, etc and both have the same 
`Element` (or any other constraint that relates associated types from more than 
one type argument).  It could be similar to what you have, but slightly more 
generalized.


func sum
        <T, C1, C2
        where C1: Sequence, C2: Sequence, C1.Iterator.Element == T, 
C2.Iterator.Element == T>
        (c1: C1, c2: C2, op: (T, T) -> T) -> [T] {
        return zip(c1, c2).map(op)
}

This would allow me to write something along the lines of:

func zipMap
        <S1, S2 where SameElementSequences<S1, S2>>
        (s1:S1, s2: S2, op: (S1.Element, S2.Element) -> S1.Element) -> 
[S1.Element] {
        return zip(s1, s2).map(op)
}

So what syntax do we use to define something like `SameElementSequences<S1, S2 
>`?  It is effectively a predicate that returns true if all of the constraints 
it defines are satisfied.  It could be similar to what you have above, but we 
would need to allow for more than one “constrainee”.

Maybe it would look something like this:

constraint SameElementSequences S1, S2 = 
        S1: Sequence, S2: Sequence
        where S1.Element == S2.Element

If we want to allow concrete types and higher order constraints to be passed we 
would have to specify “kinds” for the arguments to the constraints.  We might 
say `Constrainee` for an argument that is getting constrained, `Type` for a 
concrete type argument and `Constraint` for a higher order constraint that 
applies to a single type and something like function type syntax for 
multi-argument higher order constraints: `(Type, Constrainee, Constraint) -> 
Constraint` or something like that.

This would let us do something like:

constraint SequencesOf Element: Type, S1: Constrainee, S2: Constrainee =
        S1: Sequence, S2: Sequence
        where S1.Element == Element, S2.Element == Element

Used like this: 

func intZipMap
        <S1, S2 where SequencesOf<Int, S1, S2>>
        (s1:S1, s2: S2, op: (Int) -> Int) -> [Int] {
        return zip(s1, s2).map(op)
}

We could allow shorthand for simple constraints where the “kinds” are omitted 
and assumed to be `Constrainee`.

Ideally we would be able to overload constraints so we could use the name 
“SequencesOf” for a constraint that accepts three sequences, etc.

I think I prefer `constraint` rather than `constraintalias` but am open to 
arguments for both of them.

I like that you are allowed a `constraintalias` to be used as an existential.  
That would still work for single argument constraints in the generalized form I 
am suggesting.

I’m just spitballing on syntax and keyword names here to try and communicate 
the capability that I think we should strive for.  I’m interested in hearing 
everyone’s thoughts on this…

-Matthew

> 
> -- 
> Brent Royal-Gordon
> Architechies
> 

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

Reply via email to