Reputation: 21
class Request {
}
class Response<T: Request> {
let request: T
required init(request: T) {
self.request = request
}
}
class Adapter {
static func MakeRequest<T: Request, N: Response<T>>(request: T) -> N {
let response = N(request: request)
return response
}
}
Error: Cannot invoke initializer for type 'N' with an argument list of type '(request: T)'
I would like to create a response class that stores the request as a generic type. When I try to instantiate a response passing in a generic request it returns the error above.
Upvotes: 2
Views: 550
Reputation: 1978
What you are trying to do does not make the most sense.
If all of your request and response objects are going to be subclasses of Request
and Response
, then you have no need for generics. You won't be able to define anything other than subclasses of Request
or Response
that will be usable in your Adapter
. Just define everything like this:
class Request {
}
class Response {
let request: Request
required init(request: Request) {
self.request = request
}
}
class Adapter {
static func MakeRequest(request: Request) -> Response {
let response = Response(request: request)
return response
}
}
However, I suspect that what you really want is to define Request
and Response
as protocols. This will allow you to make any class or struct conform to the Request
or Response
protocols and thus usable in your Adapter
. This is a great use for generics.
protocol Request {
}
protocol Response {
var request: Request { get }
init(request: Request)
}
class Adapter {
static func MakeRequest<T: Request, N: Response>(request: T) -> N {
let response = N(request: request)
return response
}
}
Edit
Based on your comment, I see that you want to use a subclass of Request
in Response
without having to typecast. Certainly generics could make that possible, but it will not be useful to you.
Imagine you have your Request
and Response
classes defined as you did:
class Request {
}
class Response<T: Request> {
let request: T
required init(request: T) {
self.request = request
}
}
And you have a special Request
subclass defined as MyRequest
, which contains an additional property:
class MyRequest: Request {
let numberOfRetries: Int = 3
}
And you create a response containing a MyRequest
:
let myRequest = MyRequest()
let aResponse = Response(request: myRequest)
This all works. But what can you do with it? In a playground, you can check numberOfRetries
and see that it's working:
aResponse.request.numberOfRetries // 3
But you can't write any code in a real app that will take advantage of this. Using your Adapter
as an example, any Adapter
instance cannot check numberOfRetries
without being specialized, because a generic Adapter
that accepts a generic Response
which accepts a generic Request
will not be able to assume that the request was a MyRequest
instance, and thus cannot assume that numberOfRetries
is present.
If you want your Adapter
to be able to take advantage of a Request
or Response
subclass's functionality with typecasting or checking, you will need a specialized Adapter
subclass with constraints on what Request
and Response
it handles. And if you are creating an Adapter
subclass, I'd say the usefulness of generics in your situation is severely limited.
In other words, an Adapter
instance (or any other code that deals with Response
objects) will not be able to take advantage of a Response
subclass's special functionality without typecasting, specifically because your use of generics means that the Adapter
cannot assume what kind of Response
it will be working with.
Upvotes: 1
Reputation: 13243
Given your question and your comment on @user2194039 it is probably the best way to instantiate it directly since you need to provide the type information:
// if the function would work in your example you have to call it like so
let response: URLResponse<String> = Adapter.MakeRequest("Hello")
// this would be the easiest way
let response = URLResponse("Hello")
If your example is more complex please provide more information.
Upvotes: 0