Is it possible to enforce the value of a property to be obtained only by another class?
I have val itemValue by ItemValueDelegator() and ItemValueDelegator returns an enum (ItemValue) after some business rule logic.
can I enforce somehow that the value of itemValue is always obtained from ItemValueDelegator?
I want to make impossible to do: val itemValue = ItemValue.STOCK
val modifier already makes it impossible to assign new value to it. Calls on itemValue will only call getValue() function in the ItemValueDelegator. What you can do is hide the enums within the class of the delegate and make the itemValue hold the ordinal.
Edit:
You need to perform runtime validation. In the init block should check if the itemVal is provided by a delegate. That involves using kotlin-reflect and checking that underlying KProperty delegate is of type ItemValueDelegator or null, if isn't, just throw error("itemValue should be provided by ItemValueDelegator")
Related
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.
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
}
I need to get and set a property of another class from a method and therefore need to pass in either the property reference of lambdas for the getter and the setter:
Passing in the property reference
otherInstance::property
Passing in a lambda for the getter and one for the setter:
{otherInstance.property} // getter
{value -> otherInstance.property = value} // setter
I like the first one, because for me the code is easier to read and shorter, but my alarm bells ring when I read about it on the official documentation, because of the term "reflection". My knowledge from Java is that reflection generally isn't a good thing. Is that also valid with Kotlin? Is it valid with this case? Is one of both ways (property reference or lambdas) more performant or more safe?
By using KMutableProperty0 you would technically be exposing an object that can be used for reflection. If you want to be strict about avoiding reflection, you could use the separate function references for the getter and setter. Note that it's not necessary to pass a lambda as a function reference to a higher-order function. The compiler can interpret property references as functions if the effective signature matches. This would unfortunately mean having to pass the property reference twice. Unfortunately, the setter has to be retrieved via what is technically reflection in this case:
class Test (var x: Int)
fun foo(getter: () -> Int, setter: (Int) -> Unit) {
//...
}
val test = Test(1)
foo(test::x, test::x.setter)
// Zero reflection call:
foo(test::x) { test.x = it }
At some point you have to question how badly you want to avoid reflection, because the above code looks very messy to me. If your class takes a KMutableProperty0 reference, it is much simpler to use. As long as your receiving function isn't using the reference to introspect the code, and only calls get() or set() on it, you are not really using reflection in the ways that are suggested should be avoided.
fun foo(property: KMutableProperty0<Int>) {
//...
}
val test = Test(1)
foo(test::x)
The documentation is about Member references and reflection,
If you are referring to Property references which isn't using reflection itself,
Reflection is only referred in different section Obtaining member references from a class reference
dynamically inspect an object to see e.g. what properties and functions it contains and which annotations exist on them. This is called reflection, and it's not very performant, so avoid it unless you really need it.
Kotlin has got its own reflection library (kotlin-reflect.jar must be included in your build). When targeting the JVM, you can also use the Java reflection facilities. Note that the Kotlin reflection isn't quite feature-complete yet - in particular, you can't use it to inspect built-in classes like String.
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.
I am learning from Stanford's CS193P course. In the class, Paul has a demo project, "Calculator", where he uses id as the type of a property. He intends to not use a specific class, because he does not want to create a new class and then he does not need to write documentation, and even when it is updated, he does not need to redesign the class. id can solve all these problems.
Is this a really a good way? id is the return type of the property, and used as the parameter type of another method. How does the caller know what id is, and how to provide the correct object? By reading code comments?
In general, is there any good reason to use id as a return type or parameter type in public API? (Except init and factory method, though even for those, instancetype is recommended.)
If your method returns a class that is a member of a class cluster, you should return id.
If you're returning an object whose class is opaque, isn't declared in a public header, you should return id. (Cocoa occasionally uses such objects as tokens or context data.)
Container classes should always accept and return their constituents as ids.