How to "Explicitly" Implement a Protocol in Swift? If It Is Impossible, Why

How can I explicitly implement a protocol in swift? If it is impossible, why?

Protocol extensions basically already do what you're describing:

protocol Cat {
}
extension Cat {
func quack() {
print("meow")
}
}
class Duck : Cat {
func quack() {
print("quack")
}
}
let d = Duck()
d.quack() // quack
(d as Cat).quack() // meow

How to implement a Swift protocol across structs with conflicting property names

The desired feature from explicit interface implementations is that they are statically dispatched, right? If you use Description on a BusStop, it will be an optional string, but if you use Description on a Stop, it will be a non-optional string.

In Swift, extension members are statically dispatched, so you can make use of this to achieve something similar:

extension Stop where Self == BusStop {
// Since the type of "self" here is BusStop, "Description" refers to the one declared in BusStop
// not this one here, so this won't cause infinite recursion
var Description : String { return self.Description ?? "" }
}

extension Stop where Self == TrainStop {
var Latitude: Double { return self.Latitude ?? 0 }
var Longitude: Double { return self.Longitude ?? 0 }
}

This code shows that this works:

let busStop = BusStop(Code: "ABC", Description: "My Bus Stop", Latitude: 0, Longitude: 0)
print(type(of: busStop.Description)) // Optional<String>
let stop: Stop = busStop
print(type(of: stop.Description)) // String

However, I still don't think this is good Swift code. It is often bad to just directly translate an API from one language to another. If I were you, I would make Longitude, Latitude and Description in Stop to be all optionals.

Is it possible for a class to explicitly invoke a method on a protocol's extension?

The following answer in the thread

  • Calling protocol default implementation from regular method

describes using a nested dummy type to access the default implementation of a protocol from within a type that already has supplied its own implementation of that blueprinted method. We may extend this method to also allow actually making use of (blueprinted) properties of the MyClass2 instance, but within the call to the default implementation which MyClass2 already implements its custom version of (hence taking precedence over the default one).

We start by looking at a slightly more light weight version of your example, with a default implementation supplied for someFuncWithDefaultImplementation()

protocol MyProtocol : class {
func someFuncWithDefaultImplementation()
var someInt: Int { get set }
}

extension MyProtocol {
func someFuncWithDefaultImplementation() {
print("Called default impl. Currently, someInt = \(someInt)")
print("Mutates someInt from within default implementation (0) ...")
someInt = 0
}
}

We use the non-elegant nested type solution in the custom implementation of someFuncWithDefaultImplementation() of MyClass2, to call the default implementation of the latter, but stores a reference in the Dummy instance back to the MyClass2 instance, to allow the someInt property of MyClass2 to be used in the default implementation call (for reading and writing), even if this is called from the Dummy type.

class MyClass2 : MyProtocol
{
var someInt: Int = 42

func someFuncWithDefaultImplementation()
{
// do some additional stuff ...
print("In MyClass2 implementation, currently someInt = \(someInt)")

/* Dummy 'MyClass2'-capturing type used to call the default
implementation of 'MyProtocol', but with read and write
access to 'MyClass2':s self:s 'someInt' instance. */
class Dummy : MyProtocol {
unowned let myClass2: MyClass2
init(_ myClass2: MyClass2) { self.myClass2 = myClass2 }
var someInt: Int {
get { return myClass2.someInt }
set { myClass2.someInt = newValue }
}
}

// call default implementation of 'someFuncWithDefaultImplementation'
// supplying 'self' to read/write access to self.someInt.
Dummy(self).someFuncWithDefaultImplementation()

print("Back in MyClass2:s implementation; now someInt = \(someInt)")
// 0, woah, mutated in default implementation!
}
}

let a = MyClass2()
a.someFuncWithDefaultImplementation()
/* In MyClass2 implementation, currently someInt = 42
Called default impl. Currently, someInt = 42
Mutates someInt from within default implementation (0) ...
Back in MyClass2:s implementation; now someInt = 0 */

You could also choose to declare the nested Dummy outside of the function, just marking it private to make sure it cannot be accessed from outside MyClass2:

