Meaning of val / var when using Kotlin Primary constructor - kotlin

I have seen Kotlin-examples using a Primary-constructor like this:
class Person(firstName: String, lastName: String) {}
And I have seen example with the var or val keyword, like this:
class Person(val firstName: String, val lastName: String) {}
What the difference? When do I have to use which variation?

Regarding the documentation, with var or val in the constructor you create a property in the class. If you do not write it, then it is only a parameter that is passed to the constructor. As an example:
class Person(val firstName: String, lastName: String) {
// firstName and lastName accessible
fun getFirstName() = firstName // firstName accessible
fun getLastName() = lastName // lastName not accessible
}
So if you want to continue to use the firstName and lastName, I would make a property out of it.

Related

Why can't you change a property value permanently in kotlin?

Here's the code:
class Person(var firstName: String, var lastName: String) {
var fullName: String = firstName + lastName
fun fullName() = firstName + lastName
override fun toString(): String {
return fullName()
}
}
fun main(){
val test = Person("test", "fortest1")
test.lastName = "fortest2"
println(test.fullName)
}
The result will only be testfortest1.
It looks like you are working with a copy of test once test is created.
This is because fullName is not observing any changes to firstName or lastName. It is initialized when Person is created and stays the same unless explicitly modified.
One easy fix for this is to provide a custom getter like this:
val fullName get() = firstName + lastName
Now it will work as you expect because everytime you read fullName that expression will be evaluated and the result will be returned.
(Also, prefer using vals over vars in data class fields)

Why class member property reflection in Kotlin?

In 'Kotlin in Action', it says "if a memberProperty refers to the age property of the Person class, memberProperty.get(person) is a way to dynamically get the value of person.age" with code(10.2.1 The Kotlin Reflection API):
class Peron(val name: String, val age: Int)
>> val person = Person("Alice", 29)
>> val memberProperty = Person::age
>> println(memberProperty.get(person))
29
I can't understand why this example refers to "dynamically" getting the value of property. It just works when I run this code:
println(person.age)
Is there any other case or example of member property reflection?
For example, say you want to write a function which prints all the properties of an object along with their values, this is how you can do that:
inline fun <reified T: Any> T.printProperties() {
T::class.memberProperties.forEach { property ->
println("${property.name} = ${property.get(this)}") // You can't use `this.property` here
}
}
Usage:
data class Person(val firstName: String, val lastName: String)
data class Student(val graduate: Boolean, val rollNumber: Int)
fun main() {
val person = Person("Johnny", "Depp")
val student = Student(false, 12345)
person.printProperties()
student.printProperties()
}
Output:
firstName = Johnny
lastName = Depp
graduate = false
rollNumber = 12345

Why to put val or var in kotlin class constructors

Just learning Kotlin In the first code down below there is the val keyword right in the other code there is not,
what is the different here if the val and var is omitted?
class Person(val firstName: String, val lastName: String) {
}
class Person(firstName: String, lastName: String) {
}
If val or var is omitted then they won't be properties, but parameters passed to constructor. You won't be able to work with them outside of constructor.
If you omit val or var in in a constructor, then the only places that can access these parameters are initialization statements that are evaluated at construction time. See https://kotlinlang.org/docs/reference/classes.html
This is useful when you want to do something with a value before storing it. In Java you would put that code a constructor body
class Person(firstName: String, lastName: String) {
// directly in val / var declarations
val firstName = firstName.capitalize()
val lastName = lastName
// in init blocks
val fullName: String
init {
fullName = "$firstName $lastName"
}
// secondary constructors can only see their own parameters
// and nothing else can access those
constructor(fullName: String) : this("", fullName)
}
But it also works for delegation using by
interface Named {
fun getName(): String
}
class Human(private val fname: String, private val lname: String) : Named {
override fun getName() = "$fname + $lname" // functions need val since
// value is resolved after construction
}
class Person2(firstName: String, lastName: String) : Named by Human(firstName, lastName)
class Person3(human: Human) : Named by human {
constructor(firstName: String, lastName: String): this(Human(firstName, lastName))
}
Or in property delegation
class Person4(firstName: String, lastName: String) {
val fullName: String by lazy { "$firstName $lastName" }
}
Note: the closure is captured at initialization time, the values are therefore still available when lazy evaluates eventually.

