Reputation: 1354
I have two trait
trait TResponseData extends Serializable {} //all response data
trait TRequestData extends Serializable {} //all request
Now I have Response class, which contains data and request
case class Response[A <: TResponseData, B <: TRequestData](data: A, request: B = null){}
While instance of case class Response must have data, request is not mandatory. So I declared its default to null in case class constructor. From Scala console, I am able to create its instance like
Response(null, null)
Response(null)
To generate instance of Response, I have created helper method:
def generateResponse[A <: TResponseData, B <: TRequestData] (data: A, request: B, passRequestInResponse: Boolean): Response[A, B] = {
if (passRequestInResponse)
return Response(data, request)
return Response(data, null)
}
Based on boolean passRequestInResponse, I am setting request in Response. On compiling same, I am getting follow error:
error: type mismatch;
found : Null(null)
required: B
return Response(data, null)
How can I achieve same (making request optional in generateResponse method)
Upvotes: 0
Views: 103
Reputation: 12991
The reason for the error is that all types in Scala have a bottom type of Nothing. Nothing cannot accept the "null" value and therefore the type definition is problematic as B can be Nothing.
To solve this you can add a lower bound:
def generateResponse[A <: TResponseData, B >: Null <: TRequestData ] (data: A, request: B,
passRequestInResponse: Boolean): Response[A, B] = {
this will mean that Nothing is an illegal type for B as the minimum allowed in Null.
The use of Option[B] is probably a better idea and should be used in this case in term of good design, however, in more generic cases there are situations where lower bound would be better.
P.S. you shouldn't be using return. As you can see in other answers you can do:
if (passRequestInResponse) {
Response(data, Some(request))
} else {
Response(data)
}
as this will give the value. Return is actually a control flow breaking (it is implemented with an exception) and can have unintended consequences. See for example https://blog.knoldus.com/scala-best-practices-say-no-to-return/
Upvotes: 1
Reputation: 27356
Using null
is a bad idea (as is return
) so it is better to use Option
:
trait TResponseData extends Serializable //all response data
trait TRequestData extends Serializable //all request
case class Response[A <: TResponseData, B <: TRequestData](data: A, request: Option[B]=None)
def generateResponse[A <: TResponseData, B <: TRequestData] (data: A, request: B, passRequestInResponse: Boolean): Response[A, B] =
if (passRequestInResponse) {
Response(data, Some(request))
} else {
Response(data)
}
You can also do some Option
magic like this:
def generateResponse[A <: TResponseData, B <: TRequestData] (data: A, request: B, passRequestInResponse: Boolean): Response[A, B] =
Response(
data,
Some(request).filter(_ => passRequestInResponse)
)
The advantage of this formulation is that it will work if request
is null
, and will treat this case as if passRequestInResponse
was false
As noted by @jwvh it is not clear that the generateResponse
function is useful because you can just call Response(data, Some(request))
or Response(data)
as needed. If you don't like that Some
in the first version, then create a class object with a custom apply
method:
object Response {
def apply[A <: TResponseData, B <: TRequestData](data: A, request: B): Response[A, B]
= Response(data, Option(request))
}
Then you can just use Response(data, request)
. This will work correctly if request
is null
.
Upvotes: 2
Reputation: 51271
You can either modify the generateResponse()
return type...
def generateResponse[A <: TResponseData, B <: TRequestData] (data: A
,request: B
,passRequestInResponse: Boolean
): Response[A, _] =
if (passRequestInResponse) Response(data, request)
else Response(data, null)
... or you can cast the null
to the required type.
def generateResponse[A <: TResponseData, B <: TRequestData] (data: A
,request: B
,passRequestInResponse: Boolean
): Response[A, B] =
if (passRequestInResponse) Response(data, request)
else Response(data, null.asInstanceOf[B])
(But don't use return
. It's not idiomatic Scala.)
In general, I don't really see why you need generateResponse()
at all. The Response
constructor will still either have a B
or it won't, so it should be an Option[B]
that defaults to None
. (Idiomatic Scala avoids null
.)
Upvotes: 2