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


(Adrian Zubarev) #1

As Thorstan forgot to resend his message to the list, here it is (read below). It should make things about `any<>` more clear.

···

———

func f(obj: class<SomeClass,SomeProtocl>) {..}
if obj is class<SomeClass,SomeProtocl> {..}
obj2 = obj as! class<SomeClass,SomeProtocol>

and yes, probably struct<SomeStruct,SomeProtocol>
Why would you want to add all of these different formats where only one could serve them all. This is redundant in my opinion.

`struct<>` and `enum<>` would have same rules, only the first element would be a different value-type. I might consider this as an alternative.

Correct me if I’m wrong with the redundancy.

———

The & type operator would produce a “flattened" all<> with its operands. It could be overloaded to accept either a concrete type or a protocol on the lhs and would produce `type` for an lhs that is a type and `all` when lhs is a protocol. "Type operators” would be evaluated during compile time and would produce a type that is used where the expression was present in the code. This is a long-term idea, not something that needs to be considered right now. It would be way out of scope for Swift 3.
Which part of your statement is exactly out of scope for Swift 3, “Type operators“ I guess?

So is it a good idea to add `&` operator for "flattened“ `all<>` whereas “Type operators“ would be a better way to go (for Swift 4 maybe)? As far as I understand the idea behind `&` operator I’m not sure how it could be overloaded, because I thought it would be baked right into the language.

If I mixed something up here please feel free to correct me.

———

Would you mind to give me some feedback for the rules I've summarized.

———

The overall feedback seems to be positive so for and my fingers are crossed for this feature to be accepted.

--
Adrian Zubarev
Sent with Airmail

Am 13. Mai 2016 bei 08:16:51, Thorsten Seitz (tseitz42@icloud.com) schrieb:

Am 12. Mai 2016 um 22:08 schrieb Adrian Zubarev via swift-evolution <swift-evolution@swift.org>:

I don’t get the part how `all<>` should allow `any<>`. Could you explain that a little bit in detail (I’m not familiar with Ceylon)?

`all<>` and `any<>` form a pair of complementary type operators, one creating the intersection of the given types (your proposal) and the other creating the union of the given types. As Ceylon has demonstrated that both are really useful I'd like to have both in Swift and therefore would prefer that both should be named such that this duality is visible. Having `type<>` and `any<>` would certainly be possible technically but the naming would not be good.

From my point of view `any<>` is something different that I pitched here. `any<>` could be proposed in its own thread, because it is way different than `type<>`. Or can we refine the rules of `type<>` to get to `any<>`?

You are right, `any<>` is something different and could be proposed in its own thread. I just wanted to extend the context for finding a good name for `type<>`.

Here is a little example where `any<>` gets strange:

func foo(value: any<String, Int>) -> any<String, Int> {

// how would one use value here?
// what about its properties
// what will foo return and how to use the result

}

Ceylon uses flow typing for that (if (is String value) { /* value has type String here */ }).
In Swift the equivalent would be `if let string = value as? String { ... }`:

func foo(value: any<Strint, Int>) -> any<String, Int> {
if let string = value as? String {
return string.characters.count
}
else if let int= value as? Int {
return String(int)
}
}

A more sensical example using a type union would be the union of two sets:

func union<T, U>(a: Set<T>, b: Set<U>) -> Set<any<T, U>> { ... }

And for type intersection the intersection of two sets:

func intersection<T, U>(a: Set<T>, b: Set<U>) -> Set<all<T, U>> { ... }

