Swift Generic Subclass Type System Problem


(Cao Jiannan) #1

Hi all,
I want to discuss on optional generic sub-typing problem.

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?

like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super class of Optional<MyTableView>
Array<UITableView> should be the super class of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Also, I think, if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Thanks!

Jiannan, Cao


(Cao Jiannan) #2

Hi all,
I want to discuss on optional generic sub-typing problem.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao


(frogcjn) #3

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao


(Sune Foldager) #4

This, which is generic sub-typing variance, has already been discussed elsewhere on the list. One problem with what you suggest is that it’s not in general safe to assume that because A : B then X<A> : X<B>. Sometimes it’s the other way around, and often neither applies. For example, it’s not safe for arrays in general (although it might be for Swift arrays due to their value type semantics).

-Sune

···

On 16 Feb 2016, at 04:46, Cao Jiannan via swift-evolution <swift-evolution@swift.org> wrote:

Hi all,
I want to discuss on optional generic sub-typing problem.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

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


(Robert Widmann) #5

OK, so you have covariance covered, now what about contravariance? Surely a structure like this

struct Arrow<A, B> {
  let unArrow : A -> B
}

should be contravariant in its first argument and covariant in its second.

~Robert Widmann

2016/02/15 22:48、Cao Jiannan via swift-evolution <swift-evolution@swift.org> のメッセージ:

···

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

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


(Robert Widmann) #6

OK, one type parameter then

struct IO<A> { //... }

struct Observer<A> {
  let unObserver : A -> IO<()>
}

Point is, if you're going to introduce variance it has to go both ways. That means you'll need something more in the language than a typing rule that just works in this one small case.

~Robert Widmann

2016/02/16 0:00、Cao Jiannan <frogcjn@163.com> のメッセージ:

···

OK, let narrow the problem.

if B is subclass of A
Optional<B> is subclass of Optional<A>

Not allow multiple type template.

在 2016年2月16日,12:29,Developer <devteam.codafi@gmail.com> 写道:

OK, so you have covariance covered, now what about contravariance? Surely a structure like this

struct Arrow<A, B> {
  let unArrow : A -> B
}

should be contravariant in its first argument and covariant in its second.

~Robert Widmann

2016/02/15 22:48、Cao Jiannan via swift-evolution <swift-evolution@swift.org> のメッセージ:

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

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


(frogcjn) #7

I mean,

we only allow the class which not defined property like this kind of to has this feature.

or we only allow the system Optional type has this feature.

because Optional<B> is subclass of Optional<A>, this is very rational!

I think the problem is to implement optional with generic.
There are many other ways to implement optional feature, use generic maybe a bad idea.

···

在 2016年2月16日,13:20,Developer <devteam.codafi@gmail.com> 写道:

OK, one type parameter then

struct IO<A> { //... }

struct Observer<A> {
  let unObserver : A -> IO<()>
}

Point is, if you're going to introduce variance it has to go both ways. That means you'll need something more in the language than a typing rule that just works in this one small case.

~Robert Widmann

2016/02/16 0:00、Cao Jiannan <frogcjn@163.com <mailto:frogcjn@163.com>> のメッセージ:

OK, let narrow the problem.

if B is subclass of A
Optional<B> is subclass of Optional<A>

Not allow multiple type template.

在 2016年2月16日,12:29,Developer <devteam.codafi@gmail.com <mailto:devteam.codafi@gmail.com>> 写道:

OK, so you have covariance covered, now what about contravariance? Surely a structure like this

struct Arrow<A, B> {
  let unArrow : A -> B
}

should be contravariant in its first argument and covariant in its second.

~Robert Widmann

2016/02/15 22:48、Cao Jiannan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> のメッセージ:

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

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


(frogcjn) #8

I think the best way to balance is only allowing sub-typing working with safe classes.
For example, the optional generic type which has no constant definition like the one in your example.

By the way, B? should also be subclass with A!, do you agree? This are tons of reasons for this.
Currently, Swift using as to convert this two types (! and ?), but I think they are really the same type.
So I think the problem is not from generic. The problem is from how Swift deal with optional.

···

在 2016年2月16日,13:20,Developer <devteam.codafi@gmail.com> 写道:

OK, one type parameter then

struct IO<A> { //... }

struct Observer<A> {
  let unObserver : A -> IO<()>
}

Point is, if you're going to introduce variance it has to go both ways. That means you'll need something more in the language than a typing rule that just works in this one small case.

~Robert Widmann

2016/02/16 0:00、Cao Jiannan <frogcjn@163.com <mailto:frogcjn@163.com>> のメッセージ:

OK, let narrow the problem.

if B is subclass of A
Optional<B> is subclass of Optional<A>

Not allow multiple type template.

在 2016年2月16日,12:29,Developer <devteam.codafi@gmail.com <mailto:devteam.codafi@gmail.com>> 写道:

OK, so you have covariance covered, now what about contravariance? Surely a structure like this

struct Arrow<A, B> {
  let unArrow : A -> B
}

should be contravariant in its first argument and covariant in its second.

~Robert Widmann

2016/02/15 22:48、Cao Jiannan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> のメッセージ:

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

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


(frogcjn) #9

Hi all,

I think the best way to solve the either problem is to separate it from generic.
Optional and Either shouldn’t work the same way of generic type.
It’s just a represent of multiple type in one location.

Using an old friend, Union in C.
union {
  case firstType
  case secondType
}

This is the final solution for the sub typing problem of optional.

A == union(A,A)
union(A,B) == union(B,A)
B == union(B,B)

B is subtype of union(A,B)
A is subtype of union(A,B)

suppose
a is subclass of A
b is subclass of B, then
  union(a,B) is subtype of union(A,B)
  union(A,b) is subtype of union(A,B)
  union(a,b) is subtype of union(a,B)
  union(a,b) is subtype of union(A,b)

union can have as many case as possible. e.g., union(A,B,C,D,…)

So the Optional<UITableView> should be union(UITableView, None)
and Optional<MyTableVIew> should be union(MyTableView, None), which is subclass of union(UITableView, None)

This is a final rational solution. I think.

-Jiannan

···

下面是被转发的邮件:

发件人: Cao Jiannan via swift-evolution <swift-evolution@swift.org>
主题: [swift-evolution] Swift Generic Subtype Problem
日期: 2016年2月16日 GMT+8 11:48:18
收件人: swift-evolution@swift.org
回复-收件人: Cao Jiannan <frogcjn@163.com>

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

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


(Slava Pestov) #10

Hi Cao,

Note that Optional<T> already supports covariance as well as an “injection” from T to Optional<T>:

class A{

}

class B:A {

}

let b: B? = B() // conversion from B to B?
let a: A? = b // conversion from B? to A?

This is special-cased by the type checker, and not exposed for use by user-defined types such as Either in your example.

So the Optional<UITableView> should be union(UITableView, None)
and Optional<MyTableVIew> should be union(MyTableView, None), which is subclass of union(UITableView, None)

But you can still have generic type parameters here, if your function is generic over T and you write union(T, SomeOtherType). How would that work?

This is a final rational solution. I think.

-Jiannan

下面是被转发的邮件:

发件人: Cao Jiannan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>
主题: [swift-evolution] Swift Generic Subtype Problem
日期: 2016年2月16日 GMT+8 11:48:18
收件人: swift-evolution@swift.org <mailto:swift-evolution@swift.org>
回复-收件人: Cao Jiannan <frogcjn@163.com <mailto:frogcjn@163.com>>

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}

will trigger a compiler error.

The issue here is slightly different actually, but another interesting corner case that should be addressed. Protocol witness matching only looks at exact type equivalence, and not subtyping. So even without the ! it would hit the same issue:

protocol P {
  func f() -> A
}

class B : A {}

class C : P {
  func f() -> B {} // compile error
}

Once witness matching supports variance, your example will work.

But a better way would be to use an associated type:

protocol SequeHandlerType {
    associatedtype View : UITableView
    var tableView: View! { get }
}

Now a witness can return any subclass of UITableView, which will unify with the View associated type. Furthermore, other requirements can also reference View and the type checker will ensure any conformance has the same View in all positions where it appears.

Slava

···

On Feb 15, 2016, at 10:36 PM, Cao Jiannan via swift-evolution <swift-evolution@swift.org> wrote:

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(frogcjn) #11

Using Optional<Wrapped> generic leads to many problems, including this one.
Why subclass of UITableView cannot conform to this protocol? This is very weird.

protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

The complex design of using generic to implement optional feature, leads to many problems.
What is the type relation between A!, A?, A and B!, B?, B (if B is subtype of A)
This made a clear answer hard to answer.

In my opinion, A!, A?, A should be the same class, the only difference is the runtime checking,
not using the generic checking, because they are really the same type.

···

在 2016年2月16日,13:26,Cao Jiannan via swift-evolution <swift-evolution@swift.org> 写道:

I mean,

we only allow the class which not defined property like this kind of to has this feature.

or we only allow the system Optional type has this feature.

because Optional<B> is subclass of Optional<A>, this is very rational!

I think the problem is to implement optional with generic.
There are many other ways to implement optional feature, use generic maybe a bad idea.

在 2016年2月16日,13:20,Developer <devteam.codafi@gmail.com <mailto:devteam.codafi@gmail.com>> 写道:

OK, one type parameter then

struct IO<A> { //... }

struct Observer<A> {
  let unObserver : A -> IO<()>
}

Point is, if you're going to introduce variance it has to go both ways. That means you'll need something more in the language than a typing rule that just works in this one small case.

~Robert Widmann

2016/02/16 0:00、Cao Jiannan <frogcjn@163.com <mailto:frogcjn@163.com>> のメッセージ:

OK, let narrow the problem.

if B is subclass of A
Optional<B> is subclass of Optional<A>

Not allow multiple type template.

在 2016年2月16日,12:29,Developer <devteam.codafi@gmail.com <mailto:devteam.codafi@gmail.com>> 写道:

OK, so you have covariance covered, now what about contravariance? Surely a structure like this

struct Arrow<A, B> {
  let unArrow : A -> B
}

should be contravariant in its first argument and covariant in its second.

~Robert Widmann

2016/02/15 22:48、Cao Jiannan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> のメッセージ:

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(frogcjn) #12

Also:

union(A,B,C) is subtype of union(A,B,C,D,…)

···

在 2016年2月16日,14:36,Cao Jiannan <frogcjn@163.com> 写道:

Hi all,

I think the best way to solve the either problem is to separate it from generic.
Optional and Either shouldn’t work the same way of generic type.
It’s just a represent of multiple type in one location.

Using an old friend, Union in C.
union {
  case firstType
  case secondType
}

This is the final solution for the sub typing problem of optional.

A == union(A,A)
union(A,B) == union(B,A)
B == union(B,B)

B is subtype of union(A,B)
A is subtype of union(A,B)

suppose
a is subclass of A
b is subclass of B, then
  union(a,B) is subtype of union(A,B)
  union(A,b) is subtype of union(A,B)
  union(a,b) is subtype of union(a,B)
  union(a,b) is subtype of union(A,b)

union can have as many case as possible. e.g., union(A,B,C,D,…)

So the Optional<UITableView> should be union(UITableView, None)
and Optional<MyTableVIew> should be union(MyTableView, None), which is subclass of union(UITableView, None)

This is a final rational solution. I think.

-Jiannan

下面是被转发的邮件:

发件人: Cao Jiannan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>
主题: [swift-evolution] Swift Generic Subtype Problem
日期: 2016年2月16日 GMT+8 11:48:18
收件人: swift-evolution@swift.org <mailto:swift-evolution@swift.org>
回复-收件人: Cao Jiannan <frogcjn@163.com <mailto:frogcjn@163.com>>

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

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


(frogcjn) #13

Hi Slava:

class B : A {}

class C : P {
  func f() -> B {} // compile error
}

Once witness matching supports variance, your example will work.

But a better way would be to use an associated type:

protocol SequeHandlerType {
    associatedtype View : UITableView
    var tableView: View! { get }
}

Yes. This makes sense to me.
Associate type is a hard toy for me.
Sometimes I can figure out, sometimes I cannot. Sometimes I figure out but compiler say no.

The problem is not really with the optional sub typing relation, but looks like.
AssociatedType can solve the problem like this:

class A {}

class B : A {}

protocol HandlerType{
    var a: A { get }
}

class Handler: HandlerType{
    var b = B() //Compiler Error, though b is subtype of A
}

should be:

protocol HandlerType{
    typealias Target :A
    var a: Target { get }
}

class Handler: HandlerType {
    var a = B()
}

This is the solution to my question.
Thanks.

- Jiannan


(frogcjn) #14

Hi all,

I think the best way to solve the either problem is to separate it from generic.
Optional and Either shouldn’t work the same way of generic type.
It’s just a represent of multiple type in one location.

Using an old friend, Union in C.
union {
  case firstType
  case secondType
}

This is the final solution for the sub typing problem of optional.

It’s kind of same idea of TypeScipt 2, at 46:21 in this video.

https://channel9.msdn.com/Events/Build/2016/B881

···

A == union(A,A)
union(A,B) == union(B,A)
B == union(B,B)

B is subtype of union(A,B)
A is subtype of union(A,B)
union(A,B,C) is subtype of union(A,B,C,D,…)

suppose
a is subclass of A
b is subclass of B, then
  union(a,B) is subtype of union(A,B)
  union(A,b) is subtype of union(A,B)
  union(a,b) is subtype of union(a,B)
  union(a,b) is subtype of union(A,b)

union can have as many case as possible. e.g., union(A,B,C,D,…)

So the Optional<UITableView> should be union(UITableView, None)
and Optional<MyTableVIew> should be union(MyTableView, None), which is subclass of union(UITableView, None)

This is a final rational solution. I think.

-Jiannan


(Chris Lattner) #15

I think that the difference between “A" and "A?” is very clear and works well in Swift, but you’re right that the current definition of A! (aka ImplicitlyUnwrappedOptional<A>), and it’s relation to Optional is problematic in various ways. Joe Pamer is leading an effort to revisit our design for IUO and will be bringing some thoughts to this list when he’s ready.

-Chris

···

On Feb 15, 2016, at 9:35 PM, Cao Jiannan via swift-evolution <swift-evolution@swift.org> wrote:

What is the type relation between A!, A?, A and B!, B?, B (if B is subtype of A)
This made a clear answer hard to answer.

In my opinion, A!, A?, A should be the same class, the only difference is the runtime checking,
not using the generic checking, because they are really the same type.


(Andrew Bennett) #16

I think Union is a good solution as it's opt-in. The reason I'd want opt-in
is because the compiler could infer the data size at compile time and
possibly eliminate dynamic dispatch if the exact type is known. You'd
probably want a shorthand for the union though, for example:
    MyClass.typeUnion

The same goes for tuples. At the moment a tuple is the closest thing to a c
style struct. I think c structs are currently imported as tuples. If you
made it so (A,A) was interchangeable with (B,B) then they'd have to have
the same size, and maybe also store type information where they may not
otherwise.

···

On Tuesday, 16 February 2016, Cao Jiannan via swift-evolution < swift-evolution@swift.org> wrote:

Also:

union(A,B,C) is subtype of union(A,B,C,D,…)

在 2016年2月16日,14:36,Cao Jiannan <frogcjn@163.com> 写道:

Hi all,

I think the best way to solve the either problem is to separate it from
generic.
Optional and Either shouldn’t work the same way of generic type.
It’s just a represent of multiple type in one location.

Using an old friend, Union in C.
union {
case firstType
case secondType
}

This is the final solution for the sub typing problem of optional.

A == union(A,A)
union(A,B) == union(B,A)
B == union(B,B)

B is subtype of union(A,B)
A is subtype of union(A,B)

suppose
a is subclass of A
b is subclass of B, then
union(a,B) is subtype of union(A,B)
union(A,b) is subtype of union(A,B)
union(a,b) is subtype of union(a,B)
union(a,b) is subtype of union(A,b)

union can have as many case as possible. e.g., union(A,B,C,D,…)

So the Optional<UITableView> should be union(UITableView, None)
and Optional<MyTableVIew> should be union(MyTableView, None), which is
subclass of union(UITableView, None)

This is a final rational solution. I think.

-Jiannan

下面是被转发的邮件:

*发件人: *Cao Jiannan via swift-evolution <swift-evolution@swift.org>
*主题: **[swift-evolution] Swift Generic Subtype Problem*
*日期: *2016年2月16日 GMT+8 11:48:18
*收件人: *swift-evolution@swift.org
*回复-收件人: *Cao Jiannan <frogcjn@163.com>

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,

