I have a GUI based application (Kotlin) that consists of a list of Notes to the left (it shows the note's title) and the selected Note's edition screen to the right.
When the users modify the title in the edition screen, the list item must show the new title.
In a mutable world, I'd do something like this:
interface Note {
fun title(): String
fun content(): String
fun setTitle(newTitle: String)
fun setContent(newTitle: String)
fun addListener(l: Listener)
}
class NoteListItem(n: Note) : Listener {
init {
n.addListener(this)
}
override fun onChange() { //from Listener
repaint();
}
fun repaint() {
//code
}
}
class NoteEditionScreen(n: Note) {
fun onTitleTextChanged(newTitle: String) {
n.setTitle(newTitle)
}
//...
}
Inside Note.setTitle method, listeners are notified.
Both "screens" have the same instance of Note, so changes are propagated.
However, with immutability:
interface Note {
fun title()
fun content()
fun title(newTitle: String) : Note
fun content(newContent: String) : Note
}
the method Note.title(String) returns a new instance of Note instead of changing the state.
In that case, how can I "notify" to the NoteListItem the title has changed?
Obviously, those two concepts don't go together nicely here.
The essence of the elements on your UI is: they allow for changes. The user doesn't know (or care) if the underlying object is immutable or not. He wants to change that title.
Thus, there are two options for you:
give up on your Node being immutable
introduce an abstraction layer that is used by your UI
In other words: you can add a mutable NodeContainer that is used for displaying immutable node objects on your UI.
Now you have to balance between having the advantages of keeping your Node class immutable and the disadvantages of adding mutable wrapper thingy around the Node class. But that is your decision; depending on your context.
Related
I'm making a simple game to learn some kotlin, and I'm a little confused on the best way to change this around using OOP.
I have a class for backpack setup so that it has another class called items that will be different types of items. Below I've recreated a simple version of what I have.
class backPack {
private val item: Item
init { item = Item() }
fun display() {
item.display()
}
}
class Item {
fun display() { println("Your item!") }
}
fun main() {
val examplePack = backPack()
examplePack.display()
}
I want to change the backPack class to allow for different types of items. For example, health potions and mana potions. I considered making the item an open class, then having something like this:
class healthPotion : Item() {
override fun display() {
println("health potion!")
}
}
class manaPotion : Item() {
override fun display() {
println("mana potion!")
}
}
which seems correct, but I'm a little stuck on how to refactor the backpack class to allow different types of items and I want to make sure this seems like a proper way to do this. Any assistance is very appreciated, thank you!
That's basically the idea! If your BackPack class (it should start with a capital by convention) handles Items, then any class that has that type will work. You have two options - inheritance, and composition.
Inheritance is where you build a hierarchy of classes, e.g.:
open class Item {
val weight: Int
fun Describe()
}
open class Potion : Item() {
fun drink() {}
}
// this is a Potion, and a Potion is an Item, meaning this is an Item
class ManaPotion : Potion() {
override fun drink() {
println("whoa!")
}
}
// etc
The problem there is you're locked into a rigid hierarchy - what if you had a StaleBread that's a Food, but you also want it to be a Weapon? You can use interfaces to compose your object by giving it multiple types, not just a parent:
open class Item
interface Food {
fun eat() {
println("yum")
}
}
interface Weapon {
fun attack() {
println("RARGH")
}
}
class StaleBread : Item(), Food, Weapon
Because StaleBread has all of those types, you can treat it as any of them, because it is all of them. Because it's a Weapon, it's guaranteed to have an attack() method, etc. You can add it to a List<Food>, because it is a Food. Being able to treat objects as different types is called polymorphism. So you're able to compose an object from different types, to give it certain properties, certain behaviours, etc
Your example should work as-is because you're handling Items in your backpack, and your two potion classes are both Items (descendants of that class, specifically, since you're inheriting from the Item class). There are lots of ways to organise it - if you get into some tutorials about inheritance, composition and polymorphism (this is only a simple overview that skips over a bunch of things) you'll start to get some ideas about how to move forward
oh yeah, for the actual backpack, you probably want something like this:
class BackPack {
private val items = mutableListOf<Item>()
fun addItem(item: Item) {
// here you could do things like check it doesn't exceed the allowed weight
// or capacity of the backpack
items.add(item)
}
}
This way, your backpack can contain multiple Items, and you can control how those are accessed through the class's functions and properties. Anything which is an Item type can go in there!
If you want to be able to change which item is in the bag, the property should be a var. If you want the bag to be able to be empty, then it should be a nullable property (declared with a ? after the type so it can hold null).
By the way, class names should always start with a capital letter so your code will be easier to read. And you can initialize properties at the declaration site instead of using a separate init block.
class Backpack {
var item: Item? = null
fun display() {
item?.display()
}
}
Your generic Item() doesn't seem like it would be useful in practice. Therefore, Item should probably be either an abstract class or an interface. A general OOP principle is that you should avoid deep class hierarchies. If your superclass doesn't contain logic that must be shared by all its children, it should probably be an interface instead.
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... :-)
Hello dear reactive programmers, I started to learn project reactor but I still struggle to figure out what operator to use when. I figured out, that if I want to have reusable parts to define a reactor flow, I can use the transform operator. What I would like to achieve is to use a certain implementation of such a flow function based on the current observables context. For a Mono flow, I came up with this, but I am very unsure, if it is a good solution:
So here is a part of the flow
class CloudeventOverDelegatorRoute(
val fromHttpToDelegatorRoute: FromHttpToDelegatorRoute,
val delegatorProvider: DelegatorProvider,
val fromDelegatorToHttpRoute: FromDelegatorToHttpRoute
): MessageRoute<HttpBaseMessage, HttpResponseMessage> {
override fun isHandlerFor(context: RouteContext): Boolean {
return fromHttpToDelegatorRoute.isHandlerFor(context)
&& fromDelegatorToHttpRoute.isHandlerFor(context)
}
override fun buildPipeline(input: Mono<RoutableMessage<HttpBaseMessage>>): Mono<RoutableMessage<HttpResponseMessage>> {
var dynamicallyDeterminedDelegator: Delegator? = null
return input.transform {
fromHttpToDelegatorRoute.buildPipeline(input)
}.handle<RoutableMessage<InternalMessage>> { t, u ->
dynamicallyDeterminedDelegator = delegatorProvider.provideDelegatorFor(t.routeContext)
u.next(t)
u.complete()
}.transform {
dynamicallyDeterminedDelegator!!.sendDelegated(it)
}.transform { fromDelegatorToHttpRoute.buildPipeline(it) }
}
}
Here is the dynamic selection logic
interface DelegatorProvider {
fun provideDelegatorFor(context: RouteContext): Delegator
}
class FirstMatchDelegatorProvider(
private val delegators: List<Delegator>
): DelegatorProvider {
override fun provideDelegatorFor(context: RouteContext): Delegator {
return delegators.firstOrNull {
it.isHandlerFor(context)
}?: throw IllegalStateException("No Delegator route available for context: $context")
}
}
And this is the delegator providing an essential sub-part of the whole flow
interface Delegator {
fun isHandlerFor(context: RouteContext): Boolean
fun sendDelegated(input: Mono<RoutableMessage<InternalMessage>>): Mono<RoutableMessage<InternalStatusMessage>>
}
What do you think? How would you solve it?
this approach is problematic because it relies on shared state (the dynamicallyDeterminedDelegator variable). If multiple subscribers subscribe to the returned Mono, they could overwrite each other delegator. Maybe that (multiple subscriptions) can't happen in your application, but this is a very bad habit to get into in any case.
looks like you can derive a delegator out of a RoutableMessage<InternalMessage> , and that you don't really need to retain that delegator.
the easiest way to resolve and apply the delegator to the routableMessage in one go is simply to use flatMap. see the (pseudo) java code below:
.flatMap(routableMessage -> {
val delegator = delegatorProvider.provideDelegatorFor(routableMessage.routeContext);
return delegator.sendDelegated(routableMessage);
})
I'm a newbie in Kotlin. I want to ask what private constructor in Kotlin for? class DontCreateMe private constructor () { /*...*/ }. I mean what class is supposed to be if we can't create its instance?
Well, the answers in the comments are correct, but since nobody wrote a full answer. I'm going to have a go at it.
Having a private constructor does not necessarily mean that an object cannot be used by external code. It just means that the external code cannot directly use its constructors, so it has to get the instances through an exposed API in the class scope. Since this API is in the class scope, it has access to the private constructor.
The simplest example would be:
class ShyPerson private constructor() {
companion object {
fun goToParty() : ShyPerson {
return ShyPerson()
}
}
}
fun main(args: String) {
// outside code is not directly using the constructor
val person = ShyPerson.goToParty()
// Just so you can see that you have an instance allocated in memory
println(person)
}
The most common use case for this that I've seen is to implement the Singleton pattern, as stated by Mojtaba Haddadi, where the external code can only get access to one instance of the class.
A simple implementation would be:
class Unity private constructor() {
companion object {
private var INSTANCE : Unity? = null
// Note that the reason why I've returned nullable type here is
// because kotlin cannot smart-cast to a non-null type when dealing
// with mutable values (var), because it could have been set to null
// by another thread.
fun instance() : Unity? {
if (INSTANCE == null) {
INSTANCE = Unity()
}
return INSTANCE
}
}
}
fun main(args: Array<String>) {
val instance = Unity.instance()
println(instance)
}
This is often used so that classes that are resource consuming are only instantiated once or so that certain pieces of data are shared by the entire codebase.
Be aware that kotlin uses the object keyword to implement this pattern, with the advantage of being thread-safe. Also some developers consider Singletons to be an anti-pattern
Another use case for private constructors would be to implement Builder patterns, where classes that have complex initialization can be abstracted into a simpler API, so the user doesn't have to deal with clunky constructors. This other answer addresses its uses in kotlin.
One of the simplest uses in real life kotlin code that I've seen is on the Result implementation from the stdlib, where it's being used to change the internal representation of the object.
What is the intended meaning of "companion object"? So far I have been using it just to replace Java's static when I need it.
I am confused with:
Why is it called "companion"?
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
To instantly create a singleton instance that is scoped to a class, I often write
:
companion object {
val singleton by lazy { ... }
}
which seems like an unidiomatic way of doing it. What's the better way?
What is the intended meaning of "companion object"? Why is it called "companion"?
First, Kotlin doesn't use the Java concept of static members because Kotlin has its own concept of objects for describing properties and functions connected with singleton state, and Java static part of a class can be elegantly expressed in terms of singleton: it's a singleton object that can be called by the class' name. Hence the naming: it's an object that comes with a class.
Its name used to be class object and default object, but then it got renamed to companion object which is more clear and is also consistent with Scala companion objects.
Apart from naming, it is more powerful than Java static members: it can extend classes and interfaces, and you can reference and pass it around just like other objects.
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes, that's the idiomatic way. Or you can even group them in non-companion objects by their meaning:
class MyClass {
object IO {
fun makeSomethingWithIO() { /* ... */ }
}
object Factory {
fun createSomething() { /* ... */ }
}
}
To instantly create a singleton instance that is scoped to a class, I often write /*...*/ which seems like an unidiomatic way of doing it. What's the better way?
It depends on what you need in each particular case. Your code suits well for storing state bound to a class which is initialized upon the first call to it.
If you don't need it to be connected with a class, just use object declaration:
object Foo {
val something by lazy { ... }
}
You can also remove lazy { ... } delegation to make the property initialize on first class' usage, just like Java static initializers
You might also find useful ways of initializing singleton state.
Why is it called "companion"?
This object is a companion of the instances.
IIRC there was lengthy discussion here: upcoming-change-class-objects-rethought
Does it mean that to create multiple static properties, I have to group it together inside companion object block?
Yes. Every "static" property/method needs to be placed inside this companion.
To instantly create a singleton instance that is scoped to a class, I often write
You do not create the singleton instance instantly. It is created when accessing singleton for the first time.
which seems like an unidiomatic way of doing it. What's the better way?
Rather go with object Singleton { } to define a singleton-class. See: Object Declarations
You do not have to create an instance of Singleton, just use it like that Singleton.doWork()
Just keep in mind that Kotlin offers other stuff to organize your code. There are now alternatives to simple static functions e.g. you could use Top-Level-Functions instead.
When the classes/objects with related functionalities belong together, they are like companions of each other. A companion means a partner or an associate, in this case.
Reasons for companionship
Cleaner top-level namespace
When some independent function is intended to be used with some specific class only, instead of defining it as a top-level function, we define it in that particular class. This prevents the pollution of top-level namespace and helps with more relevant auto-completion hints by IDE.
Packaging convenience
It's convenient to keep the classes/objects together when they are closely related to each other in terms of the functionality they offer to each other. We save the effort of keeping them in different files and tracking the association between them.
Code readability
Just by looking at the companionship, you get to know that this object provides helper functionality to the outer class and may not be used in any other contexts. Because if it was to be used with other classes, it would be a separate top level class or object or function.
Primary purpose of companion object
Problem: companion class
Let's have a look at the kinds of problems the companion objects solve. We'll take a simple real world example. Say we have a class User to represent a user in our app:
data class User(val id: String, val name: String)
And an interface for the data access object UserDao to add or remove the User from the database:
interface UserDao {
fun add(user: User)
fun remove(id: String)
}
Now since the functionalities of the User and implementation of the UserDao are logically related to each other, we may decide to group them together:
data class User(val id: String, val name: String) {
class UserAccess : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
val userAccess = User.UserAccess()
userAccess.add(john)
}
While this is a good setup, there are several problems in it:
We have an extra step of creating the UserAccess object before we can add/remove a User.
Multiple instances of the UserAccess can be created which we don't want. We just want one data access object (singleton) for User in the entire application.
There is a possibility of the UserAccess class to be used with or extended with other classes. So, it doesn't make our intent clear of exactly what we want to do.
The naming userAccess.add() or userAccess.addUser() doesn't seem very elegant. We would prefer something like User.add().
Solution: companion object
In the User class, we just replace the two words class UserAccess with the two other words companion object and it's done! All the problems mentioned above have been solved suddenly:
data class User(val id: String, val name: String) {
companion object : UserDao {
override fun add(user: User) { }
override fun remove(id: String) { }
}
}
Usage:
fun main() {
val john = User("34", "John")
User.add(john)
}
The ability to extend interfaces and classes is one of the features that sets the companion objects apart from Java's static functionality. Also, companions are objects, we can pass them around to the functions and assign them to variables just like all the other objects in Kotlin. We can pass them to the functions that accept those interfaces and classes and take advantage of the polymorphism.
companion object for compile-time const
When the compile-time constants are closely associated with the class, they can be defined inside the companion object.
data class User(val id: String, val name: String) {
companion object {
const val DEFAULT_NAME = "Guest"
const val MIN_AGE = 16
}
}
This is the kind of grouping you have mentioned in the question. This way we prevent the top-level namespace from polluting with the unrelated constants.
companion object with lazy { }
The lazy { } construct is not necessary to get a singleton. A companion object is by default a singleton, the object is initialized only once and it is thread safe. It is initialized when its corresponding class is loaded. Use lazy { } when you want to defer the initialization of the member of the companion object or when you have multiple members that you want to be initialized only on their first use, one by one:
data class User(val id: Long, val name: String) {
companion object {
val list by lazy {
print("Fetching user list...")
listOf("John", "Jane")
}
val settings by lazy {
print("Fetching settings...")
mapOf("Dark Theme" to "On", "Auto Backup" to "On")
}
}
}
In this code, fetching the list and settings are costly operations. So, we use lazy { } construct to initialize them only when they are actually required and first called, not all at once.
Usage:
fun main() {
println(User.list) // Fetching user list...[John, Jane]
println(User.list) // [John, Jane]
println(User.settings) // Fetching settings...{Dark Theme=On, Auto Backup=On}
println(User.settings) // {Dark Theme=On, Auto Backup=On}
}
The fetching statements will be executed only on the first use.
companion object for factory functions
Companion objects are used for defining factory functions while keeping the constructor private. For example, the newInstance() factory function in the following snippet creates a user by generating the id automatically:
class User private constructor(val id: Long, val name: String) {
companion object {
private var currentId = 0L;
fun newInstance(name: String) = User(currentId++, name)
}
}
Usage:
val john = User.newInstance("John")
Notice how the constructor is kept private but the companion object has access to the constructor. This is useful when you want to provide multiple ways to create an object where the object construction process is complex.
In the code above, consistency of the next id generation is guaranteed because a companion object is a singleton, only one object will keep track of the id, there won't be any duplicate ids.
Also notice that companion objects can have properties (currentId in this case) to represent state.
companion object extension
Companion objects cannot be inherited but we can use extension functions to enhance their functionality:
fun User.Companion.isLoggedIn(id: String): Boolean { }
The default class name of the companion object is Companion, if you don't specify it.
Usage:
if (User.isLoggedIn("34")) { allowContent() }
This is useful for extending the functionality of the companion objects of third party library classes. Another advantage over Java's static members.
When to avoid companion object
Somewhat related members
When the functions/properties are not closely related but only somewhat related to a class, it is recommended that you use top-level functions/properties instead of companion object. And preferably define those functions before the class declaration in the same file as that of class:
fun getAllUsers() { }
fun getProfileFor(userId: String) { }
data class User(val id: String, val name: String)
Maintain single responsibility principle
When the functionality of the object is complicated or when the classes are big, you may want to separate them into individual classes. For example, You may need a separate class to represent a User and another class UserDao for database operations. A separate UserCredentials class for functions related to login. When you have a huge list of constants that are used in different places, you may want to group them in another separate class or file UserConstants. A different class UserSettings to represent settings. Yet another class UserFactory to create different instances of the User and so on.
That's it! Hope that helps make your code more idiomatic to Kotlin.
Why is it called "companion"?
An object declaration inside a class can be marked with the companion keyword:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Members of the companion object can be called by using simply the class name as the qualifier:
val instance = MyClass.create()
If you only use 'object' without 'companion', you have to do like this:
val instance = MyClass.Factory.create()
In my understanding, 'companion' means this object is companion with the outter class.
We can say that companion is same as "Static Block" like Java, But in case of Kotlin there is no Static Block concept, than companion comes into the frame.
How to define a companion block:
class Example {
companion object {
fun display(){
//place your code
}
}
}
Calling method of companion block, direct with class name
Example.Companion.display