(Ceylon's type operators just read better there...)

Another example for type unions:
Ceylon like Swift makes heavy use of optionals but where Swift has a generic wrapper Optional<T> Ceylon just makes use of type unions: in Ceylon T? is syntactic sugar for the type union T | Null where Null is the type having the singleton value null.

FWIW Microsoft's Typescript gained union and intersection types about (I think) a year ago.

One benefit of `any<>` is the replacement of overloading, at least for the type part of the function.

Exactly.

`all<>` could be seen as an alternative name for `type<>`, but to me its not clear what `all<>` can do, whereas `type<>` is almost like `protocol<>`.

Right, `all<>` is just an alternative name for `type<>`. There is no change in functionality.

-Thorsten


(Ross O'Brien) #2

In reply to:

Why would you want to add all of these different formats where only one
could serve them all. This is redundant in my opinion.

`struct<>` and `enum<>` would have same rules, only the first element would
be a different value-type. I might consider this as an alternative.

Correct me if I’m wrong with the redundancy.

'enum<>' might be valid, unless their functions (e.g. for 'init(rawValue:
Int)' or 'allCases') are declared in explicit protocols which would
implicitly cover enums and which other types could declare conformance to.

'struct<>' does seem redundant unless it becomes subtypeable. If you want a
struct which conforms to several protocols, protocol<> already covers this.
I know there's a discussion at the moment regarding the equivalent of an
'AnyObject' for value types, which might apply to this discussion, but I'm
not sure how.

A class in general would also a protocol<AnyObject, ...>. The benefit of
'type<>' is in its ability to extend the behaviours of several subclasses
at once, e.g. type<UIViewController, UIScrollViewDelegate> covers all view
controllers with scroll views, not just UITableViewController,
UICollectionViewController, etc..


(Adrian Zubarev) #3

'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&lt;StructA, SomeProtocol&gt; \{ /\* do something with a \*/ \}

else if let b = value as? struct&lt;StructB, SomeProtocol&gt; \{ /\* 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.

Btw, if we'd have separate class<> and struct<> - we'd be able to have method to separate reference type from value type.
We can write now : print(c is protocol<>)
and we'd can:
print(c is class<>)
print(c is struct<>)

True, I didn’t thought about that effect at the first glance, thank you for the hint. I will add this to the draft proposal tomorrow.

···

--
Adrian Zubarev
Sent with Airmail


(Vladimir) #4

Actually, I fully support your idea and strongly +1 for `type<>` keyword. I don't believe it will confuse anyone as protocol<> does not confuse currently.

But as I can see, the community(or core team) is strongly against of using `type` keyword.
So, we have situation : protocol<> and .. all<> ? Will all<> include protocols also? Probably I'd support to remove protocol<> and introduce just all<> for all :slight_smile: But if we have protocol<> and can't have type<> - I asked why we can't for clarity and consistency have class<> struct<>

···

On 13.05.2016 19:38, Adrian Zubarev via swift-evolution wrote:

Why would you want to add all of these different formats where only one
could serve them all. This is redundant in my opinion.

`struct<>` and `enum<>` would have same rules, only the first element would
be a different value-type. I might consider this as an alternative.


(Adrian Zubarev) #5

'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&lt;StructA, SomeProtocol&gt; \{ /\* do something with a \*/ \}

else if let b = value as? struct&lt;StructB, SomeProtocol&gt; \{ /\* 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


(Vladimir) #6

Btw, if we'd have separate class<> and struct<> - we'd be able to have method to separate reference type from value type.

We can write now : print(c is protocol<>)

and we'd can:

print(c is class<>)
print(c is struct<>)

Just thoughts..

···

On 13.05.2016 20:04, Vladimir.S wrote:

On 13.05.2016 19:38, Adrian Zubarev via swift-evolution wrote:

Why would you want to add all of these different formats where only one
could serve them all. This is redundant in my opinion.

`struct<>` and `enum<>` would have same rules, only the first element would
be a different value-type. I might consider this as an alternative.

Actually, I fully support your idea and strongly +1 for `type<>` keyword. I
don't believe it will confuse anyone as protocol<> does not confuse currently.

But as I can see, the community(or core team) is strongly against of using
`type` keyword.
So, we have situation : protocol<> and .. all<> ? Will all<> include
protocols also? Probably I'd support to remove protocol<> and introduce
just all<> for all :slight_smile: But if we have protocol<> and can't have type<> - I
asked why we can't for clarity and consistency have class<> struct<>


(Vladimir) #7

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()
   }
}

as we can(as example) expect that in 3rd party code someone will do:

extension StructA: ExtraProtocol1 {
   func bar() {}
}

extension StructB: ExtraProtocol2 {
   func 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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Matthew Johnson) #8

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.

···

On May 13, 2016, at 2:14 PM, Adrian Zubarev via swift-evolution <swift-evolution@swift.org> wrote:

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@gmail.com <mailto:svabox@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@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

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


(Austin Zheng) #9

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@swift.org> wrote:

On May 13, 2016, at 2:14 PM, Adrian Zubarev via swift-evolution < > swift-evolution@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@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@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>

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

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


(Adrian Zubarev) #10

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?), 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?

struct A<T> {

var value: struct&lt;T&gt; // 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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Vladimir) #11

You asked for any example, I give it to you :wink:
(as I said, it is syntactical, just to show that such struct<> can be used to test some struct for conforming to protocol, that was not conformed at writing time)
Probably we can invent useful examples for this struct<> - but I don't believe it will be introduced in Swift :wink:

···

On 13.05.2016 22:14, Adrian Zubarev via swift-evolution wrote:

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?


(Adrian Zubarev) #12

I don't think the struct functionality makes much sense. There are two ways you can use the struct<...> construct:
So does `enum<>` makes not much sense, I guess? I can’t think of any use-case were `enum<>` could do something what `struct<>` can’t.

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.
Was this clarified somewhere, I mean that value types won’t have subtypes ever? This would be nice to know.

We already can write the same (ugly) scenario with protocols:
protocol A {}
extension A {
func foo() {
print("foooo")
}
}

// this is the refined design that we all use
func boo(value: A) {
value.foo()
}

// this might be the original design
func zoo(value: protocol<A>) {
boo(value)
}

struct B: A {}
let value = B()

zoo(value)
boo(value)
The main idea behind `struct<>` etc. is not to make the language complicated, but to add symmetry to the type system, which should already have been there from the beginning. Compared to the little example I just wrote, we all already use the refined format of the (not present) base `struct<>`.

So if value types might have subtypes one day, this wouldn’t be hard to upgrade I suppose. Anyways I’ll move that part of the proposal to the future direction.

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<...>.
True, but I feel like there is a change incoming in that direction ([swift-evolution] Should we rename "class" when referring to protocol conformance?) and I don’t think the core team will decide to introduce `T: class`-like `struct` or `enum` constraint. :confused:

struct C<T: struct where T: SomeProtocol> {

var value: T?

func set\(value: T\) \{

    self\.value = value

\}

}

This would be nice to have. And yes this does look way better than:

struct C<struct<T, SomeProtocol>> {

\[…\]

}

But isn’t this again a refined usage of the base format (`struct<>` in this case)!?

One other example that comes to mind, where I can’t really tell if this would be possible to express with `struct<>`, can be defined outside of the generic scope just like `class<SomeBaseClass, SomeProtocol>` or `all<SomeBaseClass, SomeProtocol>`:

var structArray: [struct<Any, SomeProtocol>]

Would this work? This is an interesting case, where no values inside the struct can be reference-types!

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>).
Is there any reading you can point me to, so I can include or quote it into the proposal?

···

--
Adrian Zubarev
Sent with Airmail

Am 14. Mai 2016 bei 06:06:12, Austin Zheng (austinzheng@gmail.com ) schrieb:


(Vladimir) #13

FWIW, yes, protocols available for struct are known at compile-time, but could be unknown at the *moment of writing* the code.

What I mean:

Step 1. I write source code:

protocol A {}
protocol B {}
struct S:A {}

func f(a: A) {
   if a is struct<S,B> {...} // I expect that S could be conformed to B
}

Step 2. I give my code to someone, who can do somewhere in his project:

extension S:B{..}

···

On 14.05.2016 7:06, Austin Zheng via swift-evolution wrote:

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.


(Adrian Zubarev) #14

If anyone is interested, I started a draft proposal with detailed design here: https://github.com/DevAndArtist/swift-evolution/blob/master/proposals/nnnn-merging-types-with-protocols.md

I didn’t post it here, because it is a bit huge and could lose its markdown formats. `all<>` is always bold, because this is what we are interested in, but I provided all possible combinations if the other formats would exists (at least all combinations I could think of, anything else is derived from these).

`class<>` etc. can be seen as a future direction (I would say), otherwise this would easily become out of scope for Swift 3. (I will move `class<>` etc. from detailed design to future direction later.)

I’d love to hear your feedback and strong arguments for the motivation part I could include into this proposal.

···

--
Adrian Zubarev
Sent with Airmail

Am 13. Mai 2016 bei 23:16:20, Vladimir.S (svabox@gmail.com) schrieb:

You asked for any example, I give it to you :wink:
(as I said, it is syntactical, just to show that such struct<> can be used
to test some struct for conforming to protocol, that was not conformed at
writing time)
Probably we can invent useful examples for this struct<> - but I don't
believe it will be introduced in Swift :wink:

On 13.05.2016 22:14, Adrian Zubarev via swift-evolution wrote:

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?


(Adrian Zubarev) #15

I apologize for any possible flood (if there is any restriction in this mail list).

One other example that comes to mind, where I can’t really tell if this would be possible to express with `struct<>`, can be defined outside of the generic scope just like `class<SomeBaseClass, SomeProtocol>` or `all<SomeBaseClass, SomeProtocol>`:

var structArray: [struct<Any, SomeProtocol>]

Would this work? This is an interesting case, where no values inside the struct can be reference-types!
Actually I can answer this question by myself, because `Any` is just a typealias for `protocol<>` and does not violate any rule here.

This also adds a few more type combinations I missed out in my proposal:

e.g. `struct<Any>` is equivalent to `struct<protocol<>>`

This can allow us to use any struct without the need of generic scope! Isn’t it great or what?

Have you ever wanted to store any class references with conformance to a protocol without the generic system, with this you could do so `class<Any, SomeProtocol>`:

var classArray: [class<Any, SomeProtocol>]

Best Regards,

Adrian Zubarev


(Austin Zheng) #16

Yes, this is theoretically possible, but why is it useful? (I am genuinely
curious.)

If the intention is to allow B to be a user-defined extension point for T,
this goes back to the core team's arguments (in the thread about optional
protocol requirements) about why having checking for conformance to some
requirement at the use site is a suboptimal idea.

