https://kotlinlang.org logo
#getting-started
Title
# getting-started
r

Rob Elliot

12/05/2023, 10:02 AM
I was writing an expression which had to end up with a cast, then a method call and wrapping the whole thing in brackets was looking really ugly by the time ktlint had finished with it:
Copy code
private val jwtVerifier = (
  JWT.require(Algorithm.RSA256(jwkRSAProvider))
    .acceptLeeway(3) as JWTVerifier.BaseVerification
)
  .build(clock)
So I pulled out an extension function as so:
Copy code
private val jwtVerifier = JWT
  .require(Algorithm.RSA256(jwkRSAProvider))
  .acceptLeeway(3)
  .castTo<JWTVerifier.BaseVerification>()
  .build(clock)

@Suppress("UNCHECKED_CAST")
private fun <B> Any.castTo(): B = this as B
Is there an existing equivalent of
castTo
I'm missing? Is there any way to ensure that the receiver is a supertype of the target type, without having to pass both as type arguments at the call site?
s

Sam

12/05/2023, 10:12 AM
I think your best option would just be to use
let
.
Copy code
.acceptLeeway(3)
.let { it as JWTVerifier.BaseVerification }
.build(clock)
That way you get the formatting you want, but still get the IDE warnings and other inspections that come with using
as
.
🆒 1
r

Rob Elliot

12/05/2023, 10:16 AM
That's nice, thanks
s

Sam

12/05/2023, 10:16 AM
I think something like what you're asking for is possible with some annotation hackery:
Copy code
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
fun <A, B : A> @kotlin.internal.Exact A.castTo() = this as B
Then using
_
at the call site:
Copy code
.acceptLeeway(3)
.castTo<_, JWTVerifier.BaseVerification>()
.build(clock)
But the resulting behaviour is still less intelligent than the built-in IDE inspections 😞
Copy code
Any().castTo<_, String>() // ✅
"Hello".castTo<_, Int>() // ❌
("Hello" as Any).castTo<_, Int>() // ✅
At the end of the day, you'll always be able to come up with some example of a downcast that looks fine but fails at runtime
r

Rob Elliot

12/05/2023, 10:18 AM
Though now it occurs to me that perhaps this is nicer still:
Copy code
private val jwtVerifier = JWT
  .require(Algorithm.RSA256(jwkRSAProvider))
  .acceptLeeway(3)
  .withAudience(audience)
  .build(clock)

fun Verification.build(clock: Clock): JWTVerifier = (this as JWTVerifier.BaseVerification).build(clock)
s

Sam

12/05/2023, 10:19 AM
😄 good point
Easy to get carried away with cool Kotlin features and forget about the good old fashioned solutions
I like it 👍