Home » Swift » Is it necessary to pass a type parameter to static functions in a generic class?

Is it necessary to pass a type parameter to static functions in a generic class?

Posted by: admin January 4, 2018 Leave a comment

Questions:

My class: my class takes one type parameter, and has one static method which does not use the type parameter:

class GenericClass<T> {

    static func blub(x: Int) -> Int {
        return x + 1
    }
}

My problem: when I attempt to use the static function, my code does not compile:

let z: Int = GenericClass.blub(4) // doesn't compile

I’ve come up with two workarounds:

  1. give GenericClass a type argument — doesn’t matter which type:

    let y: Int = GenericClass<Void>.blub(4)
    
  2. create a second class, which doesn’t have any type parameters, to hold the static methods

So I know how to get the code working, although it may not be the optimal solution. But my question is about why Swift works this way.

My question:

Why doesn’t let y: Int = GenericClass<Void>.blub(4) compile?

It should compile because blub is a static method and therefore shouldn’t have any interaction with the type parameters, which are only used for instances, not for static methods and variables. Or at least, that’s what I expected.

Where am I wrong? How do class-level type parameters and static methods interact in Swift?

Is there a better way to solve this problem than the two workarounds I tried?

Screenshot:

enter image description here

Answers:

GenericClass is not a concrete type in Swift. There’s no way to talk about it any more than you can talk about the type Array without providing its type parameter. (The specific feature Swift lacks that would allow this is called “higher-kinded types.”)

Static methods are tied to the concrete type (GenericClass<T>) not to the higher-kinded type (GenericClass). In order to access the static methods, it needs to know the actual type you want.

While it’s true you’re not currently using the type parameter in this class method, there is nothing stopping you (or a subclass!) from doing so. Since you have no way to promise that T will never occur in this method, there’s no way for Swift to allow you to ignore it.

Questions:
Answers:

You can, in fact, reference generic type parameters from static methods. For example:

struct Wrapper<T> {
    var value: T

    private init(_ value: T) {
        self.value = value
    }

    static func wrap(_ value: T) -> Wrapper {
        return Wrapper(value)
    }
}

In this case the generic parameter can be inferred:

let wrapped = Wrapped.wrap(3) // => Wrapped<Int>