If the intention is to make the type system as expressive as possible, the
core team has already ruled out a number of features (user-defined variance
on generics, generic protocols) because they don't believe in their general
applicability.

Austin

···

On Sat, May 14, 2016 at 11:13 AM, Vladimir.S <svabox@gmail.com> wrote:

FWIW, yes, protocols available for struct are known at compile-time, but
could be unknown at the *moment of writing* the code.

What I mean:

Step 1. I write source code:

protocol A {}
protocol B {}
struct S:A {}

func f(a: A) {
  if a is struct<S,B> {...} // I expect that S could be conformed to B
}

Step 2. I give my code to someone, who can do somewhere in his project:

extension S:B{..}

On 14.05.2016 7:06, Austin Zheng via swift-evolution wrote:

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.


(Adrian Zubarev) #17

Thank you for pointing me to the right reading.

I just read both pages:
https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md
https://github.com/apple/swift/blob/master/docs/Generics.rst

I’ll have to rewrite my proposal a bit. Btw. is there any better name for Ceylon `Any<>`? Maybe `Either<>`?

`Any<T, U>` - "Any type that conforms to T and U“

Could someone explain to me what existentials suppose to be? I didn’t get that part from the article, where everything else made somehow sense to me. :slight_smile:

···

--
Adrian Zubarev
Sent with Airmail