   1. protocol SegueHandlerType {
   2. var tableView: UITableView! { get }
   3. }

so the UITableViewController can conform to the protocal

   1. extension UITableViewController : SegueHandlerType {
   2. }

It's great!
What if the tableView is a subclass UITableView?
like:

   1. class MyTableView : UITableView {
   2. }
   3.
   4. MyTableViewController {
   5. @IBOutlet var tableView: MyTableView!
   6. }

Then

   1. extension MyTableViewController:SegueHandlerType {
   2.
   3. }

will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

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


(frogcjn) #17

2016-2-16 GMT+8 14:36:28
Hi all,

I think the best way to solve the either problem is to separate it from generic.
Optional and Either shouldn’t work the same way of generic type.
It’s just a represent of multiple type in one location.

Using an old friend, Union in C.
union {
  case firstType
  case secondType
}

This is the final solution for the sub typing problem of optional.

It’s kind of same idea of TypeScipt 2, at 46:21 in this video.

https://channel9.msdn.com/Events/Build/2016/B881

···

A == union(A,A)
union(A,B) == union(B,A)
B == union(B,B)

B is subtype of union(A,B)
A is subtype of union(A,B)
union(A,B,C) is subtype of union(A,B,C,D,…)

suppose
a is subclass of A
b is subclass of B, then
  union(a,B) is subtype of union(A,B)
  union(A,b) is subtype of union(A,B)
  union(a,b) is subtype of union(a,B)
  union(a,b) is subtype of union(A,b)

union can have as many case as possible. e.g., union(A,B,C,D,…)

So the Optional<UITableView> should be union(UITableView, None)
and Optional<MyTableVIew> should be union(MyTableView, None), which is subclass of union(UITableView, None)

This is a final rational solution. I think.

-Jiannan


(Slava Pestov) #18

The same goes for tuples. At the moment a tuple is the closest thing to a c style struct. I think c structs are currently imported as tuples.

Actually structs are imported as structs :slight_smile: (eg, import CoreGraphics - you get a CGPoint struct). We ask clang do the in-memory layout, but from a language perspective, they look mostly like normal Swift structs.

If you made it so (A,A) was interchangeable with (B,B) then they'd have to have the same size, and maybe also store type information where they may not otherwise.

That’s not a requirement for subtyping relations actually.

If A is a struct conforming to some protocol P, then values of type ‘A’ have a different runtime representation than values of type ‘P’, because the protocol value needs to attach the runtime type to the payload, whereas the struct will not. However, we still do an implicit conversion allowing As to be passed as Ps, we just generate the right code at the point where the conversion takes place.

Another example is when you have a function () -> A, the conversion to () -> P requires actually generating a thunk to wrap the original function value.

Subtyping in Swift is different from a pointer cast in C — its semantically producing a new value, so any representational change issues are orthogonal to the language itself. They leak out in the cases that are not implemented (we don’t do tuple conversions currently, and didn’t do function conversions until 2.1) but those will get plugged over time.

Slava

···

On Feb 15, 2016, at 11:46 PM, Andrew Bennett via swift-evolution <swift-evolution@swift.org> wrote:

On Tuesday, 16 February 2016, Cao Jiannan via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Also:

union(A,B,C) is subtype of union(A,B,C,D,…)

在 2016年2月16日,14:36,Cao Jiannan <frogcjn@163.com <>> 写道:

Hi all,

I think the best way to solve the either problem is to separate it from generic.
Optional and Either shouldn’t work the same way of generic type.
It’s just a represent of multiple type in one location.

Using an old friend, Union in C.
union {
  case firstType
  case secondType
}

This is the final solution for the sub typing problem of optional.

A == union(A,A)
union(A,B) == union(B,A)
B == union(B,B)

B is subtype of union(A,B)
A is subtype of union(A,B)

suppose
a is subclass of A
b is subclass of B, then
  union(a,B) is subtype of union(A,B)
  union(A,b) is subtype of union(A,B)
  union(a,b) is subtype of union(a,B)
  union(a,b) is subtype of union(A,b)

union can have as many case as possible. e.g., union(A,B,C,D,…)

So the Optional<UITableView> should be union(UITableView, None)
and Optional<MyTableVIew> should be union(MyTableView, None), which is subclass of union(UITableView, None)

This is a final rational solution. I think.

-Jiannan

下面是被转发的邮件:

发件人: Cao Jiannan via swift-evolution <swift-evolution@swift.org <>>
主题: [swift-evolution] Swift Generic Subtype Problem
日期: 2016年2月16日 GMT+8 11:48:18
收件人: swift-evolution@swift.org <>
回复-收件人: Cao Jiannan <frogcjn@163.com <>>

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,
protocol SegueHandlerType {
    var tableView: UITableView! { get }
}

so the UITableViewController can conform to the protocal
extension UITableViewController : SegueHandlerType {
}

It's great!
What if the tableView is a subclass UITableView?
like:
class MyTableView : UITableView {
}

MyTableViewController {
      @IBOutlet var tableView: MyTableView!
}

Then
extension MyTableViewController:SegueHandlerType {
  
}
will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

_______________________________________________
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


(Andrew Bennett) #19

Thanks for the detailed response, very interesting and its helped improve
my mental model. I think I may have misinterpreted the extent of the
proposal. Good point with CoreGraphics, I was the memory layout rather than
the public interface that I was thinking of, but perhaps my memory is out
of date :slight_smile:

I think the thing I was remembering is this sort of thing:

public struct _opaque_pthread_t {

