Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Generics equivalent of Java any type <?>

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?

like image 782
Cosmin Avatar asked Nov 20 '15 16:11

Cosmin


2 Answers

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>) { /* ... */ } 
like image 166
GoZoner Avatar answered Nov 18 '22 12:11

GoZoner


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)
like image 43
Tom Pelaia Avatar answered Nov 18 '22 13:11

Tom Pelaia