can I restrict somehow type of generics for exampl...
# getting-started
m
can I restrict somehow type of generics for example I would like implement `
Copy code
class Angle<T>
where T can be Int or Float or Double and nothing else
d
class Angle<T : Number>
is about as good as it gets.
m
The best you can do with built-in types is to bound to a numeric class:
Copy code
class Angle<T : Number>
but that will accept also Long, Short and Byte. If you want to restrict to those types only I don’t see any way other than creating your specific type hierarchy:
Copy code
class Angle<T : Aunit>(value: T)

interface Aunit
inline class AInt(val value: Int) : Aunit
inline class ADouble(val value: Double) : Aunit

fun main() {
    Angle(AInt(1))
    Angle(ADouble(1.0))
    Angle(1) // obviously doesn't compile
}
Otherwise, if you don’t care about compile-time safety you could get away with runtime checks:
Copy code
class Angle<T : Number>(value: T) {
    init {
        require(value is Int || value is Float || value is Double)
    }
}
m
ok, thanks! its a bit more ugly solution than I thinked, would be nice to see such feature in one of kotlin releases 😄
m
You’re welcome. Meanwhile I thought that if you don’t need a generic class, you could try with overloaded constructors:
Copy code
class Angle(val v: Double) {
    constructor(v: Float) : this(v.toDouble())
    constructor(v: Int) : this(v.toDouble())
}

fun main() {
    Angle(1)
    Angle(1.0)
    Angle(1.0f)
    Angle(1L) // doesn't compile
}
the Idea is that your Angle will hold a Double property but you can initialize it also with an int or float
m
I rather would want make something like that:
Copy code
sealed class Angle{
  abstract val value: Double
}

data class RadiansAngle(override val value: Double) : Angle() {
  constructor(angle: DegreesAngle) : this(angle.toRadians().value)
}

data class DegreesAngle(override val value: Double) : Angle() {
  constructor(angle: RadiansAngle) : this(angle.toDegrees().value)
}
m
Ok this is good! If you want you can shorten declarations like this:
Copy code
sealed class Angle

data class RadiansAngle(val value: Double) : Angle() { }

data class DegreesAngle(val value: Double) : Angle() { }
also in my opinion you don’t need conversion constructors from one type to another, just keep the
to*()
methods. I would prefer to use
radians.toDegrees()
rather than
DegreesAngle(radians)
😉
m
oh, thanks for tips 😄!
i
There's a way, currently arrow supports Type Union so technically you could use that if you must only accept those types. The class would end up looking something like:
class Angle<T : Union<Int, Union<Float, Double>>>
Not sure if the nested Union is possible, I'm curious now though, ha!