I have following code:
import UIKit
protocol Fooable: class where Self: UIViewController {
func foo()
}
class SampleViewController: UIViewController, Fooable {
func foo() {
print("foo")
}
}
let vc1: Fooable = SampleViewController()
let vc2: Fooable = SampleViewController()
// vc1.show(vc2, sender: nil) - error: Value of type 'Fooable' has no member 'show'
// (vc1 as! UIViewController).show(vc2, sender: nil) - error: Cannot convert value of type 'Fooable' to expected argument type 'UIViewController'
(vc1 as! UIViewController).show((vc2 as! UIViewController), sender: nil)
commented lines doesn't compile.
Why am I forced to cast protocol type object to UIViewController
even if Fooable
protocol requires, that types that conform to it inherit from UIViewController
?
Google Castis the name of the protocol that is used to communicate between the sender and the receiver application. By consequence it means that a google-cast application is distributed between a sender part and a receiver part.
We cannot perform implicit type casting on the data types which are not compatible with each other such as: Converting float to an int will truncate the fraction part hence losing the meaning of the value. Converting double to float will round up the digits.
Because downcasting can fail, the type cast operator comes in two different forms. The conditional form, as?, returns an optional value of the type you are trying to downcast to.
The general syntax for type casting operations is as follows: The type name is the standard ‘C’ language data type. An expression can be a constant, a variable or an actual expression.
In Swift 5 (Xcode 10.2), your code now works as expected without having to perform a force cast.
In Swift 4.x, Swift doesn't fully support superclass constraints on protocols, that is, being able to define protocol P where Self : C
where C
is the type of a class.
The fact that the compiler doesn't prevent you from doing this until the feature is actually implemented was an oversight, as said by Swift compiler engineer Slava Pestov:
Slava Pestov added a comment - 31 May 2018 1:19 PM
[...] "protocol P : Foo where Self : Class" was discovered on accident by users, and it doesn't really work completely. It was an oversight that it wasn't banned.
However this is a feature that is intended to be fully implemented in a future version of the language as a part of SE-0156.
Slava Pestov added a comment - 31 May 2018 1:19 PM
Both are supposed to work, but we haven't fully implemented the proposal yet.
(Edit: Slava has now implemented this in #17611, #17651, #17816 & #17851, so you'll get them in Swift 5, available from Xcode 10.2)
Once implemented, you'll be able to treat such a protocol type as the class type that it requires conforming types to inherit from (e.g allowing you to treat your Fooable
as a UIViewController
without having to cast), in the same way that you can treat a class existential such as Fooable & UIViewController
as a UIViewController
.
Not only that, but you'll also be able to state the superclass requirement directly on the protocol rather than in a where
clause, for example:
protocol Fooable : UIViewController {
func foo()
}
However, until Swift 5, I would recommend steering well clear of superclass constrained protocols – they currently have some nasty rough edges around them.
For example, this will miscompile and crash at runtime in Swift 4.1:
class C : P {
func speak() {}
}
protocol P where Self : C {
func speak()
}
let c: P = C()
c.speak()
and it'll crash the compiler in later versions of the language (SR-6816).
As a workaround, you could use an underscored protocol with a class existential typealias in order to enforce the class constraint instead. For example:
import UIKit
protocol _Fooable : class {
func foo()
}
typealias Fooable = _Fooable & UIViewController
class SampleViewController : Fooable /* implicitly : UIViewController */ {
func foo() {
print("foo")
}
}
// ...
let vc1: Fooable = SampleViewController()
let vc2: Fooable = SampleViewController()
vc1.show(vc2, sender: nil)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With