What is the difference between properties and parameters in Kotlin?

Here is a simple example of a class with some code (properties) inside the bracket
class Person(firstName: String) {
....
}
Now here is an example of a function with some code (parameters) inside the bracket
fun double(x: Int) {
...
}
I know this is a fundamental question but I am quite confused as a beginner.
You pass parameters to functions and constructors, and classes have properties.
The constructor of the Person class in your example has a single parameter, and so does the double function. In this case, the firstName parameter is not a property!
To make it a property, you have to declare it so:
class Person(firstName: String) {
val firstName : String = firstName
}
Kotlin allows this to be shorter, which makes the firstName parameter serve as a property:
class Person(val firstName: String)
First, your firstName also is a parameter rather than a property in Person class.
// v-- a parameter declared on primary constructor
class Person(firstName: String)
you can access a parameter declared on primary constructor in init block or property/field declaration, for example:
class Person(firstName: String){
val first:String
init{ first=firstName }
}
class Person(firstName: String){
val first:String = firstName
}
class Person(firstName: String){
#JvmField val first:String = firstName
}
to make the firstName to a property you can using keyword val or var, for example:
// v--- immutable property
class Person(val firstName: String)
// v--- mutable property
class Person(var firstName: String)
a Kotlin property will generate getter/setter(?) and a backing field(?) to java byte code. Take an example of a mutable property to java byte code as below:
public final class Person{
private String firstName; // backing field
// v--- parameter
public Person(String firstName){ this.firstName = firstName; }
//getter
public final String getFirstName(){ return firstName; }
//setter
public final String setFirstName(String firstName){ this.firstName= firstName; }
}
a parameter only visible in function scope/constructor scope except parameter declared on primary constructor.
Note: a parameter is immutable like as java effective-final variables/parameters, so you can't reassign a parameter at all in Kotlin, for example:
fun foo(bar:String){
bar = "baz"
// ^--- compile error
}
properties and parameters are different thinks:
parameters : when we declare any function :
fun sum(a: Int, b: Int): Int {
return a + b
}
Function having two Int parameters with Int return type:
Properties and Fields:
Declaring Properties
Classes in Kotlin can have properties. These can be declared as mutable, using the var keyword or read-only using the val keyword.
class Address {
var name: String = ...
var street: String = ...
var city: String = ...
var state: String? = ...
var zip: String = ...
}
To use a property, we simply refer to it by name, as if it were a field in Java:
fun copyAddress(address: Address): Address {
val result = Address() // there's no 'new' keyword in Kotlin
result.name = address.name // accessors are called
result.street = address.street
// ...
return result
}
The full syntax for declaring a property is:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]

Empty second ctor in Kotlin

data class UserRto(val lastName: String, val firstName: String, val email: String, val password: String) {
constructor() : this("", "", "", "")
}
Is this the easiest way to get a second ctor without arguments (for json desrialization)?
There is a convention (just for that case :) that a parameterless constructor is generated if all parameters have default values:
//Kotlin
data class UserRto(val lastName: String = "",
val firstName: String = "",
val email: String = "",
val password: String = "")
//Java
new UserRto();
new UserRto("a", "a", "a", "a");
Your solution with an explicit empty constructor has an advantage that all parameters must be provided, or non. But it is not a big deal in most cases and it is rarely used.
You do not specify which JSON deserialization library you are using. It is likely that you do not need this secondary constructor at all and can work directly with the class constructor that contains all of the properties as parameters.
For Jackson, use the Jackson-Kotlin module which automatically handles all of Kotlins unqiue cases including ability to call a constructor or factory with all of the parameters being properties (and in 2.8.x this includes default values for parameters being used for missing properties in the JSON)
For Gson, I think Kotson might do the same.
Google might find others for these or other libraries as well.
Then you would only need:
data class UserRto(val lastName: String, val firstName: String, val email: String, val password: String)
And with the Jackson-Kotlin module you would simply:
val user: UserRto = jacksonObjectMapper().readValue(jsonString)