> On May 18, 2016, at 12:12 PM, Adrian Zubarev via swift-evolution
> <[email protected]> wrote:
>
> Okay now I feel like we’re merging everything we came up until now :D I’d
> love to see something like this happen to Swift, because `Any` seems to be a
> really powerful beast one day.
>
> One quick question: Do we really need this "This must be the first
> requirement, if present.“?
I’m on the fence about this. The reason it would matter is for readability.
The counter argument to that is that you can’t rely on the first argument being
a class to determine whether a composed Any will have a class constraint or not.
>
> I’d say the compiler should reorder all types as it wants to. Current
> protocol<> already doing this today.
>
> e.g.
>
> protocol A {}
> protocol B {}
>
> typealias C = protocol<A, B>
> typealias D = protocol<B, A>
>
> print(C) // prints protocol<A, B>
> print(D) // prints protocol<A, B>
> print(C.self == D.self) // prints true
>
> Basically what I mean
>
> Any<SomeProtocol, class, AnotherProtocol>
>
> Any<Any<ProtocolA, ProtocolB>, UIView>
>
> should be valid.
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 18. Mai 2016 bei 18:30:02, Austin Zheng via swift-evolution
> ([email protected] <mailto:[email protected]>) schrieb:
>
>> I made heavy revisions to my proposal to reflect all the great feedback I
>> got from you and several other folks
>> (https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md
>>
>> <https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md>).
>>
>> Here are a couple of thoughts:
>>
>> - I used 'requirements' because that's how the grammar describes similar
>> constructs elsewhere in Swift. Open to change, though.
>>
>> - Having only one where clause makes complete sense. Protocol extensions and
>> generics all use one where clause, so should this construct.
>>
>> - The "P can be used in lieu of Any<P>" just means you can declare e.g. "x :
>> Equatable" if you want, instead of "x : Any<Equatable>", just like you can
>> with protocols without associated types or self requirements today.
>>
>> - I've come to the conclusion that it's probably best to propose the
>> proposal in the most general form, and allow any reviewers on the core team
>> to excise parts they don't think are useful enough or are too difficult to
>> implement. In that spirit, the 'simple Any<...>' construct is gone and Any
>> usage is fully general.
>>
>> - I moved discussion of typealiases back into the main protocol, like you
>> said, because typealiases using existentials are *not* actually generic and
>> can be done today.
>>
>> - I added some stuff about 'narrowing' existentials at point of use using
>> as?. This isn't part of 'opening existentials' and should fit in this
>> proposal nicely.
>>
>> - I want a type expert to look at the 'usage' section, but I'm reasonably
>> sure there's not much more flexibility we can give the user. Parameter
>> associated types can't be treated as covariant (they are almost always
>> invariant or contravariant IIRC) and therefore they should only be
>> accessible if fully bound. Return types can be treated as covariant; some
>> languages do and some don't. (Swift falls into the second bucket.) I would
>> love to be wrong, though.
>>
>> Austin
>>
>>> On May 18, 2016, at 8:45 AM, Matthew Johnson <[email protected]
>>> <mailto:[email protected]>> wrote:
>>>
>>>
>>>
>>> Sent from my iPad
>>>
>>> On May 18, 2016, at 2:35 AM, Austin Zheng <[email protected]
>>> <mailto:[email protected]>> wrote:
>>>
>>>> I've put together a considerably more detailed draft proposal, taking into
>>>> account as much of Matthew's feedback as I could. You can find it below:
>>>>
>>>> https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md
>>>>
>>>> <https://github.com/austinzheng/swift-evolution/blob/az-existentials/proposals/XXXX-enhanced-existentials.md>
>>>>
>>>> Since there is no chance this will come up for review anytime soon, I
>>>> expect to make significant revisions to it over the next month or so. Any
>>>> feedback would be greatly appreciated.
>>>
>>> Thank you for working on this! Great progress.
>>>
>>> Minor nit, but I think the proper word is constraint rather than
>>> requirement here:
>>>
>>> "Within the angle brackets < and > are zero or more requirements.
>>> Requirements are separated by commas."
>>>
>>> Another tweak:
>>>
>>> "P can be used in lieu of Any<P>, where P is a protocol with or without
>>> associated type or self requirements."
>>>
>>> This proposal is introducing generalized existentials. P and Any<P> should
>>> be interchangeable for any protocol regardless of requirements of the
>>> protocol. Existentials of protocols with self or associated type
>>> requirements that do not include constraints will just expose limited
>>> direct functionality. It would still be possible to attempt cast them to
>>> concrete types to recover more functionality. In the future (after a
>>> follow on proposal) it will also be possible to open the existential.
>>>
>>> Thorsten pointed out that there should only be one where clause for the
>>> whole existential. This follows the structure of generic type and function
>>> constraints. It may also be worth removing the 'as' alias from this
>>> proposal. This could be introduced as a stand alone proposal where it
>>> would apply to any context with generic constraints.
>>>
>>> Another item:
>>> // NOT ALLOWED let a : Any<Any<ProtocolA, ProtocolB>>
>>>
>>> Why is this not allowed? It is pointless, but should be allowed and
>>> considered identical to the flattened syntax.
>>>
>>> On dynamic casting, I don't believe it should be restricted in the way you
>>> have defined here. Casting *to* an existential doesn't have anything to do
>>> with opening an existential. We should allow casting to any existential
>>> type.
>>>
>>> On a similar note, I completely disagree with the limitation you specify
>>> for use of Any in generic constraints precisely because of your
>>> counterargument. In the discussion about moving the where clause it has
>>> been noted that sometime it is necessary to apply a lot of constraints to
>>> get the necessary effect. A mechanism for factoring constraints is highly
>>> desirable and will greatly improve the readability of generic code.
>>> Typealiases bound to Any can provide such a mechanism. Let's not
>>> artificially restrict the use of it.
>>>
>>> The section regarding members of a partly constrained existential needs to
>>> be more fleshed out. We can't simply punt it to a future proposal.
>>> However, I do think it is a good idea to wait until the core team has time
>>> to participate in the discussion.
>>>
>>> The section about defining typealias also should not be left to the future.
>>> It is possible to define typealias with protocol<> today and to use that
>>> alias in a generic constraint. Removing that capability would be a
>>> regression. In fact, it's utility will increase significantly with this
>>> proposal.
>>>
>>> In general, I don't think we need the distinction between simple and full
>>> Any. The whole idea of this proposal IMO should be fully generalizing
>>> existentials. If restrictions are necessary they should be due to
>>> (hopefully temporary) implementation considerations.
>>>
>>>>
>>>> Austin
>>>>
>>>> On Tue, May 17, 2016 at 9:52 PM, Austin Zheng <[email protected]
>>>> <mailto:[email protected]>> wrote:
>>>>
>>>>
>>>> On Tue, May 17, 2016 at 1:25 PM, Matthew Johnson <[email protected]
>>>> <mailto:[email protected]>> wrote:
>>>>>
>>>>>
>>>>>>
>>>>>> Within the angle brackets are zero or more 'clauses'. Clauses are
>>>>>> separated by semicolons. (This is so commas can be used in where
>>>>>> constraints, below. Better ideas are welcome. Maybe it's not necessary;
>>>>>> we can use commas exclusively.)
>>>>>
>>>>> I’m not a fan of the semicolon idea. I don’t see any reason for this.
>>>>> The `where` keyword separates the protocol list from the constraints just
>>>>> fine. The list on either side should be able to use commas with no
>>>>> problem (or line breaks if that proposal goes through).
>>>>>
>>>>>
>>>>> I'm leaning towards getting rid of the commas, but would like to write
>>>>> out a few 'dummy' examples to see if there are any readability issues
>>>>> that arise.
>>>>
>>>> Replaced with what? Whitespace separation? I suppose that might work for
>>>> the protocol list but it feels inconsistent with the rest of Swift.
>>>> Commas plus (hopefully) the alternative of newline seem like the right
>>>> direction to me.
>>>>
>>>> Sorry, I completely misspoke (mistyped?). I meant I want to get rid of the
>>>> semicolons and use commas. I've come to the conclusion that there are no
>>>> readability issues, protocol<> already uses commas, and semicolons used in
>>>> this manner don't have a precedent anywhere else in the language.
>>>>
>>>>
>>>>>>
>>>>>> There are five different possible clauses:
>>>>>>
>>>>>> 'class'. Must be the first clause, if present. Places a constraint on
>>>>>> the existential to be any class type. (Implies: Only one can exist.
>>>>>> Mutually exclusive with class name clause.)
>>>>>>
>>>>>> (In the future a follow-up proposal should add in 'struct' or 'value' as
>>>>>> a counterpart.)
>>>>>
>>>>> If we’re going to allow `struct` we should also allow `enum`. `value`
>>>>> would allow either of those.
>>>>>
>>>>>
>>>>> Of course. A future proposal can allow list members to discuss the exact
>>>>> details as to how struct, value, or enum specifiers should work.
>>>>
>>>> Yep, agree. Just mentioning that if we’re going to reference it we should
>>>> not leave obvious holes in what would be considered. :)
>>>>
>>>> Absolutely.
>>>>
>>>>
>>>>>>
>>>>>> Class name. Must be the first clause, if present. (Implies: Only one can
>>>>>> exist. Mutually exclusive with 'class'.) Places a constraint on the
>>>>>> existential (not really an existential anymore) to be an instance of the
>>>>>> class, or one of its subclasses.
>>>>> It is still be an existential if it includes protocol requirements that
>>>>> the class does not fulfill. For example, you might have Any<UIView,
>>>>> SomeProtocol> where UIView does not conform to SomeProtocol, but various
>>>>> subclasses do.
>>>>>
>>>>>
>>>>> Fair enough. (I don't think the way things work would be affected.)
>>>>>
>>>>> Your proposal doesn’t discuss composing Any in the way that Adrian’s did
>>>>> like this:
>>>>>
>>>>> typealias Foo = Any<SomeClass, SomeProtocol, OtherProtocol>
>>>>> Any<AnotherProtocol, Foo>
>>>>>
>>>>> I didn't think it needed to be discussed. An Any<...> existential type is
>>>>> a type 'expression' just like any other, and should be allowed to
>>>>> participate in other Any<...>s.
>>>>>
>>>>>
>>>>> I like the idea of composition as it allows us to factor out constraints.
>>>>> If we are going to do that we should allow a class to be specified in
>>>>> the composition as long is it is a subclass of all class requirements of
>>>>> Any types it composes. For example, this should be allowed:
>>>>>
>>>>> typealias Bar = Any<SubclassOfSomeClass, Foo, AnotherProtocol>
>>>>>
>>>>> This is still one class requirement for Bar, it just refines the class
>>>>> requirement of Foo to be SubclassOfSomeClass rather than just SomeClass.
>>>>>
>>>>> This is a good point. There should be clarification as to how special
>>>>> cases of Any<...> used in another Any<...> behave. For example, like you
>>>>> said Any<MyClass, Any<SomeSubclassOfMyClass, Protocol>> should be valid.
>>>>> This will go into any proposal that emerges from the discussion.
>>>>
>>>> Yes, this is why we need to discuss Any composition. There are also cases
>>>> of incompatible associated type constraints which need to be rejected
>>>> (such as composing two Any’s where one has Element == String and another
>>>> has Element == Int).
>>>>
>>>>>
>>>>>
>>>>>> Example: Any<UIViewController; UITableViewDataSource;
>>>>>> UITableViewDelegate>
>>>>>> "Any UIViewController or subclass which also satisfies the table view
>>>>>> data source and delegate protocols"
>>>>>> Dynamic protocol. This is entirely composed of the name of a protocol
>>>>>> which has no associated types or Self requirement.
>>>>>> Example: Any<CustomStringConvertible; BooleanType>
>>>>>> "Any type which conforms to both the CustomStringConvertible and
>>>>>> BooleanType protocols"
>>>>>>
>>>>>> I'm going to use 'static protocol' to refer to a protocol with
>>>>>> associated types or self requirements. Feel free to propose a more sound
>>>>>> name.
>>>>>>
>>>>>> Self-contained static protocol, simple. This is composed of the name of
>>>>>> a static protocol, optionally followed by a 'where' clause in which the
>>>>>> associated types can be constrained (with any of the three basic
>>>>>> conformance types: subclassing, protocol conformance, or type equality).
>>>>>> Associated types are referred to with a leading dot.
>>>>> Please do not introduce terms “dynamic protocol” and “static protocol”.
>>>>> We want to support existentials of protocols that have self or associated
>>>>> type requirements. The dynamic vs static distinction is a limitation of
>>>>> the current implementation of Swift and doesn’t make sense for the long
>>>>> term vision.
>>>>>
>>>>> I'm not trying to introduce new terms, these are just placeholders. At
>>>>> the same time "protocols with self or associated type requirements" is
>>>>> cumbersome to work with and it would be nice for someone to come up with
>>>>> a descriptive term of art for referring to them.
>>>>
>>>> I agree that a better term would be useful. In the meantime, I would
>>>> prefer something like “trivial” and “nontrivial” protocols.
>>>>
>>>> I've decided to just use the full name until the community comes up with
>>>> better names. Clarity is preferable to brevity in this case.
>>>>
>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> Example: Any<Collection where .Generator.Element : NSObject,
>>>>>> .Generator.Element : SomeProtocol>
>>>>>> "Any type that is a Collection, whose elements are NSObjects or their
>>>>>> subclasses conforming to SomeProtocol.”
>>>>>
>>>>> Swift does not allow disjunction of requirements. Only conjunctions are
>>>>> supported. That means the correct reading is:
>>>>>
>>>>> "Any type that is a Collection, whose elements are NSObjects and their
>>>>> subclasses conforming to SomeProtocol.”
>>>>>
>>>>>
>>>>> Yes, that is what I meant. "whose elements are (NSObjects or their
>>>>> subclasses) conforming to SomeProtocol”.
>>>>
>>>> Ok, good. Wasn’t quite clear to me.
>>>>
>>>> Yes, the verbiage will need to be clearer in the future. That sentence
>>>> could be ambiguously parsed.
>>>>
>>>>
>>>>>>
>>>>>> Bound static protocol. This is the same as a self-contained static
>>>>>> protocol, but with a leading "<name> as " which binds the protocol to a
>>>>>> generic typealias. The name can be then be used in subsequent clauses to
>>>>>> build constraints.
>>>>>>
>>>>>> Example: Any<T as Collection; IntegerLiteralConvertible where
>>>>>> .IntegerLiteralType == T.Element>.
>>>>>> "Any type that is a Collection, and also can be built from an integer
>>>>>> literal, in which the collection elements are the same type as the type
>>>>>> of the integer used for the integer literal conformance.”
>>>>>
>>>>> I’m not sure about this, but if we’re going to do it it should be the
>>>>> other way around: `Collection as T` with the alias after the name of the
>>>>> protocol.
>>>>>
>>>>>
>>>>> I like this, it flows better. "Protocol as T where Protocol.Foo == Int,
>>>>> Protocol.Bar : Baz”.
>>>>
>>>> Why did you introduce an alias here and then not use it? Did you mean
>>>> "Protocol as T where T.Foo == Int, T.Bar : Baz"
>>>>
>>>> Another result of rushing to compose an email. Sorry!
>>>>
>>>>
>>>>>
>>>>> You are also using “dot shorthand” here to refer to an associated type of
>>>>> IntegerLiteralConvertible. I think “dot shorthand” should be limited to
>>>>> cases where there is only one protocol that is getting constrained. In
>>>>> other cases, we need to be clear about which protocol we are referring to.
>>>>>
>>>>> I borrowed dot shorthand from the generics manifesto. But you are right,
>>>>> it should only be allowed if there is one protocol with associated types
>>>>> or self requirements clause in the Any<...> construction.
>>>>
>>>> I would actually go further and limit it to one protocol period, and
>>>> possibly even to one protocol and no type names (as types can have nested
>>>> types and typealiases). When we allow shorthand it should be immediately
>>>> unambiguous what the shorthand references with no need to look at type or
>>>> protocol declarations.
>>>>
>>>> It might be desirable to propose the proposal with no allowance for
>>>> shorthand, and have the dot shorthand be a smaller follow-up proposal.
>>>>
>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> There will be rules to prevent recursive nesting. For example, if
>>>>>> generic typealiases are allowed, they cannot refer to each other in a
>>>>>> circular manner (like how structs can't contain themeselves, and you
>>>>>> can't create a cyclic graph of enums containing themselves).
>>>>>>
>>>>>> How an existential can be used depends on what guarantees are provided
>>>>>> by the clauses. For example, 'Any<Equatable>' can't be used for much; if
>>>>>> there were any methods on Equatable that did not use the associated
>>>>>> types at all you'd be able to call them, but that's about it. However,
>>>>>> 'Any<Equatable where .Self == String>' would allow for == to be called
>>>>>> on instances. (This is a stupid example, since Any<Equatable where .Self
>>>>>> == String> is equivalent to 'String', but there are almost certainly
>>>>>> useful examples one could come up with.)
>>>>>>
>>>>>> In order of increasing 'power':
>>>>>> Don't constrain any associated types. You can pass around
>>>>>> Any<Equatable>s, but that's about it.
>>>>>> Constrain associated types to conform to protocols.
>>>>>> Fully constrain associated types.
>>>>>
>>>>> I think we need to spell out pretty clearly what members we expect to be
>>>>> available or not available. This section probably needs the most design
>>>>> and elaboration.
>>>>>
>>>>> For example, we probably can’t access a member who uses an associated
>>>>> type as an input unless it is constrained to a specific type. On the
>>>>> other hand output types probably don’t need to limit access to a member.
>>>>> However, if the output type is Self or an associated type the visible
>>>>> signature would have an output type which has the relevant constraints of
>>>>> the existential applied, but no more. In some cases this means the
>>>>> output type would simply be Any.
>>>>>
>>>>> Absolutely. This is vaguely what I had in mind but I wanted to get
>>>>> something down first. Thanks for thinking through some of the
>>>>> implications :).
>>>>
>>>> That’s what I thought. Just wanted to start the process of elaborating
>>>> expectations.
>>>>
>>>>>
>>>>>
>>>>> Where this really gets tricky is for compound types like functions,
>>>>> generic types, etc. Working out the details in these cases is pretty
>>>>> complex. I will defer to Doug on whether it is best to just defer those
>>>>> cases to the future, leave them up to the implementer, or try to work out
>>>>> all of the relevant details in the proposal (in which case we probably
>>>>> need a type system expert to help!).
>>>>>
>>>>> Yes, exactly! For example, can Any<...> existentials involving protocols
>>>>> with associated types or self requirements be used within generic
>>>>> function or type definitions? Maybe there's an argument that existential
>>>>> types of this nature are redundant if you have access to generics (e.g.
>>>>> defining a property on a generic type that is a Collection containing
>>>>> Ints; you should be able to do that today). On the other hand, maybe
>>>>> there are use cases I haven't thought of…
>>>>
>>>> I see no reason they shouldn’t be. They are not redundant at all. For
>>>> example, you may want to store instances in a heterogeneous collection.
>>>> You need existentials to do that.
>>>>
>>>> A simple example of what I was referring to there is something like this:
>>>>
>>>> protocol P {
>>>> associatedtype Foo
>>>>
>>>> func bar(callback: (Foo) -> ())
>>>> }
>>>>
>>>> In other words, types in the signature of a protocol member are complex
>>>> types that reference Self or associated types. I think you really need a
>>>> formal understanding of the type system to understand how to expose these
>>>> members through a constrained existential. We can probably understand the
>>>> expected behavior in some of the simpler cases on a case by case basis,
>>>> but that approach doesn’t scale at all and is arbitrary. If they’re going
>>>> to be supported an expert is going to need to be involved in the design.
>>>>
>>>> Yes. I have some ideas regarding this topic.
>>>>
>>>>
>>>>>
>>>>>
>>>>> One area you didn’t touch on is “opening” the existential? Is that out
>>>>> of scope for this proposal? That would be fine with me as this proposal
>>>>> is already taking on a lot. But if so, you should mention something
>>>>> about future directions as it is pretty closely related to this proposal.
>>>>>
>>>>> Yes, existential opening is explicitly separate from this (although I
>>>>> wanted to mention it in the section where I talk about how Any<Equatable>
>>>>> is not very useful). But you are absolutely right, this proposal should
>>>>> discuss how it wants to interact with possible future directions.
>>>>>
>>>>>
>>>>> Another area you didn’t touch on is whether Any constructs (and
>>>>> typealiases referring to them) should be usable as generic constraints.
>>>>> I would expect this to be possible but I think we need to spell it out.
>>>>>
>>>>> I'm hoping for community input. This is a tricky subject, and at some
>>>>> point we'll bump into implementation limitations.
>>>>
>>>> I don’t think it’s too tricky. You can just unpack the constraints of the
>>>> Any into the list of generic constraints. Maybe I’m missing something,
>>>> but I don’t think so.
>>>>
>>>>>
>>>>>
>>>>> -Matthew
>>>>
>>>>
>>>>
>>
>> _______________________________________________
>> swift-evolution mailing list
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
> _______________________________________________
> swift-evolution mailing list
> [email protected] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-evolution
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution