Dose Kotlin have primitive types?

Does Kotlin have primitive types?. And I feel confused with two questions:
1/ When I declare the variable: val myAge: Int = 18 then the myAge variable stores the actual values is 18 or stores the addresses of the objects in the memory?.
2/ If Int is primitive type when I declare val myAge: Int = 18 then why we can use its method like myAge.toString() ?

No, it does not.

Please refer to official documentation: https://kotlinlang.org/docs/reference/comparison-to-java.html#what-java-has-that-kotlin-does-not

1 Like

Kotlin does have an unified type system where JVM primitives are used only as implementation detail. You shouldn’t bother with primitives as long as you don’t implement some kind of performance critical algorithms.

2 Likes

Also remember that JVM is only one of several Target platforms for Kotlin. On some of them the term primitive type is unknown (which does not mean there cannot be similar optimizations under the hood on those platforms).

So, Kotlin the language does not know primitive types. But the platform might have them or similar optimizations.

3 Likes

Primitives are a silly construct, which Kotlin does not attempt to bring in from Java. Everything in Kotlin is a class and Int is no exception, leading to a completely unified type system where everything inherits from Any. On Kotlin/JVM, when it is possible, the types that correspond to the Java primitives are compiled using the primitives, and when it is not, the class is used instead. In other words, you should not worry about primitives on the code side (because they don’t exist) and you should not worry about primitives on the implementation side (because they are handled automatically).

3 Likes

Two points.

First, I disagree that primitives are a silly construct. While I prefer Kotlin’s approach, the implementation was not as well understood back when Java was first developed, and primitives were a natural way to provide optimized run-time performance. See my JavaWorld article A case for keeping primitives in Java for details.

Second, even Kotlin provides some support for primitives in that one can use DoubleArray instead of Array<Double> when run-time performance is critical. Does it make a difference? Again, see section 2 “Single type system (almost)” of my second JavaWorld article Why Kotlin? Eight features that could convince Java developers to switch for details.

The only valid reason for primitives is performance (and the implementation detail that arithmetic operators only work on primitives - there are no intrinsics for the wrappers).

At the same time the primitives/objects distinction creates an inconsistency. They create a type systems where some times exist both as (immutable) reference types and value types and others as reference type only. Java addresses this by giving the boxed and unboxed versions of primitives different names. Kotlin does this by having the compiler “figure it out” and use primitives where possible.

The basis for the problem is the fact that on the JVM all objects are managed by reference (note that it may optimize this away when jitting), but that references are completely invisible. In many ways references have many advantages especially with polymorphism (because while the object sizes change, the reference size is independent of the type), but performance is not one of them. Identity semantics also seem to confuse people (two variables actually referring to the exact same object/aliassing). If you want full value semantics you end up needing a lot more compile time variance, the like of templates that C++ uses. This because for value types you need to adjust the code for the concrete type, and generic code has this issue.

On a virtual machine such as the JVM the bytecode is however sufficiently expressive that the JVM can do a lot of this code adjustment on demand. In that sense Project Valhalla inline types (was value types) seem to be interesting but nowhere near release. Inline/value types also create a consistent experience taking away the main drawback of primitives.

First, I disagree that primitives are a silly construct

They are a silly construct, why?.
Because a struct and a class with the same content should encode the same value, making them different is not meaningful because a value should be location and implementation dependent.
Deciding a type to be a value type or a reference type at the definition side is bad idea, it should be more a property of the binding or if not possible a property of a type on the call site.

For example:

class A
{
...
}

fun f(a:A){...} /*or*/  fun f(a:ref A)//a is a reference type
fun f(a:copy A){...} //a is a value type supporting a is compared with ==
fun f<T>(t:T){...} //T could be a value -or reference type
fun<copy A>(a) //T is a value type
fun<A>(a) //T is a reference type

copy states that mutations cannot be in-place, i.e. objects have to be copied and then mutated in place and that for each mutation.
Furthermore a instanceof copy A is equivalent to a instanceof A, because copy is an attribute of the type concerning only the variables of that type but not the semantic of the type itself.

Note: Value types (including primitive types) don’t say anything about boxing/unboxing, likewise where a value might be represented (heap,stack,register).