When creating an interface in Kotlin, does it matter if properties have get/set? - properties

In a Kotlin interface, does it matter if properties are declared with empty get/set statements?
For instance...
interface ExampleInterface {
// These...
val a: String
get
var b: String
get
set
// ...compared to these...
val c: String
var d: String
}
I'm having a hard time noticing a difference.
When implementing the interface, it doesn't seem to matter if I use getters/setters for the properties, or if I set the value directly.
When accessing these through java, the val's both have getters, and the var's both have getters and setters.
public void javaMethod(ExampleInterface e) {
e.getA();
e.getB();
e.setB();
e.getC();
e.getD();
e.setD();
}

The property declarations in your example are identical, get and set can be safely removed from there, because, as you correctly noted, the accessors are generated anyway. The syntax with get and set can, however, be used to provide an accessor implementation or to restrict its visibility.
Providing implementation:
interface ExampleInterface {
var b: String
get() = ""
set(value) { }
}
This example shows a default implementation of a property declared in an interface. This property can still be overriden inside the interface implementations.
class Example {
var b: String = ""
get() = "$field$field"
}
Here, get() = ... overrides the default getter behavior of a property with a backing field, whereas set is not mentioned, thus it behaves normally.
Visibility restriction:
class Example {
var s: String = "s"
private set
}
In this example, the setter visibility is private. The visibility of get is always the same to the visibility of the property, so there's no need to specify it separately. Interfaces cannot declare private members.
abstract class Example {
abstract var b: String
protected set // Restrict visibility
}
The setter of this property is restricted to this class and its subclasses. Interfaces cannot declare protected members.
Of course, an accessor implementation can be combined with visibility restriction:
class Example {
var s: String = "abc"
private set(value) { if (value.isNotEmpty()) field = value }
}
See also:
The Kotlin reference article about properties
Properties visibility explanation in another answer

Related

Simulate package-privacy on properties in Kotlin

So, I have an enum called Level. That enum is actually just a wrapper for some other Level. Now I need to access that wrapped value (currently a protected property) in a different class called Log which sits in the same package. Obviously I do not want to completely expose that property by making it internal or public, but I need to access that wrapped value in my Log class.
How to I do that?
As Kotlin doesn't provide anything similar to package-private visibility, everything I tried failed. I'm already aware of the possibility to put both classes in one file, but that only allows me to gain exclusive access to the classes themselves, not their properties. And because I need to have both classes public that won't help either. So if anyone knows a workaround, I would be more than happy to hear it, because even though I really like Kotlin, this might be the reason for me to drop the language.
Both classes I mentioned look as follows:
Level.kt
enum class Level(protected val level: java.util.logging.Level) {
/** Useful for stuff */
OFF(CustomLevel("OFF", Int.MAX_VALUE)),
ASSERT(CustomLevel("ASSERT", 1200)),
FATAL(CustomLevel("FATAL", 1100)),
ERROR(CustomLevel("ERROR", 1000)),
WARN(CustomLevel("WARN", 900)),
INFO(CustomLevel("INFO", 800)),
DEBUG(CustomLevel("DEBUG", 700)),
ALL(CustomLevel("ALL", Int.MIN_VALUE));
private class CustomLevel(name: String, value: Int) : java.util.logging.Level(name, value)
}
Log.kt
object Log {
private val DEFAULT_CONSOLE_VERBOSITY = Level.ERROR
private val DEFAULT_FILE_VERBOSITY = Level.ALL
#JvmStatic
var consoleVerbosity: Level
get() = Level.findLevel(consoleHandler.level)
set(value) {
consoleHandler.level = value.level // The property I need to access
}
#JvmStatic
var fileVerbosity: Level
get() = Level.findLevel(fileHandler.level)
set(value) {
fileHandler.level = value.level // The property I need to access
}
private val consoleHandler = ConsoleHandler()
init {
consoleHandler.formatter = SimpleFormatter()
consoleHandler.level = DEFAULT_CONSOLE_VERBOSITY.level
}
private val fileHandler = FileHandler()
init {
fileHandler.formatter = SimpleFormatter()
fileHandler.level = DEFAULT_FILE_VERBOSITY.level
}
}
I am running the latest stable version of Kotlin (1.4.31)
As a workaround you may define an extension function/property for Log class in the scope of Level class:
enum class Level(private val level: java.util.logging.Level) {
//...
//Option 1
companion object {
fun Log.getLevelOf(level: Level) = level.level
}
//Option 2
val Log._level get() = level
}
Also you may define extension property for Level class in the scope of Log class for more natural usage:
object Log {
//...
private val Level.level : java.util.logging.Level
get() = consoleHandler.level = Level.run { getLevelOf(this#level) } // For Option 1
get() = with(this) { _level } // For Option 2
}
Downside of this approach is a tough coupling between these classes.
You just have to use extension functions like this:
fun Level.toLevel() = this.level
That allows you to access protected properties of other classes.
You cannot access a private class from another class but you can access a class from a class that is packed inside a file. So the workaround is to make fun in public class to access the private class which is in the same file.
But the highlight is that you cannot write a class inside an enum class in Kotlin.
I still don't know how you managed to write this code down in an IDE, because it will show an error.

How to skip defined getters or setters in Kotlin

In java you can do the follwing:
public class Foo {
private String bar = "text";
public void method() {
// direct access (no logic)
System.out.println(this.bar);
}
// only if you access the object from the outside
// you are forced to use the getter with some logic in it
public String getBar() {
System.out.println(this.bar);
return this.bar;
}
}
But if you define a getter or a setter with logic in Kotlin you are forced to always execute this logic when accessing the field:
class Foo {
var bar: String = "text"
get() {
println(field)
return field
}
private set
fun method() {
// this also executes the getter
// Is it possible to skip the getter
// and directly access the field?
println(this.bar)
}
}
Is there a better way to access the field without executing the getter or setter logic than creating your own fun getBar() in Kotlin?
There is no possible way to skip a getter or a setter, they are intended to block the direct access of a property.
What you can do is make a multi-reference to same value (fake-referencing):
private var _bar: String = "text"
var bar
get() {
// some operations intercepting the getter
return _bar
}
// direct access
_bar
// intercepted access public field
bar
In Kotlin the backing fields (in your case the private variable) are not exposed by design. There are a few exceptions explained here: https://kotlinlang.org/docs/reference/properties.html#backing-fields
All access to val and var happens through implicit getters and setters. A val resolves to a property with a getter() while var resolves to a property with a getter and a setter: https://kotlinlang.org/docs/reference/properties.html#properties-and-fields

Primitive properties for a class in init block - Kotlin

I'm defining a Kotlin class with a number of primitive properties:
class Contract (contractEntity : ContractEntity) EntityDao<ContractEntity> {
var id : Long // <- This is a primitive datatype, needs to be initialized
var concept : String //<- This also needs to be initialized or declared abstract
init{
mapFromEntity(contractEntity)
}
override fun mapFromEntity(entity : ContractEntity){
id = entity.id
concept = entity.concept
}
}
Now, I want those properties to be initialized with the function mapFromEntity() but I'm stuck with the init block because those are not initialized. What could be a good way to achieve what I'm trying?
So far, the best solution suggest to remove the function that maps the class and use the constructor parameter.
class Contract (contractEntity : ContractEntity) EntityDao<ContractEntity> {
var id = contractEntity.id
var concept = contractEntity.concept
}

What is difference between object and data class in Kotlin?

What is difference between data and object class in Kotlin, and what is the purpose of each?
data class User(val name: String, val age: Int)
and
object user {
val name = ""
fun printName(name: String) = "Hello, $name!"
}
object
object is Kotlin's way to create a singleton (one instance class) which is instantiated by the compiler.
data class
A data class is like a usual class but with a few advantages/resctrictions (Source).
Advantages
equals()/hashCode()
toString()
componentN()
copy()
Those are created from the properties specified in the primary constructor.
Restrictions
The primary constructor needs to have at least one parameter;
All primary constructor parameters need to be marked as val or var;
cannot be abstract, open, sealed or inner;
(before 1.1) may only implement interfaces.
Kotlin's object is similar to a class in Java, where all methods and variables are static.
object User {
val name = ""
fun printName(name: String) = "Hello, $name!"
}
in Kotlin is similar to the following in Java:
class User {
public static String name = "";
public static String printName(name: String) {
return "Hello " + name + "!";
}
}
Usage example:
//Kotlin
User.printName(User.name)
//Java
User.printName(User.name);
An object isn't exactly the same as the Java comparison I gave, though. It can inherit interfaces and classes, and the object itself is instantiated as a singleton instance. If you annotate methods inside an object with #JvmStatic, they will become true static members.
Kotlin's object
The data class in Kotlin is just a simpler syntax for a class that has no (or minimal) logic, and contains certain values. Kotlin generates the equals(), hashCode() and toString() functions for you in a data class, along with some other helper functions.
data class User(val name: String, val age: String)
in Kotlin will look something like this in Java:
class User {
public final String name;
public final String age;
public User(String name, String age) {
this.name = name;
this.age = age;
}
#Override
public boolean equals(Object other) {
//Kotlin-generated equality check
}
#Override
public long hashCode() {
//Kotlin's hashcode
}
#Override
public String toString() {
return "User(name=" + name + ",age=" + age + ")";
}
//other generated methods
}
Kotlin's data class documentation
First, there is no object class, the feature you are referring to is called object declaration.
Object declaration
This is a feature in Kotlin that allows you implement a singleton. The object declaration combines a class declaration and a declaration of a single instance of the class in a single statement.
// Let's assume that class Person is defined somewhere else
object Payroll {
val employees = arrayListOf<Person>()
fun calculateSalary() {
for (person in employees) {
// ...
}
}
}
// calling methods and properties
>>> Payroll.employees.add(Person("John", 23)) // calling a property
>>> Payroll.calculateSalary() // calling a method
Just like a class, an object declaration can contain declarations of properties, methods, initializer blocks, and so on. The only thing they are not allowed are constructors (either primary or secondary).
Object declarations are created immediately at the point of the definition, not through constructor calls from other places in the code.
Note: the object keyword can also be used for companion objects and object expressions.
Data Class
It is very common to create classes whose main goal is to hold data. If you want your class to be a convenient holder for your data you need to override the universal object methods:
toString() - string representation
equals() - object equality
hashCode() - hash containers
However, by adding the modifier data to your class, the necessary methods are automatically added for you. In addition, the following methods are also generated:
componentN() functions corresponding to the properties in their order of declaration
copy() function
class PersonClass(val name: String, val age: Int) // regular class
data class PersonDataClass(val name: String, val age: Int) // data class
In summary, if you need a holder for data, you should use a data class which means adding the modifier data to your class. This will generate the following methods for you: toString(), equals(), hashCode(), componentN(), and copy(), so you avoid writing boilerplate code. On the other hand, if you need to create a singleton, you use the object declaration feature.
In short, object is used, if you want to create singleton, unique object for the class and data class is a class that has equals, hashCode, toString automatically generated.

Passing parameters to a custom getter in kotlin

I have been reading about properties in Kotlin, including custom getters and setters.
However, I was wondering if it is possible to create a custom getter with extra parameters.
For example, consider the following method in Java:
public String getDisplayedValue(Context context) {
if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
Note that the static method in PrefUtils has to have Context as a parameter, so removing this is not an option.
I would like to write it like this in Kotlin:
val displayedValue: String
get(context: Context) {
return if (PrefUtils.useImperialUnits(context)) {
// stuff
} else {
// other stuff
}
}
But my IDE highlights all of this in red.
I am aware I can create a function in my class to get the displayed value, but this would mean I would have to use .getDisplayedValue(Context) in Kotlin as well instead of being able to refer to the property by name as in .displayedValue.
Is there a way to create a custom getter like this?
EDIT: If not, would it be best to write a function for this, or to pass Context into the parameters of the class constructor?
As far as I know, property getter cannot have parameter. Write a function instead.
You can do this by having a property that returns an intermediate object that has a get and/or set operator with the parameters that you want, rather than returning the value directly.
Having that intermediate object be an inner class instance may be useful for providing easy access to the parent object. However, in an interface you can't use inner classes so in that case you might need to provide an explicit constructor parameter referencing the parent object when constructing your intermediate object.
For instance:
class MyClass {
inner class Foo {
operator fun get(context: Context): String {
return if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
}
val displayedValue = Foo()
}
...
val context : Context = whatever
val mc : MyClass = whatever
val y: String = mc.displayedValue[context]
You can do for example:
val displayedValue: String by lazy {
val newString = context.getString(R.string.someString)
newString
}