I came across the following Kotlin code for an enum:
enum class Section(val position: Int, val textKey: Int, val fragment: Fragment) {
GUIDE(0, R.string.main_pager_guide, QotGuideFragment()),
LEARN(1, R.string.main_pager_learn, QotLearnFragment()),
ME(2, R.string.main_pager_me, QotToBeVisionFragment()),
PREPARE(3, R.string.main_pager_prepare, QotPrepareFragment()),
;
}
However, when I review the Kotlin docs on enums, I don't see anything in it that shows this kind of syntax. The line:
GUIDE(0, R.string.main_pager_guide, QotGuideFragment())
I don't understand how these 3 parameters are used. Also, the enum class Section shows 3 constructor parameters that don't appear to be used.
The official docs on enum are at:
https://kotlinlang.org/docs/reference/enum-classes.html
From https://kotlinlang.org/docs/reference/enum-classes.html:
Each enum constant is an object
so GUIDE is an instance of Section class, meaning an object initialized as
GUIDE(0, R.string.main_pager_guide, QotGuideFragment())
You can get the values that initialized GUIDE, like this:
val guidePosition = Section.GUIDE.position
val guideTextKey = Section.GUIDE.textKey
val guideFragment = Section.GUIDE.fragment
usually your enums will be like that
enum class Section() {
GUIDE,
LEARN,
ME,
PREPARE
}
without any parameters
but in your example the base constructor of the enum has parameters that are set as properties also
enum class Section(**val** position: Int, **val** textKey: Int, **val** fragment: Fragment)
with the keyword val in the constructor you set as property of the class
then it has
GUIDE(0, R.string.main_pager_guide, QotGuideFragment()),
LEARN(1, R.string.main_pager_learn, QotLearnFragment()),
ME(2, R.string.main_pager_me, QotToBeVisionFragment()),
PREPARE(3, R.string.main_pager_prepare, QotPrepareFragment())
so for GUIDE 0 -> position, R.string.main_pager_guide -> textKey and QotGuideFragment -> fragment
Related
guys, I am learning kotlin. From https://kotlinlang.org/docs/interfaces.html#properties-in-interfaces it says:
Properties declared in interfaces can't have backing fields, and
therefore accessors declared in interfaces can't reference them.
(I think the pronoun "them" at the end of quoted sentence should refer to "properties" rather than "fields". )
However the following code works. It seems that we can refer to properties. Why is print(prop) highlighted as red then?
interface MyInterface {
val prop: Int // abstract
val propertyWithImplementation: String
get() = "foo"
fun foo() {
print(prop) // this is highlighted red but it works. what's does the author want to say?
}
}
class Child : MyInterface {
override val prop: Int = 29
}
fun main() {
val c = Child()
c.foo()
}
Besides, I noticed that in the above example foo is not accessor. So I tried following example and it works too:
interface User {
val email: String
val nickname: String
get() = email.substringBefore('#') // aren't we referring to a property in accessor? why does this work then?
}
So what does the author want to say in here? what does "them" refer to?
"Them" in this sentence means "fields".
Property is basically a getter (setter) and it could be optionally backed by a field. For technical reasons interfaces can't hold fields, so properties in interfaces have to be "fieldless". Property has to be either abstract or its implementation can only use e.g. other properties/functions, but it can't store/read any data directly. Note that referencing other properties does not break above rule, because, as I said, property is mainly a getter/setter, not a field.
print(prop) is highlighted as red, because... well, this is how automatic highlighter colored it... :-)
I'm trying to convert my Android library to a Kotlin multiplatform library.
One of the things I want to preserve are all the android specific annotations for Android Lint. I was able to convert most of them by doing simple things like
#MustBeDocumented
#Retention(AnnotationRetention.BINARY)
#Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.CLASS,
AnnotationTarget.VALUE_PARAMETER
)
expect annotation class MainThread()
actual typealias MainThread = androidx.annotation.MainThread
This did not work with RestrictTo because it takes an argument.
The android RestrictTo annotation looks like
#Retention(CLASS)
#Target({ANNOTATION_TYPE,TYPE,METHOD,CONSTRUCTOR,FIELD,PACKAGE})
public #interface RestrictTo {
/**
* The scope to which usage should be restricted.
*/
Scope[] value();
enum Scope {
}
}
I cannot seem to make the compiler happy with the type for value.
If I make the expect look like
#Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.FIELD,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.CLASS
)
#MustBeDocumented
#Retention(AnnotationRetention.BINARY)
expect annotation class RestrictTo(vararg val value: RestrictScope)
I get a compile error
public expect final val value: Array<out RestrictScope /* = RestrictTo.Scope */>
The following declaration is incompatible because return type is different:
public final val value: Array<RestrictTo.Scope>
If I change the value from a vararg to an Array I get this error.
public constructor RestrictTo(value: Array<RestrictScope /* = RestrictTo.Scope */>)
The following declaration is incompatible because parameter types are different:
public constructor RestrictTo(vararg value: RestrictTo.Scope)
Is there anyway to make the types work for both the constructor and the values method?
This is a bug - https://youtrack.jetbrains.com/issue/KT-20900
Feel free to upvote the issue.
I came across something and wondered all the time why you should do this.
You implement an interface in Kotlin through a simple function type:
"It is possible for a class to implement a function type as if it were an interface. It must then supply an operator function called invoke with the given signature, and instances of that class may then be assigned to a variable of that function type:"
class Divider : (Int, Int) -> Double {
override fun invoke(numerator: Int, denominator: Int): Double = ...
}
But why should I do this? Why should I add an interface in that way? I think its only possible to add one function and not more.
Or is it an advantage that I can implement a function with a function body and not only the function head like in normal interfaces? I think it is possible in Java to add default methods to interfaces with a function body. So maybe it is something like that?
Function as a class can have state. For example you could store the last invocations and use the history as a cache:
class Divider : (Int, Int) -> Double {
val history = mutableMapOf<Pair<Int, Int>, Double>()
override fun invoke(numerator: Int, denominator: Int): Double {
return history.computeIfAbsent(Pair(numerator, denominator)) {
numerator.toDouble() / denominator.toDouble()
}
}
}
fun main() {
val divider = Divider()
println(divider(1,2))
println(divider(2,3))
println(divider.history)
}
It is probably not very useful to write a class that only implements a function type interface; however, it might be useful to write a class that can among other things be used in place of a function.
An example from the standard library is the KProperty1 interface. You can write code like this:
data class C(val id: Int, val name: String)
val objs = listOf(C(1, "name1"), C(2, "name2"), C(3, "name3"))
val ids = objs.map(C::id)
Here, C::id is a property reference of type KProperty1<C, Int>, and it can be used as an argument to List.map in place of a lambda because KProperty1<C, Int> extends (C) -> Int. However, KProperty1 has a lot of other uses besides being passed as a function.
I'm currently working on a multi-platform module using kotlin. To do so, I rely on the expect/actual mechanism.
I declare a simple class in Common.kt:
expect class Bar constructor(
name: String
)
I'd like to use the defined class in a common method (also present in Common.kt):
fun hello(bar: Bar) {
print("Hello, my name is ${bar.name}")
}
The actual implementation is defined in Jvm.kt:
actual data class Bar actual constructor(
val name: String
)
The problem is I got the following error inside my hello function
Unresolved reference: name
What am I doing wrong?
Expected classes constructor cannot have a property parameter
Therefore it is necessary to describe the property as a class member with val name: String
Actual constructor of 'Bar' has no corresponding expected declaration
However, for the actual constructor to match the expected declaration the number of parameters has to be the same. That is why the parameter is also added name: String in the constructor in addition to the existence of the property.
expect class Bar(name: String) {
val name: String
}
actual class Bar actual constructor(actual val name: String)
Note: If we leave the constructor empty of the expected class we see how the IDE complains when adding a constructor in the current class for the incompatibility.
GL
It should be val name in the expect part as well, either in the constructor parameter list or as a member property.
Recently IntelliJ suggested to add final to one of a val properties. This particular property was initialized in init {} block. I've tried to find out what is the semantics of final val construct and when should I use it, but Kotlin is all about immutability and how val is equivalent of final in Java and so results were so noisy, that I couldn't find anything.
Example:
final val id: Int // `final` suggested by IDE
init { id = 1 }
What is the meaning and possible usages of similar property? By applying final what limitations it implies beyond immutability, which is already known? Does it have anything to do with inheritance or external access?
IntelliJ stopped sugessting final if property is private.
The example as it is should not suggest adding final as it does nothing in this case. The only place where adding final makes sense in Kotlin is when overriding members. By adding final to an overridden property (or method), you're preventing subclasses from further overriding it.
For example:
open class A {
open val x: Int = 0
}
open class B : A() {
final override val x: Int = 25
}
class C : B() {
override val x: Int = 56 // Error: `x` in `B` is final and cannot be overridden
}
The final keyword isn't really applicable if:
the class you're in isn't open,
the property isn't open,
the property is private.