Reputation: 13
So I'm learning some cool plain Kotlin by making a blackjack game called DeadJack (Dead simple Blackjack). Here's the code:
class DeadJack(name: String = "Joe") {
private val name: String = name
private var number: Number = 0
fun hit() {
val rand = (0..10).random()
if (number < 12) { // <--- Error in here
// Code stopped here
}
}
}
Then I get this Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: ..
error, I tried using IntelliJ's quick fix but it's just added some function with a TODO inside them (which I, who just started learning kotlin last night, can't understand).
Can I get some help? Thanks!
Upvotes: 1
Views: 2011
Reputation: 18547
Short answer: use a concrete type such as Int
instead of Number
.
Number
is an interface, and although it's implemented by many numeric classes (Int
, Short
, Byte
, Long
, Float
, Double
, BigInteger
, BigDecimal
, &c), it's very limited and not very useful in practice. About all you can do with it is convert it to standard numeric types — it has toFloat()
, toInt()
, &c methods — but it provides no way to do arithmetic, comparison, or other numeric operations.
In this case, the specific error is because Number
is not Comparable
, and so you can't use it in combination with the <
operator.
It's not very clear why Number
is so weak. I suspect the interface was something of an afterthought. Also, there are issues with the result types of any operations: what would be the result type of adding, say, a Byte
and a Short
? A Byte
or Short
would risk overflow; but to yield an Int
would either need a huge matrix of method overloads, or a bunch of special cases in the type system. You can't even return the ‘biggest’ type each time, as both Long
and Double
can store values the other can't.
In fact, Kotlin is stricter about numeric types than Java or C, which both do some automatic conversions (‘numeric promotions’) where the intent is clear. Because those conversions can cause obscure bugs, Kotlin forces you to be more explicit about them.
So in general, it's better to stick to a concrete type in your code. (If you're providing an interface for other people to use, you could accept a Number
as a parameter, but then immediately convert it to the concrete type you're using internally. But even that's not a great idea, since that conversion could be lossy.)
Upvotes: 2
Reputation: 17460
The problem is that number
is a Number
and 12
is an Int
, which can't be compared like that. Either you make number
as Int
:
class DeadJack(name: String = "Joe") {
private val name: String = name
private var number = 0
fun hit() {
val rand = (0..10).random()
if (number < 12) {
}
}
}
Or you use number.toInt()
while comparing:
class DeadJack(name: String = "Joe") {
private val name: String = name
private var number: Number = 0
fun hit() {
val rand = (0..10).random()
if (number.toInt() < 12) {
}
}
}
Upvotes: 0