Primitive types in the type hierarchy


#1

The root of Kotlin’s type hierarchy is Any. But Any maps directly to java.lang.Object. How is it possible then to have primitive types (directly supported by the JVM) in this hierarchy?

In Scala you have

  • Any
    • AnyRef (root of all objects)
    • AnyVal (root of Int, Long …)

What is the equivalent in Kotlin? This would be a good addition to the documentation, too.


#2

There is no equivalent to AnyRef and AnyVal in Kotlin. The basic types (such as Int) are mapped to the primitive JVM types when it’s possible, and to boxed types (java.lang.Integer etc) in all other contexts.


#3

So a primitive type like Int is a “virtual” subtype of “Any” and treated as primitive int by the compiler whenever possible?


#4

There’s nothing “virtual” about it. From the point of view of the Kotlin type system, it’s a completely regular subtype.


#5

I’m just trying to understand it. If Any is equal to Java’s Object, and Int is a subclass of Any in Kotlin, how can Int being something else than a reference type? Any is a reference type, so all children must be reference types as well. Where does the primitive int come into the game?


#6

From the point of view of Kotlin’s type system, Any is not equal to java.lang.Object, and it is not a reference type. It’s a common supertype of all types, both reference and primitive types.

When Kotlin code is translated to Java bytecode, literal occurrences of Any are translated to java.lang.Object. Occurrences of Int are translated to the int primitive type whenever possible - e.g. when it is a type of a property, parameter or local variable. In these contexts, it doesn’t matter that int is not a subtype of java.lamg.Object.

In contexts where the subtyping relationship does matter - for example, when you’re passing a value of type Int as a parameter to a function that accepts an argument of type Any - the value will be boxed and represented as a java.lang.Integer instance, so the Java subtyping relationship will still hold.


#7

Thanks for the good explanation.


#8

If you do need to know that a type is actually a number there is the kotlin.Number interface that all the kotlin primitive type classes implement with the exception of Boolean.


#9

I’m a bit confused. It says in the “Comparison to Scala” document that Kotlin does not have value types, at least not until Project Valhalla (which I get). But it highlights that Scala does. So what exactly is Scala achieving that Kotlin does not? From what I’ve read, it sounds like AnyVal and AnyRef have been abstracted away by Kotlin, correct? https://kotlinlang.org/docs/reference/comparison-to-scala.html


#10

Scala’s value classes allow you to define new, distinct types that are represented by primitive values on the JVM. Kotlin does not have this capability.


#11

Dmitry, I’m a bit confused in situations with java primitive types/boxed types where I have to convert existing java interfaces into Kotlin (1.0.6) interfaces.
For example, originally in Java I have public interface:

public interface AutoScalingService {
    List<Activity> detachInstances(@Nonnull String autoScalingGroupName, @Nonnull List<String> instanceIdsToDetach,
                                       @Nonnull Boolean shouldDecrementDesiredCapacity) throws AwsToolException;
}

After conversion, this interface will look like:

interface AutoScalingService {
    @Throws(AwsToolException::class)
    fun detachInstances(autoScalingGroupName: String, instanceIdsToDetach: List<String>, shouldDecrementDesiredCapacity: Boolean): List<Activity>
}

But the original implementation of java interface was:

    @Override
    public List<Activity> detachInstances(@Nonnull String autoScalingGroupName, @Nonnull List<String> instanceIdsToDetach,
                                          @Nonnull Boolean shouldDecrementDesiredCapacity) throws AwsToolException {
.............................
}

The thing is that the contract has been broken due to boxed/raw type mismatch.
Is there are any way how to workaround this ? The only visible (and ugly at the same time) way to solve this is to use java.lang.Boolean type explicitly:

....., shouldDecrementDesiredCapacity: java.lang.Boolean): List<Activity>

Official documentation states that there is no such representation for java.lang.Boolean in Kotlin.


#12

Ok, maybe my previous example looks not that critical, but here I have something different and related to generics in Java.
In original Java interface I have method declaration like:

public interface AwsDataTransformationsHelperService {
    List<String> getIpAddressesAcrossAllDescribedStacks(List<StackInfrastructureHolder> describedInfrastructures);
}

Here my method signature not that flexible and type parametrization defined without wildcards.
After conversion into Kotlin (1.0.6) interface, original Java implementation can not be used anymore:

   @Override
    public List<String> getIpAddressesAcrossAllDescribedStacks(List<StackInfrastructureHolder> describedInfrastructures) {
    // .....................................
}

because Kotlin interface required this method signature:

List<? extends StackInfrastructureHolder>

#13

java.lang.Boolean corresponds to Boolean? in Kotlin. This information is indeed missing from the interop docs; we’ll add it.


#14

If you need to preserve the original method signature, use the @JvmSuppressWildcards annotation. See the docs for more information.


#15

Thanks, this is very consistent, IMO!