Rod_Brown
(Rod Brown)
1
Hi everyone. I found something odd that seems baked into how Cocoa Touch does protocols, but Swift cannot model it:
@interface UIScrollView: UIView
@property (weak, nonatomic) id <UIScrollViewDelegate> delegate;
@end
@interface UITableView: UIScrollView
@property (weak, nonatomic) id <UITableViewDelegate> delegate;
@end
@protocol UITableViewDelegate: UIScrollViewDelegate
...
@end
Subclasses can further specify the conformance of a property’s protocol-conforming object to state a further type on that property. I tried to do something extremely similar today in Swift, and it failed, saying the protocols were different:
class SourceBar: UIScrollView {
override var delegate: SourceBarDelegate? {
get { return super.delegate as? SourceBarDelegate }
set { super.delegate = newValue }
}
}
@objc protocol SourceBarDelegate: UIScrollViewDelegate {
func foo()
}
Considering the fact that the protocol SourceBarDelegate conforms to UIScrollViewDelegate, I can’t see why this override should fail. Can anyone enlighten me as to why this is a limitation in the language?
Thanks,
Rod
I kinda feel this is somehow related: http://discourse.natecook.com/t/pitch-return-a-subclass-for-a-protocol-method-without-the-need-for-an-associatedtype/2355
It would be really handy to be able to override any type A with another type B where the relationship is B : A.
···
--
Adrian Zubarev
Sent with Airmail
Am 10. März 2017 um 13:08:37, Rod Brown via swift-evolution (swift-evolution@swift.org) schrieb:
Hi everyone. I found something odd that seems baked into how Cocoa Touch does protocols, but Swift cannot model it:
@interface UIScrollView: UIView
@property (weak, nonatomic) id <UIScrollViewDelegate> delegate;
@end
@interface UITableView: UIScrollView
@property (weak, nonatomic) id <UITableViewDelegate> delegate;
@end
@protocol UITableViewDelegate: UIScrollViewDelegate
...
@end
Subclasses can further specify the conformance of a property’s protocol-conforming object to state a further type on that property. I tried to do something extremely similar today in Swift, and it failed, saying the protocols were different:
class SourceBar: UIScrollView {
override var delegate: SourceBarDelegate? {
get { return super.delegate as? SourceBarDelegate }
set { super.delegate = newValue }
}
}
@objc protocol SourceBarDelegate: UIScrollViewDelegate {
func foo()
}
Considering the fact that the protocol SourceBarDelegate conforms to UIScrollViewDelegate, I can’t see why this override should fail. Can anyone enlighten me as to why this is a limitation in the language?
Thanks,
Rod
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
mayoff
(Rob Mayoff)
3
The problem here is that `UITableView`'s redefinition of `delegate` is not
type-safe. By casting a `UITableView` reference to a `UIScrollView`, you
set the `delegate` to something that doesn't conform to `UITableView`:
@interface ViewController () <UIScrollViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tableView = [[UITableView alloc] init];
// This line correctly generates a warning, because self isn't a
UITableViewDelegate:
tableView.delegate = self;
// This line generates no warning:
((UIScrollView *)tableView).delegate = self;
}
@end
···
On Fri, Mar 10, 2017 at 6:08 AM, Rod Brown via swift-evolution < swift-evolution@swift.org> wrote:
Hi everyone. I found something odd that seems baked into how Cocoa Touch
does protocols, but Swift cannot model it:
@interface UIScrollView: UIView
@property (weak, nonatomic) id <UIScrollViewDelegate> delegate;
@end
@interface UITableView: UIScrollView
@property (weak, nonatomic) id <UITableViewDelegate> delegate;
@end
@protocol UITableViewDelegate: UIScrollViewDelegate
...
@end
Looks like a compiler bug, since it works with classes:
class Base {}class Derived : Base {}
class A {
var x: Base? { return Base() }
}
class B : A {
override var x: Derived? { return Derived() }
}
dwaite
(David Waite)
5
The getter is covariant while the setter is contravariant. The result is read/write properties are invariant.
Objective-C basically considers declared types to be advisory (to generate compiler warnings). In reality, both delegate properties are of type ‘id’, with type issues surfacing at runtime.
-DW
···
On Mar 10, 2017, at 5:08 AM, Rod Brown via swift-evolution <swift-evolution@swift.org> wrote:
Hi everyone. I found something odd that seems baked into how Cocoa Touch does protocols, but Swift cannot model it:
@interface UIScrollView: UIView
@property (weak, nonatomic) id <UIScrollViewDelegate> delegate;
@end
@interface UITableView: UIScrollView
@property (weak, nonatomic) id <UITableViewDelegate> delegate;
@end
@protocol UITableViewDelegate: UIScrollViewDelegate
...
@end
Subclasses can further specify the conformance of a property’s protocol-conforming object to state a further type on that property. I tried to do something extremely similar today in Swift, and it failed, saying the protocols were different:
class SourceBar: UIScrollView {
override var delegate: SourceBarDelegate? {
get { return super.delegate as? SourceBarDelegate }
set { super.delegate = newValue }
}
}
@objc protocol SourceBarDelegate: UIScrollViewDelegate {
func foo()
}
Considering the fact that the protocol SourceBarDelegate conforms to UIScrollViewDelegate, I can’t see why this override should fail. Can anyone enlighten me as to why this is a limitation in the language?
Thanks,
Rod
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
dwaite
(David Waite)
6
This works because your properties are read-only, thus allowed to be covariant. If you add a setter, the compiler will complain.
-DW
···
On Mar 10, 2017, at 5:33 AM, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:
Looks like a compiler bug, since it works with classes:
class Base {}
class Derived : Base {}
class A {
var x: Base? { return Base() }
}
class B : A {
override var x: Derived? { return Derived() }
}
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
Rod_Brown
(Rod Brown)
7
Hi Rob,
I think we could actually do that (and cause the same bug) with the derived classes Anton mentioned, which means the behaviour is inconsistent, despite the perhaps safety.
- Rod
···
On 11 Mar 2017, at 6:32 am, Rob Mayoff <mayoff@dqd.com> wrote:
On Fri, Mar 10, 2017 at 6:08 AM, Rod Brown via swift-evolution <swift-evolution@swift.org> wrote:
Hi everyone. I found something odd that seems baked into how Cocoa Touch does protocols, but Swift cannot model it:
@interface UIScrollView: UIView
@property (weak, nonatomic) id <UIScrollViewDelegate> delegate;
@end
@interface UITableView: UIScrollView
@property (weak, nonatomic) id <UITableViewDelegate> delegate;
@end
@protocol UITableViewDelegate: UIScrollViewDelegate
...
@end
The problem here is that `UITableView`'s redefinition of `delegate` is not type-safe. By casting a `UITableView` reference to a `UIScrollView`, you set the `delegate` to something that doesn't conform to `UITableView`:
@interface ViewController () <UIScrollViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UITableView *tableView = [[UITableView alloc] init];
// This line correctly generates a warning, because self isn't a UITableViewDelegate:
tableView.delegate = self;
// This line generates no warning:
((UIScrollView *)tableView).delegate = self;
}
@end