[swift-evolution] [Pitch] merge types and protocols back together with type<Type, Protocol, ...>

Austin Zheng austinzheng at gmail.com
Fri May 13 23:06:11 CDT 2016


This is certainly a detailed and well-considered proposal.

I don't think the struct functionality makes much sense. There are two ways
you can use the struct<...> construct:

1. struct<SomeConcreteStruct, Protocol1, Protocol2>. In this case the
struct<...> representation is unnecessary; the protocols that are available
to the user are known at compile-time, and structs can't have subtypes that
conform to additional protocols like classes can. There is an example
marked "func boo(value: struct<SomeStruct>) /* equivalent to */ func
boo(value: SomeStruct)"; my question is why having more than two ways to
express the same idea makes the language better, easier to use, etc.

2. struct<T, Protocol1, Protocol2>. In this case struct<...> is being used
as an add-on to the generics system to denote a 'must be value type'
constraint. However, I think a 'T : class'-like 'struct' constraint makes
more sense, both because it fits better with the existing 'class'
constraint and because it can be used anywhere the generic system allows a
type parameter to be constrained. A generic 'struct' constraint would give
the currently generics system as much expressive power as struct<...>.

Overall, rather than having this be a separate feature I think it should be
developed as part of the "Generalized Existentials" feature that is already
on the roadmap for Swift 3. The cases where adding class<...>, struct<...>,
etc can improve expressive power are covered by allowing variables to take
existential types with constraints. The one big feature that Generalized
Existentials should absorb from this proposal is allowing the
representation of a concrete class type with protocol constraints
(<MyClass, SomeProtocol, AnotherProtocol>).

Best,
Austin



On Fri, May 13, 2016 at 5:16 PM, Matthew Johnson via swift-evolution <
swift-evolution at swift.org> wrote:

>
> On May 13, 2016, at 2:14 PM, Adrian Zubarev via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> As we can(as example) expect that in 3rd party code someone will do:
>
> extension StructA: ExtraProtocol1 {
> func bar() {}
> }
>
> extension StructB: ExtraProtocol2 {
> func blort() {}
> }
>
>
> Can we really do that? I mean, I thought about that myself but I came to
> the conclusion that this scenario is like: I was to lazy to couple this
> structs to my library protocols, will you do that for me?
>
> Sure one could think that this protocols might be optional but the `f(p:
> MyProtocol)` function will cover this scenario.
>
> Another interesting side-effect `struct<>`, `class<>` and `enum<>` will
> allow us to do is to distinguish between value and reference types for
> generics. I tried this differentiation types with protocols like
> `AnyReference` and `AnyValue` in another topic before (Should we rename
> "class" when referring to protocol conformance?
> <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160502/016286.html>),
> but I kinda like this new approach.
>
> Here is what I mean in detail:
>
> protocol SomeProtocol /* we can’t constraint it to value types at the
> moment, only `class`es works */ {}
>
> func foo<T>(value: struct<T, SomeProtocol>) { /* do some work */ }
>
> This function is pretty neat. (1) You can force the library user to create
> a struct with conformance to `SomeProtocol`. (2) This approach will accept
> any struct which conforms to that protocol.
>
> As I said in the protocol comment above protocols can only be constrained
> to classes at the moment, and this might change in the future. If we also
> had some sort of things for generics so the function from above might have
> looked like this:
>
> func foo<T: struct where T: SomeProtocol>(value: T) {}
>
> But it seems that such a thing won’t ever happen to Swift.
>
> Basically `struct<>`, `class<>` and `enum<>` will just enable this for us.
> `all<>` would accept any type at its first element.
>
> func foo<T /* add more constraints here */ >(value: all<T, SomeProtocol>)
> { /* T could be a reference type or value type */ }
>
> That been said, `all<>` could replace `protocol<>` where it is composed
> from protocols. `all<>` can only be used as a generic constraints if the
> first element is a protocol or a reference type.
>
> @Matthew: isn’t this somehow a step towards (generic) `PureValue` types?
>
>
> No.  These say nothing about semantics.  PureValue is all about the
> semantics of a type and has nothing to do with what mechanism is used to
> implement the type.
>
>
> struct A<T> {
>
>     var value: struct<T> // if we drop the strict rule of at least one
> protocols
> }
>
> How does it sound to you?
>
> --
> Adrian Zubarev
> Sent with Airmail
>
> Am 13. Mai 2016 bei 20:34:59, Vladimir.S (svabox at gmail.com) schrieb:
>
> Hmm..
>
> What about such synthetic scenario:
>
> at the moment of writing our code we have:
>
> public protocol MyProtocol {
> func foo()
> }
>
> public struct StructA:MyProtocol {
> func foo()
> }
>
> public struct StructB:MyProtocol {
> func foo()
> }
>
> and have
>
> public protocol ExtraProtocol1 {
> func bar()
> }
>
> public protocol ExtraProtocol2 {
> func blort()
> }
>
> then we actually can have such code:
>
> func f(p: MyProtocol) {
> if let a = p as? struct<StructA, ExtraProtocol1> {
> a.foo()
> a.bar()
> }
> else
> if let b = p as? struct<StructB, ExtraProtocol2> {
> b.foo()
> b.blort()
> }
> }
>
>
>
>
> On 13.05.2016 20:50, Adrian Zubarev via swift-evolution wrote:
> >> 'struct<>' does seem redundant unless it becomes subtypeable. If
> >> you want a struct which conforms to several protocols, protocol<>
> >> already covers this.
> >>
> >> I think this is not correct. Lets check this example:
> >>
> >> func foo(value: SomeProtocol) {
> >>
> >> if let a = value as? struct<StructA, SomeProtocol> { /* do
> >> something with a */ }
> >>
> >> else if let b = value as? struct<StructB, SomeProtocol> { /* do
> >> something with b */ }
> >>
> >> }
> >>
> >> In this scenario you’ll be able to access properties and functions
> >> from `StructA` or `StructB` which might not be covered by
> >> `SomeProtocol`. Everything is merged nicely into one instance. But
> >> you are right it depends on the use-case.
> >>
> >>
> >> There is no need to include the protocol here. Just do this:
> >>
> >> if let a = value as? StructA { use a }
> >>
> > Whoops, I forgot that this will do the trick. I apologize for any
> confusion
> > here, you are totally right.
> >
> > That been said, do we really need `type<>` aka. `all<>` for value types?
> I
> > need to rethink this part of the proposal. Is there any use-case where we
>
> > would need this (any scenario for the future Swift version also counts)?
>
> >
> > If we had `all<>` in Swift already for extendable reference types and one
>
> > day structs would become subtypeable, this wouldn’t be a huge problem to
>
> > upgrade `all<>` for structs I guess.
> >
> > --
> > Adrian Zubarev
> > Sent with Airmail
> >
> >
> >
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-evolution
> >
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
> _______________________________________________
> 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/20160513/350b0db2/attachment.html>


More information about the swift-evolution mailing list