Swift Generics equivalent of Java any type <?>
Asked Answered
B

2

6

In Java you can some times use generics without caring about the actual type. Can you do that in Swift?

For instance MyClass<AnyObject> doesn't work like MyClass<?> would in Java. At I'd expect it to work the same.

Is there any other way?

Barretter answered 20/11, 2015 at 16:24 Comment(2)
I haven't found any case where I'd use wildcards, I believe Swift doesn't need it. Do you have one? The most similar thing would be MyClass<Any> where Any really is any type (class, struct, enum, Type, function, tuple, etc.) but then again it may be just what a wildcard is, I can't fully remember how it works in JavaOtiose
I am trying to call this method func executeRequest(request: APIRequest<Any>) with a class MoviesAPIRequest: APIRequest<Movie> instance, and I get a compile error saying that Cannot convert value of type MoviesAPIRequest to expected argument type APIRequest<Any>Barretter
N
3

Introduce a type parameter; the compiler will let it take any type. Try:

func executeRequest<T> (request: APIRequest<T>) {
 // ...
}

For example:

class APIRequest<T> {}
class Movie {}
class MovieRequest : APIRequest<Movie> {}
let m = MovieRequest()
//print(m)

func executeRequest<T> (request: APIRequest<T>) {
    print(request)
}

executeRequest(m)

The introduction of a type parameter allows one to be more explicit and to better match the problem domain. For example, in your case, you surely can't do a APIRequest on anything whatsoever; you can make an APIRequest on, say, a Resource.

protocol Resource {}
class Movie : Resource {}
class Song : Resource {}

class APIRequest<T:Resource> { /* ... */ }

func executeRequest<T:Resource> (request: APIRequest<T>) { /* ... */ } 
Need answered 24/11, 2015 at 19:17 Comment(0)
C
3

There is no equivalent in Swift. Generics in Swift are somewhat different from in Java generally, so the use cases are different, too. Generics in Swift are very good for making general utility constructs and functions. If you are considering designing classes with intended inheritance around Generics, be very careful up front with your design up front and consider alternatives. It may be quite challenging. There are fundamental differences in the two languages, so trying to maintain parities in code may prove difficult. Some requirements will result in fundamentally different solutions in the two languages.

Here are some possible options depending on the specifics of your problem:

// start with a common protocol
protocol Requestable {
    func execute()
    func processData(input: Any)
}


// protocol with type constraint
protocol APIRequest : Requestable {
    typealias ContentType
    var content : ContentType { get }
    func processInput(input: ContentType)
}


extension APIRequest {
    func processData(input: Any) {
        if let input = input as? ContentType {
            processInput(input)
        } else {
            // probably should throw an error here
        }
    }
}


// Either define a Generic function to execute with a specific type
func executeRequest<RequestType:APIRequest>(request: RequestType) {
    request.execute()
}


// Or define a function taking a protocol conforming type
func executeRequest(request: Requestable) {
    request.execute()
}


// process the data with a specific request and input
func processRequest<RequestType:APIRequest>(request: RequestType, input: RequestType.ContentType) {
    request.processInput(input)
}


// process the data with input of arbitrary type
func processRequest(request: Requestable, data: Any) {
    request.processData(data)
}


class Movie {
}


class MovieRequest : APIRequest {
    var content : Movie

    init(movie: Movie) {
        self.content = movie
    }

    func execute() {
        // do something here
    }

    func processInput(input: Movie) {
        // do something with the movie input
    }
}

let movieRequest = MovieRequest(movie: Movie())
executeRequest(movieRequest)
Creekmore answered 20/11, 2015 at 17:3 Comment(0)
N
3

Introduce a type parameter; the compiler will let it take any type. Try:

func executeRequest<T> (request: APIRequest<T>) {
 // ...
}

For example:

class APIRequest<T> {}
class Movie {}
class MovieRequest : APIRequest<Movie> {}
let m = MovieRequest()
//print(m)

func executeRequest<T> (request: APIRequest<T>) {
    print(request)
}

executeRequest(m)

The introduction of a type parameter allows one to be more explicit and to better match the problem domain. For example, in your case, you surely can't do a APIRequest on anything whatsoever; you can make an APIRequest on, say, a Resource.

protocol Resource {}
class Movie : Resource {}
class Song : Resource {}

class APIRequest<T:Resource> { /* ... */ }

func executeRequest<T:Resource> (request: APIRequest<T>) { /* ... */ } 
Need answered 24/11, 2015 at 19:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.