Importance of var keyword in Kotlin enum class constructor declaration - kotlin

enum class Admin(myName:String, val id:Int, val age:Int){
ROOT_ADMIN ("Pete", 1, 55),
ACADEMIC_ADMIN("Jacob",11,56),
DEPARTMENT_ADMIN("Robin",111,50),
CLASS_ADMIN("Chris",1111,22)
To access the properties of objects of enum class Admin, when I type
Admin.CLASS_ADMIN.____
Naturally, myName to come out in the IDE auto-complete is expected. But its not happening. But id and age does come as they have val keyword associated with them.
But when I add var in front of myName, like:
enum class Admin(var myName:String, val id:Int, val age:Int)
I am now getting myName in auto-complete.
What is the importance of var keyword here?
Note: I am aware of the fact that when we declare variables with var or val keywords in constructor, it declares a property inside that class.
But how this logic relates to this situation?

This is more about Kotlin properties and less about how val/var work with enums. In fact for most of this answer, we can completely ignore the fact that we're even talking about enums, as opposed to any other Kotlin class (but I do have a note at the end on this).
For background, when you create an instance of a class in Kotlin and provide arguments to its constructor, if those arguments have var or val, Kotlin will treat them as properties. If not, it treats them as an argument to the constructor (these can be used in init blocks, for example but do not get turned into properties).
That's what is happening in your case. Kotlin treats myName as a constructor argument and effectively throws it away as you aren't using it. It does not get turned into a property. For id and age, you've specified they are val, so Kotlin turns them into read-only properties.
As for var, when Kotlin sees this it makes them into a read/write property (they can change).
Basically: Kotlin turned id and age into read-only properties and myName was defined as a constructor argument. This is why autocomplete did not offer you myName, it wasn't a property.
Some general advice: I would absolutely not declare any mutable properties on an enum (so, use val only for read-only properties). By using var, you'll get mutable read/write properties. Normally that's fine but with enum specifically there is an expectation that they do not change, ever. You are declaring a fixed set of values (an enumeration of them!) whose internal properties do not change. As a developer if I saw an enum whose internal state was mutable, it would immediately seem wrong.

Since item of enum class is acting like object in Kotlin (just for understanding), if you declare property as var of enum class, you could change the property value and it affects everywhere. This might be hard to understand. You can see below example code.
enum class Test(var a: String) {
A("a"),
B("b");
}
fun main()
{
println(Test.A.a) // a
Test.A.a = "b"
println(Test.A.a) // b
}
Usually, you might not want to declare a property as mutable for the design.

Related

Property must be initialised even though type is defined in Kotlin

I am not sure Stack overflow will like this question. I am learning Kotlin and trying to declare a basic variable without any class.
This is the simplest example.
I now understand why the compiler won't accept it, says it must be initialised. But if I put it inside the main function, then it works fine.
I saw this tutorial on W3Schools and it says you dont have to initialise the variable if you declare its type? Well I have and it still is forcing me to initialise it
https://www.w3schools.com/kotlin/kotlin_variables.php
It's a simple variable in a file no class:
/**
* Number types:
* This is the most important, and we should be able to go over it quick.
* We start from the smallest to the biggest
*/
var byteEg: Byte;
Even inside a class it doesn't work:
class Variables{
var byteEg: Byte;
}
When I try latentinit it gives an exception: 'lateinit' modifier is not allowed on properties of primitive types
What W3Schools fails to mention is that it only holds true for variables that are not top level. So inside functions like
fun someFunction() {
var byteEg: Byte
}
if you want to do it with top level declarations you can mark it as lateinit like
lateinit var byteEg: Byte
The general principle is that everything must be initialised before it's used.*
(This is in contrast to languages like C, in which uninitialised values hold random data that could be impossible, invalid, or cause an error if used; and languages like Java, which initialise everything to 0/false/null if you don't specify.)
That can happen in the declaration itself; and that's often the best place. But it's not the only option.
Local variables can be declared without an initialiser, as long as the compiler can confirm that they always get set before they're used. If not, you get a compilation error when you try to use it:
fun main() {
var byteEg: Byte
println(byteEg) // ← error ‘Variable 'byteEg' must be initialized’
}
Similarly, class properties can be declared without an initialiser, as long as a constructor or init block always sets them.
In your example, you could set byteEg in a constructor:
class Variables2 {
var byteEg: Byte
constructor(b: Byte) {
byteEg = b
}
}
Or in an init block:
class Variables {
var byteEg: Byte
init {
byteEg = 1.toByte()
}
}
But it has to be set at some point during class initialisation. (The compiler is a little stricter about properties, because of the risk of them being accessed by other threads — which doesn't apply to local variables.)
Note that this includes vals as well as vars, as long as the compiler can confirm that they always get set exactly once before they're used. (Kotlin calls this ‘deferred assignment’; in Java, it's called a ‘blank final’.)
As another answer mentions, there's an exception to this for lateinit variables, but those are a bit specialised: they can't hold primitive types such as Byte, nor nullable types such as String?, and have to be var even if the value never changes once set. They also have a small performance overhead (having to check for initialisation at each access) — and of course if you make a coding error you get an UninitializedPropertyAccessException at some point during runtime instead of a nice compile-time error. lateinit is very useful for a few specific cases, such as dependency injection, but I wouldn't recommend them for anything else.
(* In fact, there are rare corner cases that let you see a property before it's been properly initialised, involving constructors calling overridden methods or properties. (In Kotlin/JVM, you get to see Java's 0/false/null; I don't know about other platforms.) This is why it's usually recommended not to call any of a class's non-final methods or properties from its constructors or init blocks.)

Why is a Kotlin enum property not a compile time constant?

The primary target of this question is understanding the implementation and why it is like this. A solution or workaround for it would of course also be highly appreciated...
Given this example:
enum class SomeEnum(val customProp: String) {
FOO("fooProp"),
BAR("barProp");
}
#Target(AnnotationTarget.FUNCTION)
#Retention(AnnotationRetention.SOURCE)
annotation class TheAnnotation(
val targetValue: String
)
#TheAnnotation(targetValue = SomeEnum.FOO.customProp)
fun testFun() {
}
The compilation results in the following error:
SomeEnum.kt: (14, 30): An annotation argument must be a compile-time constant
For obvious reasons, annotation values (along with others) must be compile-time constants, which makes sense in many different ways. What is unclear to me, is why customProp is not treated as a constant by the compiler.
If enums are defined as finite, closed sets of information, they should, in my understanding, only be mutable at compile-time a.k.a. "compile-time constant". For the unlikely case that enums somehow are modifiable at runtime in Kotlin, that would answer the question as well.
Addendum:
The enum value (e.g. SomeEnum.FOO) is actually treated as a compile-time constant. The proof is, that the following slightly changed snippet compiles:
enum class SomeEnum(val customProp: String) {
FOO("fooProp"),
BAR("barProp");
}
#Target(AnnotationTarget.FUNCTION)
#Retention(AnnotationRetention.SOURCE)
#MustBeDocumented
annotation class TheAnnotation(
val targetValue: SomeEnum
)
#TheAnnotation(targetValue = SomeEnum.FOO)
fun testFun() {
}
enums are defined as finite, closed sets of information, they should, in my understanding, only be mutable at compile-time
Actually, no. An enum class is just a special kind of class, that doesn't allow you to create any new instances other than the ones that you name in the declaration, plus a bunch more syntactic sugars. Therefore, like a regular class, it can have properties whose values are only known at runtime, and properties that are mutable (though this is usually a very bad idea).
For example:
enum class Foo {
A, B;
val foo = System.currentTimeMillis() // you can't know this at compile time!
}
This basically de-sugars into:
class Foo private constructor(){
val foo = System.currentTimeMillis()
companion object {
val A = Foo()
val B = Foo()
}
}
(The actual generated code has a bit more things than this, but this is enough to illustrate my point)
A and B are just two (and the only two) instances of Foo. It should be obvious that Foo.A is not a compile time constant*, let alone Foo.A.foo. You could add an init block in Foo to run arbitrary code. You could even make foo a var, allowing you to do hideous things such as:
Foo.A.foo = 1
// now every other code that uses Foo.A.foo will see "1" as its value
You might also wonder why they didn't implement a more restricted enum that doesn't allow you to do these things, and is a compile time constant, but that is a different question.
See also: The language spec
* Though you can still pass Foo.A to an annotation. To an annotation, Foo.A is a compile time constant, because all the annotation has to do, is to store the name "Foo.A", not the object that it refers to, which has to be computed at runtime.

What is the purpose of explicit getters in kotlin?

Using getters and setters is a very well known practice in object oriented languages. This is done in order to have a greater control on the variables. To achieve this, we make the variables private in java and hence we need both getters and setters there.
But in kotlin this is not the case. Here even public variables are accessed through getters and setters by default. Though setters can be used to validate an assignment to a variable, getters just return the variable as it is stored (and I think this is it for them). Hence custom getters are not required at all.
I have also seen some wrong usage of this feature where instead of writing a zero argument function, they use a val and do the computation in the getter. This creates an illusion that the thing is just a val but in reality it does not store anything and instead it performs a computation every time.
So is there a real need to have a custom getter?
getters just return the variable as it is stored (and I think this is it for them). Hence custom getters are not required at all.
If that was really the case, why have getters at all in Java? One of the goals of encapsulation is to make sure a change in the class doesn't change it's API. It's the same in Kotlin.
I have also seen some wrong usage of this feature where instead of writing a zero argument function, they use a val and do the computation in the getter. This creates an illusion that the thing is just a val but in reality it does not store anything and instead it performs a computation every time.
This is a perfectly valid use case for a custom getter. In Kotlin, one must not assume that using a property is entirely free of overhead. There are many questions to ask yourself when choosing between a property with a getter or a zero-arg function:
Does it describe behavior? Use a function (walk(), build(), etc)
Does it describe state? Use a property (firstName, lastIndex, etc)
Additionally, a property getter should not throw an exception, should be either cheap to calculate or cached on first access, and should return the same result for multiple consecutive executions. Here's examples from the standard library:
ArrayDeque.first() is a function, it throws if deque is empty.
List.lastIndex is a property, it's cheap to calculate.
Lazy<T>.value is a property, the value is computed and cached on first access.
Most delegated properties make use of custom getters.
More reading:
Why use getters and setters/accessors?
Kotlin: should I define Function or Property?
Just some more info. Other than readability, the possibility of defining a custom getter allows you to evolve a class without changing its public members, even if you started with a simple val with no custom getter.
In a language without properties like Java, if you define a public field:
public class Foo {
public final int value;
public Foo(int value) {
this.value = value;
}
}
And then later you want to modify the class to add a feature where it returns negated values if you flip a Boolean, there's no way to do it without breaking code that uses the original version of the class. So you should have used getters and setters to begin with.
But in Kotlin, you can't directly expose a backing field like this, so it's impossible to paint yourself in a corner like you could with a public field in Java. If your original class is like this:
class Foo(val value: Int)
You could modify it like this to add the feature and have no impact on code that already uses the class.
class Foo(private val originalValue: Int) {
var isNegated = false
val value: Int
get() = if (isNegated) -originalValue else originalValue
}

What is the purpose of empty class in Kotlin?

I was going through Kotlin reference document and then I saw this.
The class declaration consists of the class name, the class header
(specifying its type parameters, the primary constructor etc.) and the
class body, surrounded by curly braces. Both the header and the body
are optional; if the class has no body, curly braces can be omitted.
class Empty
Now I'm wondering what is the use of such class declaration without header and body
Empty classes can be useful to represent state along with other classes, especially when part of a sealed class. Eg.
sealed class MyState {
class Empty : MyState()
class Loading : MyState()
data class Content(content: String) : MyState()
data class Error(error: Throwable) : MyState()
}
In this way you can think of them like java enum entries with more flexibility.
tldr: they want to demonstrate it's possible
even an empty class is of type Any and therefore has certain methods automatically. I think in most cases, this does not make sense, but in the documentation case it's used to show the simplest possible definition of a class.
The Java equivalent would be:
public final class Empty {
}
From practical programmer day to day perspective empty class makes no much sense indeed. There are however cases where this behavior is desirable.
There are scenarios where we want to make sure that we want to define a class and at the same time, we want to make sure that instance of this class will never be created (type created from such class is called empty type or uninhabited type).
Perfect example of this is Kotlin Nothing class with do not have class declaration header and body (notice that it also have private constructor)
https://github.com/JetBrains/kotlin/blob/master/core/builtins/native/kotlin/Nothing.kt
There are few usages for Nothing in Kotlin language. One of them would be a function that does not return a value (do not confuse this with Unit where the function returns actually returns a value of type Unit). A typical example is an assertFail method used for testing or method that exits current process. Both methods will never actually return any value yet we need to explicitly say tell it to a compiler using special type (Nothing).
fun assertFail():Nothing {
throw Exception()
}
Nothing can be also used with start projections where type Function<*, String> can be in-projected to Function<in Nothing, String>
Another usage for empty class is type token or placeholder:
class DatabaseColumnName
class DatabaseTableName
addItem(DatabaseColumnName.javaClass, "Age")
addItem(DatabaseTableName.javaClass, "Person")
...
getItemsByType(DatabaseTableName.javaClass)
Some languages are using empty classes for metaprogramming although I haven't explored this part personally:
Advantages of an empty class in C++
An example of empty class usage from Spring Boot framework:
#SpringBootApplication
class FooApplication
fun main(args: Array<String>) {
runApplication<FooApplication>(*args)
}
It doesn't make much sense as a final result. However it can be useful in active development and at a design time as a placeholder of some sort, which may be expanded in the future. Such terse syntax allows you to quickly define such new types as needed. Something like:
class Person (
val FirstName: String,
val LastName: String,
// TODO
val Address: Address
)
class Address
I think main reason this is specifically mentioned in documentation is to demonstrate, that language syntax in general can be terse, not that it is specifically created for common usage.
Sealed classes, in a sense, an extension of enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances which can contain state.
reference

Is a private 'property' a 'field'?

Looking into properties in Kotlin, this concept is a somewhat new to me so I'm curious, is it legitimate to state that a private property is a field (instance variable)?
You can consider properties as values that you can get (and set for mutable ones), but they can have custom and overridable behaviour and might not be actually stored. So properties are not fields.
In Kotlin, all member properties, private or not, can have a backing field, but it is not necessary.
Property with a backing field:
var counter = 0
Here, 0 is put into the backing field, and the property behaves like a field: getting a value from it returns the value stored in the field, setting a value to it just stores the value into the backing field. But it's not a field, e.g. for Java it will still be a pair of getter and setter.
Private properties with no custom accessors are optimized and compiled into fields to avoid function call overhead, but it's rather an implementation detail, and adding a custom accessor will also change the bytecode that accessing the property is compiled into.
var counter = 0
get() = field + 1
set(value) { if (value >= 0) field = value }
Here again the property has a backing field, but its behaviour is different, custom accessors get() and set(...) will be executed in statements like counter = something or val x = counter. This is true for accessing the property both from within and from outside the class, and private properties are not different here.
The backing field can be accessed directly only inside the accessors code by a soft keyword field, it is not exposed to the other code. If you want to access the backing value from somewhere else, you have to define another backing property. You can expose a backing field to Java code by adding #JvmField annotation to the property (this won't make it accessible from Kotlin).
Property without a backing field
When a property has no initializer and has at least get(), it is a property with no backing field:
val time: Long get() = System.currentTimeMillis()
No backing field will be generated for it, but you can use another property as a backing property as stated above.
Properties with no backing field can also be extension properties, which is quite far from fields:
val String.isCapitalized: Boolean get() = length > 0 && this[0].isUpperCase()
These can also be private, but it will have different semantics.
No because "classes in Kotlin cannot have fields" (Properties and Fields - Kotlin Programming Language).
In addition, "if you need to expose a Kotlin property as a field in Java, you need to annotate it with the #JvmField annotation" (Calling Kotlin from Java - Kotlin Programming Language). It still isn't a field though.
As Kotlin classes do not have fields it is best to always refer to properties as properties.