[swift-evolution] [swift-evolution-announce] [Review] SE-0089: Replace protocol<P1, P2> syntax with Any<P1, P2>

L Mihalkovic laurent.mihalkovic at gmail.com
Tue Jun 7 13:35:05 CDT 2016


> On Jun 7, 2016, at 7:51 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
> 
> 
> on Tue Jun 07 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
> 
>>> On Jun 6, 2016, at 12:22 AM, Dave Abrahams <dabrahams at apple.com>
>> wrote:
>>> 
>>> 
>>> on Sun Jun 05 2016, Matthew Johnson <matthew-AT-anandabits.com
>> <http://matthew-at-anandabits.com/>> wrote:
>>> 
>> 
>>>> Sent from my iPhone
>>>> 
>>>>> On Jun 5, 2016, at 3:51 PM, Dave Abrahams via swift-evolution
>>>>> <swift-evolution at swift.org> wrote:
>>>>> 
>>>>> 
>>>>>> on Wed May 25 2016, Matthew Johnson <swift-evolution at swift.org> wrote:
>>>>>> 
>>>>>> Sent from my iPad
>>>>>> 
>>>>>>> On May 25, 2016, at 12:10 PM, Jordan Rose via swift-evolution
>>>>>>> <swift-evolution at swift.org> wrote:
>>>>>>> 
>>>>>>> 
>>>>>>>>> On May 25, 2016, at 05:27, Brent Royal-Gordon via swift-evolution
>>>>>>>>> <swift-evolution at swift.org> wrote:
>>>>>>>>> 
>>>>>>>>> AFAIK an existential type is a type T with type parameters that
>>>>>>>>> are still abstract (see for example
>>>>>>>>> https://en.wikipedia.org/wiki/Type_system#Existential_types),
>>>>>>>>> i.e. have not been assigned concrete values.
>>>>>>>> 
>>>>>>>> My understanding is that, in Swift, the instance used to store
>>>>>>>> something whose concrete type is unknown (i.e. is still abstract),
>>>>>>>> but which is known to conform to some protocol, is called an
>>>>>>>> "existential". Protocols with associated values cannot be packed
>>>>>>>> into normal existentials because, even though we know that the
>>>>>>>> concrete type conforms to some protocol, the associated types
>>>>>>>> represent additional unknowns, and Swift cannot be sure how to
>>>>>>>> translate uses of those unknown types into callable members. Hence,
>>>>>>>> protocols with associated types are sometimes called
>>>>>>>> "non-existential".
>>>>>>>> 
>>>>>>>> If I am misusing the terminology in this area, please understand
>>>>>>>> that that's what I mean when I use that word.
>>>>>>> 
>>>>>>> We’re not consistent about it, but an “existential value” is a value
>>>>>>> with protocol or protocol composition type. My mnemonic for this is
>>>>>>> that all we know is that certain operations exist (unlike a generic
>>>>>>> value, where we also have access to the type). John could explain it
>>>>>>> more formally. We sometimes use “existentials” as a (noun) shorthand
>>>>>>> for “existential value”.
>>>>>>> 
>>>>>>> In the compiler source, all protocols and protocol compositions are
>>>>>>> referred to as “existential types”, whether they have associated
>>>>>>> types or not. Again, a protocol asserts the existence (and
>>>>>>> semantics) of various operations, but nothing else about the
>>>>>>> conforming type. (Except perhaps that it’s a class.) All protocols
>>>>>>> are thus “existential types” whether or not the language supports
>>>>>>> values having that type.
>>>>>>> 
>>>>>>> It is incorrect to say that protocols with associated types (or
>>>>>>> requirements involving Self) are “non-existential”.
>>>>>> 
>>>>>> I haven't heard people using this term myself, but I imagine they
>>>>>> probably mean "can't form an existential value with the protocol".
>>>>>> There certainly appears to be a lot of confusion in the community with
>>>>>> many not realizing that this is a temporary limitation of the
>>>>>> implementation, not a necessary fact.
>>>>> 
>>>>> As far as I know there is no known way to make protocols with Self
>>>>> requirements usefully “existentiable,” or whatever you want to
>> call it.
>>>>> So unless I'm missing something, in this respect, the limitation
>> is not
>>>>> temporary at all.
>>>> 
>>>> Take a look at the Equatable example in the opening existentials
>>>> section of Doug's manifesto:
>>>> 
>> https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160229/011666.html
>>> 
>>> Yes, note that I said *usefully* “existential.”
>> 
>> Fair enough.  But note that I was only talking about the inability to
>> form and open such an existential which appears likely to be a
>> temporary limitation given the generics manifesto (of course things
>> could change).
>> 
>>> While we can of course downcast in this way, you have to handle the
>>> failure case and it's not like you can use this to make a
>>> heterogeneous Set<Hashable>.  AFAICT, this is not at all like what
>>> happens with associated types, where Collection<Element: Int> has
>>> obvious uses.
>> 
>> We can’t use this to form Set<Hashable> because existentials don’t
>> conform to the protocol.  I know there is complexity in implementing
>> this and it is not possible to synthesize conformance of the
>> existential for all protocols, but AFAIK it isn’t a settled point that
>> we won’t try to improve the situation in some way.  
> 
> Of course.  I'm just trying to point out that such existentials are
> likely to be a whole lot less useful than many people might think.
> 
>> Maybe we can make progress here somehow.
> 
> Maybe.  It's a research project.
> 
>> In the meantime, we can make a simple wrapper type to provide the
>> required conformance and make a Set<HashableWrapper> that allows us to
>> put Hashable into a Set.  This isn’t ideal but it is a lot less
>> boilerplate than is involved in manual type erasure today where you
>> need to define a struct, base class, and wrapper class.  I’d say
>> that’s a win even if we’d like to do better in the future.
>> 
>> struct HashableWrapper: Hashable {
>>    var value: Hashable
>>    public var hashValue: Int { return base.hashValue }
>> }
>> 
>> public func ==(lhs: HashableWrapper, res: HashableWrapper) -> Bool {
>>    if let lhsValue = lhs.value openas T { // T is a the type of
>> lhsValue, a copy of the value stored in lhs
>>        if let rhsValue = rhs.value as? T {      // is res also a T?
>>            // okay: lhsValue and rhsValue are both of type T, which
>> we know is Equatable
>>            if lhsValue == rhsValue { 
>>                return true
>>            }
>>        } 
>>    }
>>    return false
>> }
>> 
>> (We could also do this with a generic Wrapper<T> and conditional
>> conformance in an `extension Wrapper: Hashable where T == Hashable` if
>> we don’t want a bunch of wrapper types laying around)
> 
> I don't think I"ve made my point very well.  Equatable (the
> Self-requirement part of Hashable) has a simple answer when the types
> don't match, as I noted in the POP talk.  Let me put it differently:
> existentializing a protocol with Self requirements comes with
> limitations that I'm betting most people haven't recognized.  For
> example, you won't be able to add two arbitrary FloatingPoint
> existentials.  I think many people view working with existentials as
> “easier” or “cleaner” than working with generics, but haven't realized
> that if you step around the type relationships encoded in Self
> requirements and associated types you end up with types that appear to
> interoperate but in fact trap at runtime unless used in exactly the
> right way.

I was thinking more about that, and it seems that of all the possible generics extensions, the least ‘generic’ might be the most interesting in the short term: a type safe way to open existentials 

But rather than Doug, strawman suggestion:
if let storedInE1 = e1 openas T {     // T is a the type of storedInE1, a copy of the value stored in e1
  if let storedInE2 = e2 as? T {      // is e2 also a T?
    if storedInE1 == storedInE2 { … } // okay: storedInT1 and storedInE2 are both of type T, which we know is Equatable
  }
}
I’d rather have something like this (using the new extended ‘if/where’)
if let storedInE1 = e1 as? T;
   let storedInE2 = e2 as? T;
       storedInE1 == storedInE2 { … } // okay: storedInT1 and storedInE2 are both of type T, which we know is Equatable
  }
}
which with my ongoing little pet-project might go down to
if let! e1 as? T;
   let! e2 as? T;
       e1 == e2 { … } // okay: e1 and e2 are both of type T, which we know is Equatable
  }
}


> 
> -- 
> Dave
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160607/c1da95de/attachment.html>


More information about the swift-evolution mailing list