    public var __sig: Int

    public var __cleanup_stack: UnsafeMutablePointer<
__darwin_pthread_handler_rec>

    public var __opaque: (Int8, Int8, Int8, Int8, ...))

}

But I think that's a pthread thing, and probably for fixed sized arrays
too. Anyway tuples is for the other thread.

If my assumptions were false and the original idea doesn't change the
memory/performance overhead then I am all for it :slight_smile:

···

On Tue, Feb 16, 2016 at 5:24 PM, Slava Pestov <spestov@apple.com> wrote:

On Feb 15, 2016, at 11:46 PM, Andrew Bennett via swift-evolution < > swift-evolution@swift.org> wrote:

The same goes for tuples. At the moment a tuple is the closest thing to a
c style struct. I think c structs are currently imported as tuples.

Actually structs are imported as structs :slight_smile: (eg, import CoreGraphics -
you get a CGPoint struct). We ask clang do the in-memory layout, but from a
language perspective, they look mostly like normal Swift structs.

If you made it so (A,A) was interchangeable with (B,B) then they'd have to
have the same size, and maybe also store type information where they may
not otherwise.

That’s not a requirement for subtyping relations actually.

If A is a struct conforming to some protocol P, then values of type ‘A’
have a different runtime representation than values of type ‘P’, because
the protocol value needs to attach the runtime type to the payload, whereas
the struct will not. However, we still do an implicit conversion allowing
As to be passed as Ps, we just generate the right code at the point where
the conversion takes place.

Another example is when you have a function () -> A, the conversion to ()
-> P requires actually generating a thunk to wrap the original function
value.

Subtyping in Swift is different from a pointer cast in C — its
semantically producing a new value, so any representational change issues
are orthogonal to the language itself. They leak out in the cases that are
not implemented (we don’t do tuple conversions currently, and didn’t do
function conversions until 2.1) but those will get plugged over time.

Slava

On Tuesday, 16 February 2016, Cao Jiannan via swift-evolution < > swift-evolution@swift.org> wrote:

Also:

union(A,B,C) is subtype of union(A,B,C,D,…)

在 2016年2月16日,14:36,Cao Jiannan <frogcjn@163.com> 写道:

Hi all,

I think the best way to solve the either problem is to separate it from
generic.
Optional and Either shouldn’t work the same way of generic type.
It’s just a represent of multiple type in one location.

Using an old friend, Union in C.
union {
case firstType
case secondType
}

This is the final solution for the sub typing problem of optional.

A == union(A,A)
union(A,B) == union(B,A)
B == union(B,B)

B is subtype of union(A,B)
A is subtype of union(A,B)

suppose
a is subclass of A
b is subclass of B, then
union(a,B) is subtype of union(A,B)
union(A,b) is subtype of union(A,B)
union(a,b) is subtype of union(a,B)
union(a,b) is subtype of union(A,b)

union can have as many case as possible. e.g., union(A,B,C,D,…)

So the Optional<UITableView> should be union(UITableView, None)
and Optional<MyTableVIew> should be union(MyTableView, None), which is
subclass of union(UITableView, None)

This is a final rational solution. I think.

-Jiannan

下面是被转发的邮件:

*发件人: *Cao Jiannan via swift-evolution <swift-evolution@swift.org>
*主题: **[swift-evolution] Swift Generic Subtype Problem*
*日期: *2016年2月16日 GMT+8 11:48:18
*收件人: *swift-evolution@swift.org
*回复-收件人: *Cao Jiannan <frogcjn@163.com>

Hi all,
I want to discuss on a problem about optional generic sub-typing.

This is my suggesion.

if B is subclass of A
Either<B,B> is subclass of Either<A,A>, Either<A,B>, Either<B,A>
Either<B,A> is subclass of Either<A,A>
Either<A,B> is subclass of Either<A,A>

Why? Let’s see an example code in a real project:

Here is a protocol type for some UIViewController,

