I am trying to search for a collection type that have the following properties:
Maintain insertion order
Don't allow duplicates
Add one or more elements after another
I could create my own data collection but I wish not to.
After taking a look at all collections available in kotlin I think LinkedHashSet have almost all of my requirements, however it can't add elements after another or at nth position.
Is there any way to accomplish this with an extension method or any another trick?
You can just use List<> or any of its implementations. Its maintain insertion order, you can add one or more elements after another, and you can accomplish the "avoid duplicates" requirement by calling .distinct() when returning your list. i.e:
private fun fillData(): MutableList<String> {
var dataSet: MutableList<String> = ArrayList()
for (i in 0..10) dataSet.add("Product $i")
dataSet.add("aaa")
dataSet.add("aaa")
dataSet.add("aaa")
dataSet.add("aaa")
dataSet.add("aaa")
return dataSet.distinct().toMutableList()
}
The result of this function returns an array with 11 elements, "Product 1".. "Product 10" and just 1 "aaa" element at the end.
you can see the doc of List.distinct() here
In the standard library (& Java collection API) there isn't such a collection type as far as I know.
Apache commons collections however contains what you are looking for: ListOrderedSet
Why not implement a custom data structure that exactly serve your requirements?
class OrderedHashSet<E> : MutableSet<E>{
private val set = HashSet<E>()
private val list = LinkedList<E>()
override val size: Int
get() = list.size
override fun contains(element: E) = set.contains(element)
override fun containsAll(elements: Collection<E>) = set.containsAll(elements)
override fun isEmpty() = list.isEmpty()
override fun iterator() = list.iterator()
override fun add(element: E): Boolean {
if(set.add(element)){
list.add(element)
return true
}
return false
}
fun add(index: Int, element: E) : Boolean {
if(set.add(element)){
list.add(index, element)
return true
}
return false
}
override fun addAll(elements: Collection<E>): Boolean {
var modified = false
for(element in elements){
if(add(element)){
modified = true
}
}
return modified
}
override fun clear() {
set.clear()
list.clear()
}
override fun remove(element: E): Boolean {
set.remove(element)
return list.remove(element)
}
override fun removeAll(elements: Collection<E>): Boolean {
var modified = false
for(element in elements){
if(remove(element)){
modified = true
}
}
return modified
}
override fun retainAll(elements: Collection<E>): Boolean {
set.retainAll(elements)
return list.retainAll(elements)
}
}
Related
I'm trying to understand the functional programming paradigm so I'm playing around with an immutable linked list. I've created a Bag with some utility functions and now I want to iterate through the collection. I want to implement an Iterable:
sealed class Bag<out A> : Iterable<A> {
companion object {
fun <A> of(vararg aa: A): Bag<A> {
val tail = aa.sliceArray(1 until aa.size)
return if (aa.isEmpty()) Nil else Cons(aa[0], of(*tail))
}
/**
* Returns the tail of the bag
*/
fun <A> tail(bag: Bag<A>): Bag<A> =
when (bag) {
is Cons -> bag.tail
is Nil -> throw IllegalArgumentException("Nil cannot have a tail")
}
/**
* Add an item to the beginning
*/
fun <A> add(bag: Bag<A>, elem: A): Bag<A> =
Cons(elem, bag)
fun <A> isEmpty(bag: Bag<A>): Boolean =
when (bag) {
is Nil -> true
is Cons -> false
}
}
class BagIterator<A> : Iterator<A> {
override fun hasNext(): Boolean {
TODO("Not yet implemented")
}
override fun next(): A {
TODO("Not yet implemented")
}
}
}
object Nil : Bag<Nothing>() {
override fun iterator(): Iterator<Nothing> =
BagIterator()
}
data class Cons<out A>(val head: A, val tail: Bag<A>) : Bag<A>() {
override fun iterator(): Iterator<A> =
BagIterator()
}
Now I'm stuck with hasNext() and next() implementations. I'm not even sure if this approach works. Can I implement Iterable this way?
Note that an Iterator is a mutable thing. next must mutate the iterator's current state. Its signature does not allow you to "return a new Iterator with a different state". So if you wanted to do that, sad news for you :( This is because the way that iteration is supposed to happen is (this is roughly what a for loop translates to):
val iterator = something.iterator()
while (iterator.hasNext()) {
val elem = iterator.next()
...
}
Now knowing that, we can store a var current: Bag<A>:
// in Bag<A>
class BagIterator<A>(var current: Bag<A>) : Iterator<A> {
override fun hasNext(): Boolean = current !is Nil
override fun next(): A {
val curr = current
return when (curr) {
is Nil -> throw NoSuchElementException()
is Cons -> curr.also {
current = it.tail
}.head
}
}
}
override fun iterator(): Iterator<A> = BagIterator(this)
And the Nil and Cons types can have empty bodies.
If you don't like this, blame the standard library designers :) You can always write your own Iterator<A> interface, but of course you can't use the for loop with your Bag if you do that. You can write your own forEach extension function though.
I'm trying to build a class where certain values are Observable but also Serializable.
This obviously works and the serialization works, but it's very boilerplate-heavy having to add a setter for every single field and manually having to call change(...) inside each setter:
interface Observable {
fun change(message: String) {
println("changing $message")
}
}
#Serializable
class BlahVO : Observable {
var value2: String = ""
set(value) {
field = value
change("value2")
}
fun toJson(): String {
return Json.encodeToString(serializer(), this)
}
}
println(BlahVO().apply { value2 = "test2" })
correctly outputs
changing value2
{"value2":"test2"}
I've tried introducing Delegates:
interface Observable {
fun change(message: String) {
println("changing $message")
}
#Suppress("ClassName")
class default<T>(defaultValue: T) {
private var value: T = defaultValue
operator fun getValue(observable: Observable, property: KProperty<*>): T {
return value
}
operator fun setValue(observable: Observable, property: KProperty<*>, value: T) {
this.value = value
observable.change(property.name)
}
}
}
#Serializable
class BlahVO : Observable {
var value1: String by Observable.default("value1")
fun toJson(): String {
return Json.encodeToString(serializer(), this)
}
}
println(BlahVO().apply { value1 = "test1" }) correctly triggers change detection, but it doesn't serialize:
changing value1
{}
If I go from Observable to ReadWriteProperty,
interface Observable {
fun change(message: String) {
println("changing $message")
}
fun <T> look(defaultValue: T): ReadWriteProperty<Observable, T> {
return OP(defaultValue, this)
}
class OP<T>(defaultValue: T, val observable: Observable) : ObservableProperty<T>(defaultValue) {
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
super.setValue(thisRef, property, value)
observable.change("blah!")
}
}
}
#Serializable
class BlahVO : Observable {
var value3: String by this.look("value3")
fun toJson(): String {
return Json.encodeToString(serializer(), this)
}
}
the result is the same:
changing blah!
{}
Similarly for Delegates.vetoable
var value4: String by Delegates.vetoable("value4", {
property: KProperty<*>, oldstring: String, newString: String ->
this.change(property.name)
true
})
outputs:
changing value4
{}
Delegates just doesn't seem to work with Kotlin Serialization
What other options are there to observe a property's changes without breaking its serialization that will also work on other platforms (KotlinJS, KotlinJVM, Android, ...)?
Serialization and Deserialization of Kotlin Delegates is not supported by kotlinx.serialization as of now.
There is an open issue #1578 on GitHub regarding this feature.
According to the issue you can create an intermediate data-transfer object, which gets serialized instead of the original object. Also you could write a custom serializer to support the serialization of Kotlin Delegates, which seems to be even more boilerplate, then writing custom getters and setters, as proposed in the question.
Data Transfer Object
By mapping your original object to a simple data transfer object without delegates, you can utilize the default serialization mechanisms.
This also has the nice side effect to cleanse your data model classes from framework specific annotations, such as #Serializable.
class DataModel {
var observedProperty: String by Delegates.observable("initial") { property, before, after ->
println("""Hey, I changed "${property.name}" from "$before" to "$after"!""")
}
fun toJson(): String {
return Json.encodeToString(serializer(), this.toDto())
}
}
fun DataModel.toDto() = DataTransferObject(observedProperty)
#Serializable
class DataTransferObject(val observedProperty: String)
fun main() {
val data = DataModel()
println(data.toJson())
data.observedProperty = "changed"
println(data.toJson())
}
This yields the following result:
{"observedProperty":"initial"}
Hey, I changed "observedProperty" from "initial" to "changed"!
{"observedProperty":"changed"}
Custom data type
If changing the data type is an option, you could write a wrapping class which gets (de)serialized transparently. Something along the lines of the following might work.
#Serializable
class ClassWithMonitoredString(val monitoredProperty: MonitoredString) {
fun toJson(): String {
return Json.encodeToString(serializer(), this)
}
}
fun main() {
val monitoredString = obs("obsDefault") { before, after ->
println("""I changed from "$before" to "$after"!""")
}
val data = ClassWithMonitoredString(monitoredString)
println(data.toJson())
data.monitoredProperty.value = "obsChanged"
println(data.toJson())
}
Which yields the following result:
{"monitoredProperty":"obsDefault"}
I changed from "obsDefault" to "obsChanged"!
{"monitoredProperty":"obsChanged"}
You however lose information about which property changed, as you don't have easy access to the field name. Also you have to change your data structures, as mentioned above and might not be desirable or even possible. In addition, this work only for Strings for now, even though one might make it more generic though.
Also, this requires a lot of boilerplate to start with. On the call site however, you just have to wrap the actual value in an call to obs.
I used the following boilerplate to get it to work.
typealias OnChange = (before: String, after: String) -> Unit
#Serializable(with = MonitoredStringSerializer::class)
class MonitoredString(initialValue: String, var onChange: OnChange?) {
var value: String = initialValue
set(value) {
onChange?.invoke(field, value)
field = value
}
}
fun obs(value: String, onChange: OnChange? = null) = MonitoredString(value, onChange)
object MonitoredStringSerializer : KSerializer<MonitoredString> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("MonitoredString", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: MonitoredString) {
encoder.encodeString(value.value)
}
override fun deserialize(decoder: Decoder): MonitoredString {
return MonitoredString(decoder.decodeString(), null)
}
}
I am aware that in Kotlin classes will have an equals and hashcode created automatically as follows:
data class CSVColumn(private val index: Int, val value: String) {
}
My question is, is there a way to have the implementation just use one of these properties (such as index) without writing the code yourself. What was otherwise a very succinct class now looks like this:
data class CSVColumn(private val index: Int, val value: String) {
override fun equals(other: Any?): Boolean {
if (this === other) {
return true
}
if (javaClass != other?.javaClass) {
return false
}
other as CSVColumn
if (index != other.index) {
return false
}
return true
}
override fun hashCode(): Int {
return index
}
}
In Java with Lombok, I can do something like:
#Value
#EqualsAndHasCode(of="index")
public class CsvColumn {
private final int index;
private final String value;
}
Would be cool if there were a way to tell Kotlin something similar.
From the Data Classes documentation you get:
Note that the compiler only uses the properties defined inside the primary constructor for the automatically generated functions. To exclude a property from the generated implementations, declare it inside the class body
So you have to implement equals() and hashCode() manually or with the help of a Kotlin Compiler Plugin.
You can't do something like this for data classes, they always generate equals and hashCode the same way, there's no way to provide them such hints or options.
However, they only include properties that are in the primary constructor, so you could do this for them to only include index:
data class CSVColumn(private val index: Int, value: String) {
val value: String = value
}
... except you can't have parameters in the primary constructor that aren't properties when you're using data classes.
So you'd have to somehow introduce a secondary constructor that takes two parameters, like this:
class CSVColumn private constructor(private val index: Int) {
var value: String = ""
constructor(index: Int, value: String) : this(index) {
this.value = value
}
}
... but now your value property has to be a var for the secondary constructor to be able to set its value.
All this to say that it's probably not worth trying to work around it. If you need an non-default implementation for equals and hashCode, data classes can't help you, and you'll need to implement and maintain them manually.
Edit: as #tynn pointed out, a private setter could be a solution so that your value isn't mutable from outside the class:
class CSVColumn private constructor(private val index: Int) {
var value: String = ""
private set
constructor(index: Int, value: String) : this(index) {
this.value = value
}
}
I wrote a little utility called "stem", which allows you to select which properties to consider for equality and hashing. The resulting code is as small as it can get with manual equals()/hashCode() implementation:
class CSVColumn(private val index: Int, val value: String) {
private val stem = Stem(this, { index })
override fun equals(other: Any?) = stem.eq(other)
override fun hashCode() = stem.hc()
}
You can see its implementation here.
I guess that we have to write equals()/hashCode() manually for now.
https://discuss.kotlinlang.org/t/automatically-generate-equals-hashcode-methods/3779
It is not supported and is planning to be, IMHO.
I guess that we have to write equals()/hashCode() manually for now. https://discuss.kotlinlang.org/t/automatically-generate-equals-hashcode-methods/3779
It is not supported and is planning to be, IMHO.
Below are some reference which may be helpful.
https://discuss.kotlinlang.org/t/how-does-kotlin-implement-equals-and-hashcode/940
https://kotlinlang.org/docs/reference/data-classes.html
https://medium.com/#appmattus/effective-kotlin-item-11-always-override-hashcode-when-you-override-equals-608a090aeaed
See the following performance optimized way (with the use of value classes and inlining) of implementing a generic equals/hashcode for any Kotlin class:
#file:Suppress("EXPERIMENTAL_FEATURE_WARNING")
package org.beatkit.common
import kotlin.jvm.JvmInline
#Suppress("NOTHING_TO_INLINE")
#JvmInline
value class HashCode(val value: Int = 0) {
inline fun combineHash(hash: Int): HashCode = HashCode(31 * value + hash)
inline fun combine(obj: Any?): HashCode = combineHash(obj.hashCode())
}
#Suppress("NOTHING_TO_INLINE")
#JvmInline
value class Equals(val value: Boolean = true) {
inline fun combineEquals(equalsImpl: () -> Boolean): Equals = if (!value) this else Equals(equalsImpl())
inline fun <A : Any> combine(lhs: A?, rhs: A?): Equals = combineEquals { lhs == rhs }
}
#Suppress("NOTHING_TO_INLINE")
object Objects {
inline fun hashCode(builder: HashCode.() -> HashCode): Int = builder(HashCode()).value
inline fun hashCode(vararg objects: Any?): Int = hashCode {
var hash = this
objects.forEach {
hash = hash.combine(it)
}
hash
}
inline fun hashCode(vararg hashes: Int): Int = hashCode {
var hash = this
hashes.forEach {
hash = hash.combineHash(it)
}
hash
}
inline fun <T : Any> equals(
lhs: T,
rhs: Any?,
allowSubclasses: Boolean = false,
builder: Equals.(T, T) -> Equals
): Boolean {
if (rhs == null) return false
if (lhs === rhs) return true
if (allowSubclasses) {
if (!lhs::class.isInstance(rhs)) return false
} else {
if (lhs::class != rhs::class) return false
}
#Suppress("unchecked_cast")
return builder(Equals(), lhs, rhs as T).value
}
}
This allows you to write a equals/hashcode implementation as follows:
data class Foo(val title: String, val bytes: ByteArray, val ignore: Long) {
override fun equals(other: Any?): Boolean {
return Objects.equals(this, other) { lhs, rhs ->
combine(lhs.title, rhs.title)
.combineEquals { lhs.bytes contentEquals rhs.bytes }
}
}
override fun hashCode(): Int {
return Objects.hashCode(title, bytes.contentHashCode())
}
}
I am trying to implement a QueryBus. Basically, I want to register a list of QueryHandlers. Each QueryHandler implements a handle method defined by an interface. Each QueryHandler is associated to a Query. I want to be able to retrieve a QueryHandler using the Query and call handle on it.
The thing is the handle has to be generic because each QueryHandler handles a Query differently. They all take a dedicated Query and may return whatever they want.
interface Query<R>
interface QueryHandler<R, Q : Query<R>> {
fun handle(query: Q): R
fun listenTo(): String
}
// DTOs
data class BookDto(val name: String)
// List books query
data class ListBooksQuery(val page: Int = 1): Query<List<BookDto>>
class ListBooksQueryHandler: QueryHandler<List<BookDto>, ListBooksQuery> {
override fun handle(query: ListBooksQuery): List<BookDto> {
return listOf(BookDto("Dune"), BookDto("Dune II"))
}
override fun listenTo(): String = ListBooksQuery::class.toString()
}
// Get book query
data class GetBookQuery(val name: String): Query<BookDto?>
class GetBookQueryHandler: QueryHandler<BookDto?, GetBookQuery> {
override fun handle(query: GetBookQuery): BookDto {
return BookDto("Dune")
}
override fun listenTo(): String = GetBookQuery::class.toString()
}
// Run it!
fun main(args: Array<String>) {
// Initializing query bus
val queryHandlers = mapOf(
with(ListBooksQueryHandler()) {this.listenTo() to this},
with(GetBookQueryHandler()) {this.listenTo() to this}
)
val command = ListBooksQuery()
val result = queryHandlers[command::class.toString()].handle(command)
// Should print the list of BookDto
print(result)
}
I don't even know if its possible, to be honest.
UPDATE 1:
I changed the usage example in the main to show what I am really trying to do. The List was for (bad?) demonstration purpose. I want to store the QueryHandlers and retrieve them from a map.
Additional resources:
Here is what I really want to do:
https://gist.github.com/ValentinTrinque/76b7a32221884a46e657090b9ee60193
UPDATE I've read your gist and tried to come up with a solution that will provide a clean interface to the user of the QueryBusMiddleware.
Note that I used objects instead of classes for the QueryHandler implementations, which felt more natural to me (since there is only one possible entry in the map for each Query implementation).
interface Query<R>
interface QueryHandler<R, Q: Query<R>> {
fun handle(query: Q): R
fun listenTo(): String
}
// DTOs
data class BookDto(val name: String)
// List books query
data class ListBooksQuery(val page: Int = 1): Query<List<BookDto>>
object ListBooksQueryHandler: QueryHandler<List<BookDto>, ListBooksQuery> {
override fun handle(query: ListBooksQuery): List<BookDto> {
return listOf(BookDto("Dune"), BookDto("Dune II"))
}
override fun listenTo(): String = ListBooksQuery::class.toString()
}
// Get book query
data class GetBookQuery(val name: String): Query<BookDto?>
object GetBookQueryHandler: QueryHandler<BookDto?, GetBookQuery> {
override fun handle(query: GetBookQuery): BookDto {
return BookDto("Dune")
}
override fun listenTo(): String = GetBookQuery::class.toString()
}
// Run it!
fun main(args: Array<String>) {
// Initializing query bus
val queryHandlers = listOf(
ListBooksQueryHandler,
GetBookQueryHandler
)
val dispatcher: QueryBusMiddleware = QueryDispatcherMiddleware(queryHandlers)
// Calling query bus
val query = ListBooksQuery()
// Result should be List<BookDto>
val result = dispatcher.dispatch(query)
print(result)
}
interface QueryBusMiddleware {
fun <R, Q : Query<R>> dispatch(query: Q): R
}
class QueryDispatcherMiddleware constructor(handlers: List<QueryHandler<*, *>>) : QueryBusMiddleware {
private val handlers = HashMap<String, QueryHandler<*, *>>()
init {
handlers.forEach { handler -> this.handlers[handler.listenTo()] = handler }
}
override fun <R, Q : Query<R>> dispatch(query: Q): R {
val queryClass = query::class.toString()
val handler = handlers[queryClass] ?: throw Exception("No handler listen to the query: $queryClass")
return handler::class.members.find { it.name == "handle" }!!.call(handler, query) as R
}
}
I have several data class with fields, which are used in forms and need them to have a method return true if any of the fields has been filled.
I don't want to rewrite this for all the classes, so I'm doing it like this at the moment:
data class Order(var consumer: String, var pdfs: List<URI>): Form {
override val isEmpty(): Boolean
get() = checkEmpty(consumer, pdfs)
}
data class SomethingElse(var str: String, var set: Set<String>): Form {
override val isEmpty(): Boolean
get() = checkEmpty(str, set)
}
interface Form {
val isEmpty: Boolean
fun <T> checkEmpty(vararg fields: T): Boolean {
for (f in fields) {
when (f) {
is Collection<*> -> if (!f.isEmpty()) return false
is CharSequence -> if (!f.isBlank()) return false
}
}
return true;
}
}
This is obviously not very pretty nor type-safe.
What's a more idiomatic way of doing this, without abstracting every property into some kind of Field-type?
Clarification: What I'm looking for is a way to get exhaustive when, for example by providing all the allowed types (String, Int, List, Set) and a function for each to tell if they're empty. Like an "extension-interface" with a method isEmptyFormField.
It's kinda hacky but should work.
Every data class creates set of method per each constructor parameters. They're called componentN() (where N is number starting from 1 indicating constructor parameter).
You can put such methods in your interface and make data class implicitly implement them. See example below:
data class Order(var consumer: String, var pdfs: List) : Form
data class SomethingElse(var str: String, var set: Set) : Form
interface Form {
val isEmpty: Boolean
get() = checkEmpty(component1(), component2())
fun checkEmpty(vararg fields: T): Boolean {
for (f in fields) {
when (f) {
is Collection -> if (!f.isEmpty()) return false
is CharSequence -> if (!f.isBlank()) return false
}
}
return true;
}
fun component1(): Any? = null
fun component2(): Any? = null
}
You can also add fun component3(): Any? = null etc... to handle cases with more that 2 fields in data class (e.g. NullObject pattern or handling nulls directly in your checkEmpty() method.
As I said, it's kinda hacky but maybe will work for you.
If all you are doing is checking for isEmpty/isBlank/isZero/etc. then you probably don't need a generic checkEmpty function, etc.:
data class Order(var consumer: String, var pdfs: List<URI>) : Form {
override val isEmpty: Boolean
get() = consumer.isEmpty() && pdfs.isEmpty()
}
data class SomethingElse(var str: String, var set: Set<String>) : Form {
override val isEmpty: Boolean
get() = str.isEmpty() && set.isEmpty()
}
interface Form {
val isEmpty: Boolean
}
However, if you are actually do something a bit more complex then based on your added clarification I believe that "abstracting every property into some kind of Field-type" is exactly what you want just don't make the Field instances part of each data class but instead create a list of them when needed:
data class Order(var consumer: String, var pdfs: List<URI>) : Form {
override val fields: List<Field<*>>
get() = listOf(consumer.toField(), pdfs.toField())
}
data class SomethingElse(var str: String, var set: Set<String>) : Form {
override val fields: List<Field<*>>
get() = listOf(str.toField(), set.toField())
}
interface Form {
val isEmpty: Boolean
get() = fields.all(Field<*>::isEmpty)
val fields: List<Field<*>>
}
fun String.toField(): Field<String> = StringField(this)
fun <C : Collection<*>> C.toField(): Field<C> = CollectionField(this)
interface Field<out T> {
val value: T
val isEmpty: Boolean
}
data class StringField(override val value: String) : Field<String> {
override val isEmpty: Boolean
get() = value.isEmpty()
}
data class CollectionField<out C : Collection<*>>(override val value: C) : Field<C> {
override val isEmpty: Boolean
get() = value.isEmpty()
}
This gives you type-safety without changing your data class components, etc. and allows you to "get exhaustive when".
You can use null to mean "unspecified":
data class Order(var consumer: String?, var pdfs: List<URI>?) : Form {
override val isEmpty: Boolean
get() = checkEmpty(consumer, pdfs)
}
data class SomethingElse(var str: String?, var set: Set<String>?) : Form {
override val isEmpty: Boolean
get() = checkEmpty(str, set)
}
interface Form {
val isEmpty: Boolean
fun <T> checkEmpty(vararg fields: T): Boolean = fields.all { field -> field == null }
}
The idea here is the same as that of an Optional<T> in Java but without the extra object, etc.
You now have to worry about null safety but if your fields are meant to have a concept of absent/empty then this seems appropriate (UsingAndAvoidingNullExplained ยท google/guava Wiki).