Having a interface defined:
interface IData {
fun getHash() : Int
fun getUUID(): UUID
......
}
Trying to create object for the interface. the fun getUUID(): UUID is fine, but the fun getHash() : Int got error as below.
What might be wrong? why they are different?
fun buidlDataList () : ArrayList<IData> {
val dataList = ArrayList<IData>(0)
dataList.add(object : IData {
val hash: Int by lazy { dataFetchers.size+System.currentTimeMillis().toInt() } //<=== get error
override fun getHash(): Int { //<=== get the same error
return hash
}
val uuid: UUID by lazy { UUID.randomUUID() }
override fun getUUID(): UUID {
return uuid
}
......
}
}
Platform declaration clash: The following declarations have the same JVM signature(getHash() I):
* public final fun <get-hash>(): int defined in com.data. buidlDataList <no name provided>
* public open fun getHash(): int defined in defined in com.data. buidlDataList <no name provided>
The variables create their own getters, but you also explicitly define them. When you declare a var or a val, they usually have their own getters automatically generated1. Private vals or vars don't, if you don't create a custom getter.
But in all other cases, this:
val x: Int = TODO()
generates a getter1.
In your case, I'd recommend using val in the interface directly. You see, the generated getter has the same name as the getHash method you explicitly declared. The getters don't override methods either (unless you annotate it with one of the #Jvm annotations, and I don't remember which, but you don't really need those anyways).
So you change your interface to:
interface IData {
val hash: Int
val uuid: UUID
}
And remove the getters in the overridden object, and add override to the vals:
dataList.add(object : IData {
override val hash: Int by lazy { dataFetchers.size+System.currentTimeMillis().toInt() }
override val uuid: UUID by lazy { UUID.randomUUID() }
}
The first interface is actually equivalent to declaring an interface with get and set methods. If you override it from Java, it will ask you to override getHash() and getUid(), and you need to declare the field locally. Kotlin works differently because it automatically generates setters.
And since you can declare variables in interfaces without messing up Java interop, I highly recommend you use that over #Jvm* annotations (mainly because it makes it easier to understand the code, though that's a personal preference).
Also, if you decompile the Kotlin bytecode, you'll see what the interface with the variables compiles to:
public interface IData {
int getHash();
#NotNull
UUID getUuid();
}
So it's identical to the one you originally had, just without conflicts in child classes because of variable name clashes.
And the reason only one has a clash is because, as you see in the interface, val uuid creates a getter named getUuid, while your interface declares getUUID. Methods in Java and Kotlin are case-sensitive, which is why those don't clash. If you re-name your variable to upper-case UUID, you will get a clash on that too.
1: Assuming the variable/constant isn't in a method. Top-level variables, variables in interfaces, enums, classes, objects, and companion objects all generate getters/setters, but if you declare a variable inside a method, it naturaly won't have getters and setters where that applies.
Related
I'm trying this:
class Foo<T> {
var member: T = T()
}
...but the Kotlin compiler gives me an error: Type parameter T cannot be called as function.
How do I default-construct a generic member variable?
Well, to access the type information, we need to use the reified keyword on the type, but this is only applicable in inlined functions. So instead of relying on direct construction, a workaround can be to use a generator function wrapped in the companion object that immediately sets the member right after construction
// Test class to verify the implementation
class Yolo {
override fun toString() = "Yolo swag"
}
class Foo<T : Any> {
lateinit var member: T
companion object {
inline fun <reified T : Any> newInstance() =
T::class.java.newInstance().let { memberInstance ->
Foo<T>().apply { member = memberInstance}
}
}
}
fun main() {
// generate a Foo<Yolo>
val foo = Foo.newInstance<Yolo>()
println(foo.member) // displays "Yolo swag"
}
It's implied that T has a public no-arg constructor, but in general case it may not be true. This code uses reflection to bypass compiler complains about it (which may end up with runtime error if you dissapoint the JVM expectations and indeed pass T without public no-arg constructor).
//Reified generics at class level are not yet supported in Kotlin (KT-33213),
// so you have to pass instance of `KClass` manually as a consructor parameter
class Foo<T : Any>(clazz: KClass<T>) {
var member: T = clazz.createInstance()
}
So I have an abstract class Composition, which has two children: one is a Track, and one is an Album (which is a group of Tracks).
class Composition(val name: String, ...)
class Track(name: String): Composition(name)
class Album(name: String, val tracks: List<Track>): Composition(name)
So far, so good. Now, I have the duration that is added. It is abstract in Composition, so I can override it in the children:
abstract class Composition(...){
abstract fun getDuration(): Int
}
Now, I can add override the method in the Track, which takes it as a parameter:
class Track(..., private val duration: Int): Composition(...){
override fun getDuration() = duration
}
And finally, I make the Album, whose duration is the sum of the Tracks:
class Album(..., val tracks: List<Track>): Composition(...){
override fun getDuration() = tracks.sumBy { it.getDuration() }
}
It works as intended, but I do not understand why I cannot simply use tracks.sumBy { it.duration }, since in Kotlin properties are nothing more than getters and setters (I'm thinking about the getDuration in Composition).
I feel like I'm missing something, because if the same code was written in Java, I would be able to call composition.duration as a property -- so that makes me think that Kotlin allows it from Java code, but not from Kotlin code, which is sad.
An other example:
Let's say I have a class named Artist, who wrote multiple Compositions:
class Artist(
val nom: String,
private val _compositions: MutableList<Composition> = ArrayList()
) {
// HERE (I wrote the extension method List<E>.toImmutableList)
fun getCompositions() : List<Composition> = _compositions.toImmutableList()
}
This is standard in Java (exposing immutable versions of Collections via getters, so they are not modified) ; Kotlin doesn't recognize it though:
val artist = Artist("Mozart")
artist.getCompositions() // Legal
artist.compositions // Illegal
I thought about making this a property, but:
- If I choose the type List<E>, I can override the getter to return the immutable list, but I cannot use regular methods (add...) as the List is immutable
- If I choose the type MutableList<E>, I cannot override the getter to return ImmutableList (which is a subclass of List that I wrote, and is obviously not a subclass of MutableList).
There's a chance I'm doing something ridiculous while there is an easy solution, but right now I cannot find it.
In the end, my question is: Why aren't manually-written getters considered properties when written from Kotlin?
And, if I'm mistaking, What is the expected way of solving both of these patterns?
If you want to use it as property, you should use Kotlin-way to override getter.
For example:
abstract class Composition(...){
abstract val duration: Int
}
// You can use "override" in constructor
// val - is immutable property that has only getter so you can just
// remove private modifier to make possible get it.
class Track(..., override val duration: Int): Composition(...){
...
}
class Album(..., val tracks: List<Track>): Composition(...) {
override val duration: Int
get() = tracks.sumBy { it.duration }
}
Also there are may be case when you need mutable property that can be changed only inside of object. For this case you can declare mutable property with private setter:
class SomeClass(value: Int) {
var value: Int = value
private set
}
Read more in docs: https://kotlinlang.org/docs/reference/properties.html#getters-and-setters
You have to define duration as an abstract property and not as an abtract function (https://kotlinlang.org/docs/reference/properties.html#getters-and-setters):
abstract class Composition(val name: String) {
abstract val duration: Int
}
class Track(name: String, override val duration: Int): Composition(name)
class Album(name: String, val tracks: List<Track>): Composition(name) {
override val duration: Int
get() = tracks.sumBy { it.duration }
}
The getter/setter conversion as properties does only work for Java classes (https://kotlinlang.org/docs/reference/java-interop.html#getters-and-setters).
Kotlin provides support for property overriding. I an wondering what is the best way to override a property as a constant value.
To be more specific, assume that an abstract val property is declared in a superclass or an interface:
// In a superclass or an interface
abstract val num : Int
In its subclass there are at least 2 ways as far as I can think of to override it:
// In its subclass
override val num : Int = 0
or
// In its subclass
override val num : Int get() = 0
Besides the two, I can also do it in the Java way:
// In a superclass or an interface
abstract fun getNum() : Int
// In its subclass
override fun getNum() : Int = 0
What's the difference among the three in terms of memory and generated bytecode? Which one is the best?
Are there even better ways or patterns in Kotlin to declare properties that are to be overridden as constants?
There's functional difference.
Using assignment You initialize the field when object is created:
override val num : Int = 0
This creates an implicit final backing field with value 0, and getter that always returns same value. This is generated bytecode decompiled into java:
private final int num;
public int getNum() {
return this.num;
}
Second declaration is actually a getter override, which is also a valid way to implement property from the interface. This does not create a backing field, so your property can return different values on each call (for example method call):
override val num : Int get() = 0
Decompiled bytecode:
public int getNum() {
return 0;
}
When running spotbugs on a Kolin project I get errors such as:
[ERROR] Private method com.example.CSVRecord.component1() is never called [com.example.CSVRecord] In CSVRecord.kt UPM_UNCALLED_PRIVATE_METHOD
on classes such as:
data class CSVRecord(private val columns: SortedSet<CSVColumn>) : Iterable<String> {
override fun iterator(): Iterator<String> {
return columns.map { it.value }.iterator()
}
}
I'm not really clear where component1 came from!
According to the Data Classes documentation:
The compiler automatically derives the following members from all
properties declared in the primary constructor:
equals()/hashCode() pair;
toString() of the form "User(name=John, age=42)";
componentN() functions corresponding to the properties in their order of declaration;
copy() function (see below).
This is one the features of data classes. The auto-generated componentN functions allow you to use Destructuring Declarations on this type of classes:
data class Result(val result: Int, val status: Status)
fun function(...): Result {
// computations
return Result(result, status)
}
// Now, to use this function:
val (result, status) = function(...)
Since kotlin has such good support for lambdas, I started to use lambdas as constructor parameters for abstract classes instead of declaring abstract val/fun.
It's more concise in my opinion, especially because val type get's inferred.
What are the downsides to this?
abstract class AbstractListScreen<T> (
val data: Set<T>,
val filterators: (T) -> Set<String>
) {
fun open() {
/* ... */
}
}
class OrderListScreen : AbstractListScreen<Data>(data = setOf(),
filterators = { setOf(it.toString()) }
) {
fun someEvent() {
/* ...*/
}
}
In your example, each instance of OrderListScreen will create its own filterators instance of function type (T) -> Set<String>. This has additional run-time overhead in both memory and performance when compared with abstract functions and their overrides which are stored in the type definition at compile-time.
The default filterators can be stored in a property to reduce this run-time overhead:
class OrderListScreen : AbstractListScreen<Data>(data = setOf(),
filterators = defaultFilterators
) {
companion object {
val defaultFilterators: (Data) -> Set<String> = { setOf(it.toString()) }
}
fun someEvent() {
/* ...*/
}
}
However, each instance of OrderListScreen will still have its own reference to defaultFilterators which is still additional run-time overhead (although marginal unless you have many instances of these types).
Function types such as (T) -> Set<String> may have named parameters (e.g. (element: T) -> Set<String>) but currently IDEs such as IntelliJ IDEA do not use those named parameters in generated documentation or code stubs so such information is lost when subclassing, etc. IDEs do use named parameters in generated documentation and code stubs for abstract functions.
You cannot (currently) associate documentation directly with the function type parameter which you can do with abstract functions.
When attempting to account for the run-time overhead the code doesn't look much different when using abstract functions, the run-time overhead is eliminated, and current IDE support for generated code stubs, documentation, etc. is improved:
abstract class AbstractListScreen<T>(val data: Set<T>) {
abstract fun filterators(element: T): Set<String>
fun open() {
/* ... */
}
}
class OrderListScreen : AbstractListScreen<Data>(data = setOf()) {
override fun filterators(element: Data): Set<String> = setOf(element.toString())
fun someEvent() {
/* ...*/
}
}