   1. protocol SegueHandlerType {
   2. var tableView: UITableView! { get }
   3. }

so the UITableViewController can conform to the protocal

   1. extension UITableViewController : SegueHandlerType {
   2. }

It's great!
What if the tableView is a subclass UITableView?
like:

   1. class MyTableView : UITableView {
   2. }
   3.
   4. MyTableViewController {
   5. @IBOutlet var tableView: MyTableView!
   6. }

Then

   1. extension MyTableViewController:SegueHandlerType {
   2.
   3. }

will trigger a compiler error.

So the Optional needs a subclass system.
Or to say, that the template system needs a subclass system.

Optional<UITableView> should be the super type of Optional<MyTableView>
Array<UITableView> should be the super type of Array<MyTableView>

https://forums.developer.apple.com/message/101646#101646

Thanks!

Jiannan, Cao

_______________________________________________
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


(frogcjn) #20

It’s kind of same idea of TypeScipt 2, at 46:21 in this video.

https://channel9.msdn.com/Events/Build/2016/B881

···

2016-2-16 GMT+8 14:36:28
Hi all,

I think the best way to solve the either problem is to separate it from generic.
Optional and Either shouldn’t work the same way of generic type.
It’s just a represent of multiple type in one location.

Using an old friend, Union in C.
union {
  case firstType
  case secondType
}

This is the final solution for the sub typing problem of optional.

A == union(A,A)
union(A,B) == union(B,A)
B == union(B,B)

B is subtype of union(A,B)
A is subtype of union(A,B)
union(A,B,C) is subtype of union(A,B,C,D,…)

suppose
a is subclass of A
b is subclass of B, then
  union(a,B) is subtype of union(A,B)
  union(A,b) is subtype of union(A,B)
  union(a,b) is subtype of union(a,B)
  union(a,b) is subtype of union(A,b)

union can have as many case as possible. e.g., union(A,B,C,D,…)

So the Optional<UITableView> should be union(UITableView, None)
and Optional<MyTableVIew> should be union(MyTableView, None), which is subclass of union(UITableView, None)

This is a final rational solution. I think.

-Jiannan