class MyClass2 : MyProtocol
{
var someInt: Int = 42

/* Dummy 'MyClass2'-capturing type used to call the default
implementation of 'MyProtocol', but with read and write
access to 'MyClass2':s self:s 'someInt' instance. */
private class Dummy : MyProtocol {
unowned let myClass2: MyClass2
init(_ myClass2: MyClass2) { self.myClass2 = myClass2 }
var someInt: Int {
get { return myClass2.someInt }
set { myClass2.someInt = newValue }
}
}

func someFuncWithDefaultImplementation()
{
// do some additional stuff ...
print("In MyClass2 implementation, currently someInt = \(someInt)")

// call default implementation of 'someFuncWithDefaultImplementation'
// supplying 'self' to read/write access to self.someInt.
Dummy(self).someFuncWithDefaultImplementation()

print("Back in MyClass2:s implementation; now someInt = \(someInt)")
// 0, woah, mutated in default implementation!
}
}

I will, however, repeat the same as the author of the linked answer: this approach is not very elegant.

Swift 2.0: Protocol extensions: Two protocols with the same function signature compile error

A protocol defines requirements (methods, properties, ...) for a
conformant type.

protocol FirstDelegate {
func someFunc()
}

protocol SecondDelegate {
func someFunc()
}

defines two protocols with the same required method someFunc().
A conformant type must implement this method:

class SomeClass: FirstDelegate, SecondDelegate {
func someFunc() {
print("SomeClass implementation")
}
}

A protocol extension provides method and property implementations
to conformant types. A special case of a protocol extension is a
default implementation, which is what you defined here:

extension FirstDelegate {
func someFunc() {
print("First delegate")
}
}

It defines a default implementation of someFunc() for all types
conforming to FirstDelegate. Since this is the only required
method of that protocol, a conforming class need not define the
method at all:

class SomeClass: FirstDelegate {

}

SomeClass().someFunc() // Output: First delegate

But if the class provides its own implementation then that
will be used:

class SomeClass: FirstDelegate {
func someFunc() {
print("SomeClass implementation")
}
}

SomeClass().someFunc() // Output: SomeClass implementation

In your case, you have defined default implementations of someFunc()
for both protocols:

extension FirstDelegate {
func someFunc() {
print("First delegate")
}
}

extension SecondDelegate {
func someFunc() {
print("Second delegate")
}
}

A class can still conform to both protocols if it provides its own
implementation of the required method:

class SomeClass: FirstDelegate, SecondDelegate {
func someFunc() {
print("SomeClass implementation")
}
}

But the class cannot conform by using the default implementation

class SomeClass: FirstDelegate, SecondDelegate {

}

for both protocols
because there is a conflict. It is unspecified which default
implementation should be used, and that's why the compiler complains.

Actually the class now conforms to none of the protocols.
This can be seen in the full compiler log in the Report navigator:


main.swift:24:7: error: type 'SomeClass' does not conform to protocol 'FirstDelegate'
class SomeClass: FirstDelegate, SecondDelegate {
^
main.swift:5:10: note: multiple matching functions named 'someFunc()' with type '() -> ()'
func someFunc()
^
main.swift:19:10: note: candidate exactly matches
func someFunc() {
^
main.swift:13:10: note: candidate exactly matches
func someFunc() {
^
main.swift:24:7: error: type 'SomeClass' does not conform to protocol 'SecondDelegate'
class SomeClass: FirstDelegate, SecondDelegate {
^
main.swift:9:10: note: multiple matching functions named 'someFunc()' with type '() -> ()'
func someFunc()
^
main.swift:19:10: note: candidate exactly matches
func someFunc() {
^
main.swift:13:10: note: candidate exactly matches
func someFunc() {
^

implement protocol with different associated type

I just fund a way to archive this. The trick is to add another associated type in one of the subtypes of the protocol:

protocol ConvertableInt : Convertable {
associatedtype TResI
typealias TargetType = TResI
}

extension MyData : Convertable {
typealias TargetType = String
func convert() -> String { return String(self.data) }
}

extension MyData : ConvertableInt {
typealias TResI = Int
func convert() -> TResI { return self.data }
}

This also allows to get rid of the second subtype for string.

While this passes the compiler it totally crashes at runtime!

The compiler always calls the method defined which was defined at the explicit typealias. In this case:

typealias TargetType = String

Which will result in interpreting the address as a integer and give you totally wrong results. If you define it vice versa it will simply crash because it tries to interpret the integer as a address.



Related Topics



Leave a reply



Submit