Am 14. Mai 2016 bei 20:21:04, Austin Zheng via swift-evolution (swift-evolution@swift.org) schrieb:

Yes, this is theoretically possible, but why is it useful? (I am genuinely curious.)

If the intention is to allow B to be a user-defined extension point for T, this goes back to the core team's arguments (in the thread about optional protocol requirements) about why having checking for conformance to some requirement at the use site is a suboptimal idea.

If the intention is to make the type system as expressive as possible, the core team has already ruled out a number of features (user-defined variance on generics, generic protocols) because they don't believe in their general applicability.

Austin

On Sat, May 14, 2016 at 11:13 AM, Vladimir.S <svabox@gmail.com> wrote:
FWIW, yes, protocols available for struct are known at compile-time, but could be unknown at the *moment of writing* the code.

What I mean:

Step 1. I write source code:

protocol A {}
protocol B {}
struct S:A {}

func f(a: A) {
if a is struct<S,B> {...} // I expect that S could be conformed to B
}

Step 2. I give my code to someone, who can do somewhere in his project:

extension S:B{..}

On 14.05.2016 7:06, Austin Zheng via swift-evolution wrote:
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.

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


(Vladimir) #18

Yes, this is theoretically possible, but why is it useful? (I am genuinely
curious.)

I just showing that we *can* invent the situation when checking for struct<Struct,Protocol> have a sense. Not more, not less.
I'm not going to discuss if that can have any (or never can have at all) useful intention.

