https://kotlinlang.org logo
#compiler
Title
# compiler
y

Youssef Shoaib [MOD]

07/26/2022, 12:14 PM
Is there any compile-time-evaluated way to check if a reified type is a specific class?
T::class == Desired::class
doesn't seem to be evaluated at compile time. I can also do
valueOfTypeDesired is T && !(valueOfSupertypeOfDesired is T)
but again this isn't evaluated at compile time. I'm interested not only because of performance but for a value-class optimization use case (can give more details if interested).
t

Tóth István Zoltán

07/26/2022, 5:01 PM
I don't think there is, for two reasons. First, the specification explicitly says that
reified
is about making the type runtime-available. IMHO, it means that when you use
reified
the exact type will be available during run-time, not just some generic, erased super-type. There is a reason, why
reified
applies only to
inline
functions. Second, all the checks you've written above are run-time checks, the only way to have a compile type check is to build a type system which enforces the type and/or use a non-inline function. Maybe your best bet is a compiler plugin, after playing around with them a bit it is quite easy to write one. (Disclaimer: I might be wrong, not an expert, ask your doctor, etc...)
y

Youssef Shoaib [MOD]

07/27/2022, 11:50 PM
Decompiled using cfr-0.152:
Copy code
public final class MainKt {
    public static final void test() {
        Object myResult = Result.constructor-impl((Object)42);
        Result myResultAny = Result.box-impl((Object)myResult);
        Result result = Result.box-impl((Object)myResult);
        System.out.println(result);
        System.out.println(myResultAny);
    }

    public static final void test2() {
        Object myResult;
        Object myResultAny = myResult = Result.constructor-impl((Object)42);
        Object value$iv = myResult;
        boolean $i$f$printlnWithoutBoxing = false;
        System.out.println((Object)Result.toString-impl((Object)value$iv));
        boolean $i$f$printlnWithoutBoxing2 = false;
        System.out.println((Object)Result.toString-impl((Object)myResultAny));
    }

    public static final <T> void printlnWithoutBoxing(@NotNull T value) {
        Intrinsics.checkNotNullParameter(value, (String)"value");
        boolean $i$f$printlnWithoutBoxing = false;
        System.out.println((Object)(value instanceof Result ? Result.toString-impl((Object)((Result)value).unbox-impl()) : value));
    }
}
And, if I use
myResultAny
as an actual `Any`:
Copy code
public fun test2(){
  val myResultAny: Any = Result.success(42).id() // ensures boxing
  printlnWithoutBoxing(myResultAny)
}
public fun <T> T.id(): T = this
it does indeed box, and you can see that in that case (i.e. when value isn't statically known to be a
Result
) the
else
branch persists:
Copy code
public static final void test2() {
    Result myResultAny = MainKt.id(Result.box-impl((Object)Result.constructor-impl((Object)42)));
    boolean $i$f$printlnWithoutBoxing = false;
    System.out.println((Object)(myResultAny instanceof Result ? Result.toString-impl((Object)myResultAny.unbox-impl()) : myResultAny));
}
s

shikasd

07/28/2022, 8:31 AM
My guess is that the compiler should be fine optimizing this, as the branches don't have any side effects. About inline class optimization though, note that in your case the values are still boxed even if the comparison is discarded, kinda destroying the purpose of value classes in the process If you want compile time safety, I suggest just using overloads of inline functions accepting known types
2 Views