Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I call a static property on a Swift protocol from a generic function?

Tags:

generics

swift

Given this code:

public protocol Selectable {

    typealias T

    var selected: Bool { get }

    static var defaultValue: T { get }

}

public func selected<T: Selectable>(items: [T]) -> T {
    if let selected = items.filter({$0.selected}).first {
        return selected
    }
    return T.defaultValue
}

I get an error on the return line: "Cannot convert return expression of type 'T.T' to expected return type 'T'".

Changing it to return T.defaultValue as! T seems to work but that doesn't make any sense to me. Am I missing something or should I file a radar?

like image 344
Robert Atkins Avatar asked Apr 02 '15 14:04

Robert Atkins


People also ask

What is static property in Swift?

Swift lets you create properties and methods that belong to a type, rather than to instances of a type. This is helpful for organizing your data meaningfully by storing shared data. Swift calls these shared properties “static properties”, and you create one just by using the static keyword.

Can Swift Protocol have properties?

Protocols provide a blueprint for Methods, properties and other requirements functionality. It is just described as a methods or properties skeleton instead of implementation. Methods and properties implementation can further be done by defining classes, functions and enumerations.

How do I create a static function in Swift?

In Swift, we use the static keyword to create a static method. For example, class Calculator { // static method static func add() { ... } } Here, add() is the static method.

When should I use static in Swift?

The Static keyword makes it easier to utilize an objects properties or methods without the need of managing instances. Use of the Static keyword in the Singleton pattern can reduce memory leaks by mismanaging instances of classes.

How do you define a static variable in Swift?

In C and Objective-C, you define static constants and variables associated with a type as global static variables. In Swift, however, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports.

Can a swift property have an instance variable?

A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly. This approach avoids confusion about how the value is accessed in different contexts and simplifies the property’s declaration into a single, definitive statement.

When should I prefix type property requirements with the static keyword?

Always prefix type property requirements with the static keyword when you define them in a protocol. This rule pertains even though type property requirements can be prefixed with the class or static keyword when implemented by a class: Here’s an example of a protocol with a single instance property requirement:

What is the difference between class and instance methods in Swift?

In Swift, you can choose whether to define a class, structure, or enumeration, and still have the flexibility to define methods on the type you create. Instance methods are functions that belong to instances of a particular class, structure, or enumeration.


2 Answers

You can use Self in the protocol:

public protocol Selectable {

    var selected: Bool { get }

    static var defaultValue: Self { get }
    //                       ^^^^
}

public func selected<T: Selectable>(items: [T]) -> T {
    if let selected = items.filter({$0.selected}).first {
        return selected
    }
    return T.defaultValue
}

OR, if you want to use typealias, you have to:

public protocol Selectable {
    typealias Value

    var selected: Bool { get }

    static var defaultValue: Value { get }
}

public func selected<T: Selectable where T.Value == T>(items: [T]) -> T {
    //                             ^^^^^^^^^^^^^^^^^^
    if let selected = items.filter({$0.selected}).first {
        return selected
    }
    return T.defaultValue
}
like image 193
rintaro Avatar answered Oct 21 '22 22:10

rintaro


Building on @rintaro's answer, using Self for the type of defaultValue means the typealias is unnecessary:

public protocol Selectable {

    var selected: Bool { get }

    static var defaultValue: Self { get }

}

public func selected<T: Selectable >(items: [T]) -> T {
    if let selected = items.filter({$0.selected}).first {
        return selected
    }
    return T.defaultValue
}

(I found this as changing defaultValue's type to Self made my implementing class not conform to the protocol anymore—and I noticed I wasn't even referring to the typealias Value; removing that made my implementing class comply again.)

like image 34
Robert Atkins Avatar answered Oct 21 '22 21:10

Robert Atkins