···

On 14.05.2016 21:20, Austin Zheng wrote:

If the intention is to allow B to be a user-defined extension point for T,
this goes back to the core team's arguments (in the thread about optional
protocol requirements) about why having checking for conformance to some
requirement at the use site is a suboptimal idea.

If the intention is to make the type system as expressive as possible, the
core team has already ruled out a number of features (user-defined variance
on generics, generic protocols) because they don't believe in their general
applicability.

Austin

On Sat, May 14, 2016 at 11:13 AM, Vladimir.S <svabox@gmail.com > <mailto:svabox@gmail.com>> wrote:

    FWIW, yes, protocols available for struct are known at compile-time,
    but could be unknown at the *moment of writing* the code.

    What I mean:

    Step 1. I write source code:

    protocol A {}
    protocol B {}
    struct S:A {}

    func f(a: A) {
      if a is struct<S,B> {...} // I expect that S could be conformed to B
    }

    Step 2. I give my code to someone, who can do somewhere in his project:

    extension S:B{..}

    On 14.05.2016 7:06, Austin Zheng via swift-evolution wrote:

        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.


(Austin Zheng) #19

That makes sense, thanks for pointing out a possibility I missed!

Austin

···

On Sat, May 14, 2016 at 11:34 AM, Vladimir.S <svabox@gmail.com> wrote:

On 14.05.2016 21:20, Austin Zheng wrote:

Yes, this is theoretically possible, but why is it useful? (I am genuinely
curious.)

I just showing that we *can* invent the situation when checking for
struct<Struct,Protocol> have a sense. Not more, not less.
I'm not going to discuss if that can have any (or never can have at all)
useful intention.

If the intention is to allow B to be a user-defined extension point for T,
this goes back to the core team's arguments (in the thread about optional
protocol requirements) about why having checking for conformance to some
requirement at the use site is a suboptimal idea.

If the intention is to make the type system as expressive as possible, the
core team has already ruled out a number of features (user-defined
variance
on generics, generic protocols) because they don't believe in their
general
applicability.

Austin

On Sat, May 14, 2016 at 11:13 AM, Vladimir.S <svabox@gmail.com >> <mailto:svabox@gmail.com>> wrote:

    FWIW, yes, protocols available for struct are known at compile-time,
    but could be unknown at the *moment of writing* the code.

    What I mean:

    Step 1. I write source code:

    protocol A {}
    protocol B {}
    struct S:A {}

    func f(a: A) {
      if a is struct<S,B> {...} // I expect that S could be conformed to B
    }

    Step 2. I give my code to someone, who can do somewhere in his
project:

    extension S:B{..}

    On 14.05.2016 7:06, Austin Zheng via swift-evolution wrote:

        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.


(Adrian Zubarev) #20

I’ve done some progress on the draft proposal. There are still a few things to fill, but now it should be clear what `all<>` will solve (empty cells in the table) and what types it might produce (equivalent refined type).
`protocol<>` could completely be replaced with `all<>`.

I have rewritten the examples for `all<>` to be more specific and moved `class<>` etc. to future directions with some examples what can be done with these.

Due the fact that Swift 3 will have generic typealias and possible `any<>`, `struct<>` and `enum<>` in the future, we could also build `value<>` which I showed at the button of the proposal.

Feel free to give me some feedback. :slight_smile:

···

--
Adrian Zubarev
Sent with Airmail