How to Call a Static Function on a Protocol in a Generic Way

How can I call a static function on a protocol in a generic way?

Nice question. Here is my humble point of view:

Is there a point to declaring a static function on a protocol?

Pretty much the same as having instance methods declared in a protocol.

The client using the protocol has to call the function on a type conforming to the protocol anyway right?

Yes, exactly like instance functions.

That breaks the idea of not having to know the type conforming to the protocol IMO.

Nope. Look at the following code:

protocol Feline {
var name: String { get }
static func createRandomFeline() -> Feline
init()
}

extension Feline {
static func createRandomFeline() -> Feline {
return arc4random_uniform(2) > 0 ? Tiger() : Leopard()
}
}

class Tiger: Feline {
let name = "Tiger"
required init() {}
}

class Leopard: Feline {
let name = "Leopard"
required init() {}
}

let feline: Feline = arc4random_uniform(2) > 0 ? Tiger() : Leopard()
let anotherFeline = feline.dynamicType.createRandomFeline()

I don't know the real type inside the variable feline. I just know that it does conform to Feline. However I am invoking a static protocol method.

Is there a better way to do this?

I see, you would like to call a static method/function declared in a protocol without creating a value that conforms to the protocol.

Something like this:

Feline.createRandomFeline() // DANGER: compiler is not happy now

Honestly I don't know the reason why this is not possible.

How to call static methods on a protocol if they are defined in a protocol extension?

Apple doc

Protocols do not actually implement any functionality themselves.
Nonetheless, any protocol you create will become a fully-fledged type
for use in your code.

Therefore, you cannot call static methods directly of protocol.

Implementing protocol static method that takes and returns Self (in swift)

Your * implementation has a few subtle problems. Here's the implementation you mean:

static func *(lhs: Float, rhs: ThingBox<T>) -> Self {
return self.init(thing: lhs * rhs.thing)
}

First, you can't use Self as a parameter type. You have to be explicit. Self means "the actual type" and if you could use that for a subclass, this would violate LSP. For example, say I have types Animal and Dog (with the obvious relationships). Say I wrote the function:

class Animal {
func f(_ a: Self) { ... }
}

with the meaning that Animal.f will take Animal, but Dog.f will only take Dog but will not take a Cat. So you would expect the following to be true:

dog.f(otherDog) // this works
dog.f(cat) // this fails

But that's breaks the rules of substitution. What if I write this:

let animal: Animal = Dog()
animal.f(cat)

That should be legal, because Animal.f can take any Animal, but the implementation of Dog.f cannot take a cat. Type mismatch. Boom. So it's not legal. (This restriction does not exist for return types. I'll leave that as an exercise for the reader. Try to create an example like the above for returning Self.)

The second error was just a syntax mistake. It's not Self(), it's self.init(). In a static method, self is the dynamic type (which is what you want), and Swift requires you to call init explicitly when used this way. That's just syntax, not a deep type issue like the other.


There's no way in Swift to inherit the thing you're talking about. If you want to overload, that's fine, but you have to be explicit about the types:

class OtherBox: ThingBox<Int> {
static func *(lhs: Float, rhs: OtherBox) -> Self {
return self.init(thing: lhs * rhs.thing)
}
}

This does exactly what you want, but it has to be added to each child; it won't inherit automatically with covariance. Swift doesn't have a strong covariance system to express it.

That said, when you start intermixing generics, protocols, and subclassing this way, you're going to run into many, many weird corner cases, both due to the math, and due to current Swift limitations. You should ask carefully if your actual code needs this much parameterization. Most cases I encounter of these kinds of questions are over-designed "in case we need it" and just simplifying your types and making things concrete is everything you need for solving the actual program you want to write. It's not that it wouldn't be nice to build incredibly generic algorithms built on higher-kinded types, but Swift just isn't the language for that today (and possibly never; there are a lot of costs to adding those features).

How to infer type in static generic method with the type of the caller in Swift

I want to tell to the compiler "T is the class who calls the static method"

Assuming you want to apply your get only when T is the class who calls the static method, how is this?

protocol Storable {
//...
}

extension Storable where Self: Decodable {
static func get(by identifier: String, completion: @escaping (Self?) -> Void) {
//...
}
}

struct User: Storable, Decodable {
//...
}

This will be compiled successfully:

    User.get(by: "userId", completion: { user in
print(user)
})

Swift generics & protocols: Return specialized type from static function?

You can use AssociatedTypes in your protocol definition.

protocol DAO {
associatedtype Item
static func fromDictionary(_ dictionary: [String : Any]) -> Item
}

class User : DAO {

static func fromDictionary(_ dictionary: [String : Any]) -> User {
return User(dictionary)
}
}

Read the official docs for AssociatedTypes

What is the proper way to reference a static variable on a Swift Protocol?

In the example you show, there is no difference. Because identifier is a protocol requirement, it will be dynamically dispatched to in both cases, therefore you don't need to worry about the wrong implementation being called.

However, one difference arises when you consider the value of self inside the static computed property when classes conform to your protocol.

self in a static method/computed property is the metatype value that it's is called on. Therefore when called on I, self will be I.self – which is the static type that the compiler infers the generic placeholder I to be. When called on type(of: identifiable), self will be the dynamic metatype value for the identifiable instance.

In order to illustrate this difference, consider the following example:

protocol Identifiable {
static var identifier: String { get }
}

extension Identifiable {
static var identifier: String { return "\(self)" }
}

func work<I : Identifiable>(on identifiable: I) {
let identifier = I.identifier
print("from Protocol: \(identifier)")

let identiferFromType = type(of: identifiable).identifier
print("using type(of:): \(identiferFromType)")
}

class C : Identifiable {}
class D : C {}

let d: C = D()

// 'I' inferred to be 'C', 'type(of: d)' is 'D.self'.
work(on: d)

// from Protocol: C
// using type(of:): D

In this case, "which is better" completely depends on the behaviour you want – static or dynamic.

SWIFT: Protocol function in static method is not visible on self

protocol PrintProtocolTest {
static func printTest()
}

extension PrintProtocolTest {
static func printTest() {
print(self)
}
}

class A: PrintProtocolTest {
}

extension A {
static func test() {
self.printTest()
}
}

class B: A
{

}

B.test() /// <--- print 'B' here

You can get the result

B

Your code is right. Using self is ok.

With the return

protocol PrintProtocolTest {
static func printTest()
}

extension PrintProtocolTest {
static func printTest() {
print(self)
}
}

class A: PrintProtocolTest {
required init() {

}
}

extension A {
static func test() -> PrintProtocolTest {
self.printTest()
return self.init()
}
}

class B: A
{

}

B.test() // <--- return B instance here


Related Topics



Leave a reply



Submit