As http://kotlinlang.org/docs/reference/multi-declarations.html#multi-declarations says:
The component1() and component2() functions are another example of the principle of conventions widely used in Kotlin (see operators like + and *, for-loops etc.). Anything can be on the right-hand side of a destructuring declaration, as long as the required number of component functions can be called on it. And, of course, there can be component3() and component4() and so on.
For example,
class Pair<K, V>(val first: K, val second: V) {
operator fun component1(): K {
return first
}
operator fun component2(): V {
return second
}
}
But I think it's very boring to manually input these methods. So is there any way to generate these methods in IDEA.
You can let IDEA help you. Take the following example, a simple class without componentX functions:
class Ex(val a: Int, val b: Int)
And then a destructuring of it, which does not compile:
val (a,b) = Ex(1,2)
IDEA will give you some hints on how to fix the problem if you use the shortcut "Show intention action":
Try to use data classes.
In such case, you class should looks like:
data class Pair<K, V>(val first: K, val second: V)
https://kotlinlang.org/docs/reference/data-classes.html
Related
I'm trying to reduce boilerplate on something I'm working on and wondering if something is possible - I suspect it's not but was looking for confirmation
class Something<T> {
private val list = mutableListOf<T>()
fun addToList(value: T) = list.add(value) }
So if I wanted to use this with a class like:
class Data(number: Int, letter: Char)
I'd have to use addToList like:
addToList(Data(1,"a"))
Is there some way to use the supplied type T to construct the method addToList dynamically? So that the class would be instantiated like:
val thing = Something<Data>()
but then addToList were called like
addToList(1,"a")
Like I said, don't think this is possible but was looking for confirmation.
What I was really trying to do was come up with something that would allow me to do this without declaring Data at all, but instead just define the structure and the subsequent addToList method when Something() was instantiated - not sure if I have described this all that well but if anyone has any suggestions in general around that I'd be grateful!
Thanks!
There are Pair and Triple tuple classes provided in the standard library which allows you to avoid declaring a class for simple combinations of values. If you need more than 3 parameters of different types, you'd need to create your own class or use a library that provides larger tuple classes. If all types are the same, you can use List instead of a tuple.
In my opinion even Triple is pushing it and anything with more than two distinct properties should just have its own data class defined.
class Something<A, B> {
private val list = mutableListOf<Pair<A, B>>()
fun addToList(valueA: A, valueB: B) = list.add(Pair(valueA, valueB))
}
val something = Something<Int, String>()
something.addToList(1, "a")
An alternate approach if you want to keep the flexibility of your Something class to hold anything would be to use an extension function.
class Something<T> {
private val list = mutableListOf<T>()
fun addToList(value: T) = list.add(value)
}
fun <A, B> Something<Pair<A, B>>.addToList(valueA: A, valueB: B) =
addToList(Pair(valueA, valueB))
val something = Something<Pair<Int, String>>()
something.addToList(1, "a")
I struggle with providing a type as parameter for a procedure that uses the enumValues<MyEnum>() function.
Got it to work with reified but using inline functions all the way is no option for me.
fun <T: Enum<Trait>> traits(
selectionState: SnapshotStateMap<Trait, Boolean>
) {
val chunks = enumValues<T>().toList().chunked(5)
chunks.forEach {
Row {
it.forEach {
TraitIcon(it, selectionState)
}
}
}
}
My enums all derive from enum class Trait. So in fact I want to pass enum class TraitFoo: Trait, enum class TraitBar: Trait and so on into the function.
Cannot use 'T' as reified type parameter. Use a class instead.
Is the compile error I receive here. Any idea of solving this? I am somewhat confused why this is not working.
Looking at the implementation of enumValues:
public inline fun <reified T : Enum<T>> enumValues(): Array<T>
I see it uses reified. That does mean the type has to be known at compile time. Therefore I can not pass a generic but need to pass an explicit type? Is that the issue?
If yes - is there another way to achieve this rather than using reified ?
If you want to be able to use T in your function as if it's a real type then it must be reified. And in order for a type parameter to be reified it must be part of an inline function. So you're going to need an inline function.
The next bit is figuring out the generics. You currently have:
<T : Enum<Trait>>
That means, due to the nature of enums, that T can't possibly be anything other than Trait. However, you have since clarified that Trait is not an enum but is actually an interface that's implemented by various enum classes. So what you really want is T to be bounded by both Enum<T> and Trait.
Given all this, I believe what you're looking for is the following:
inline fun <reified T> traits(
selectionState: SnapshotTraitMap<Trait, Boolean>
) where T : Enum<T>, T : Trait {
val chunks = enumValues<T>().toList().chunked(5)
chunks.forEach {
Row {
it.forEach {
TraitIcon(it, selectionState)
}
}
}
}
I want to write a function like this, where T must be the same data-type for both variables, but can be anything as long as they are the same.
fun <T> doSomething(var1: T, var2: T) {}
When I write this, it will work with any two variables, such as
doSomething(5, listOf<Thread>())
The current assumption is it assumes that since int and list are different, that T is now considered Any?
Is there any way to make this work? A coworker is using Swift and it works as expected for him, failing to compile if either item is a different type.
I tried using reified functions as well, but same problem. It only causes a compile error if I explicitly added the reified class at the start, it just assumes it's any otherwise.
E.G.
inline fun <reified T> doSomething(var1: T, var2: T) { }
doSomething(1,"2") <-- unwanted compile
doSomething<String>(1,"2") <-- Will not compile
But I don't want to only have the function work if the person remembers to add the explicit type on it...
Sounds like maybe your coworker is adding associated type constraints. Kotlin doesn't have associated types, but it might be similar to specifying your Kotlin function with something like this:
fun <T> doSomething(var1: Comparable<T>, var2: Comparable<T>)
which in Kotlin would enforce the same type for primitives, for instance doSomething(3, 4). doSomething(4, "x") would fail to compile because the arguments do not both implement a Comparable of the same type.
If you also need to handle collections, you can overload the function:
fun <T> doSomething(var1: Iterable<Comparable<T>>, var2: Iterable<Comparable<T>>)
This probably covers most of the use cases you described in the comments.
I don't like comparable approach because it won't work for all types. I think this will do the trick, although has strange syntax:
fun <T> doSomething(var1: T) = fun(var2: T) {
println("Hello $var1 and $var2")
}
fun te() {
doSomething(42)("Text") // Error
doSomething(42)(78) // OK
}
You can also easily expand it:
fun <T> doSomething(var1: T) = fun(var2: T) = fun(var3: T) {
println("Hello $var1 and $var2 and $var3")
}
The following example is perfectly legal in Kotlin 1.3.21:
fun <T> foo(bar: T): T = bar
val t: Int = foo(1) // No need to declare foo<Int>(1) explicitly
But why doesn't type inference work for higher order functions?
fun <T> foo() = fun(bar: T): T = bar
val t: Int = foo()(1) // Compile error: Type inference failed...
When using higher order functions, Kotlin forces the call site to be:
val t = foo<Int>()(1)
Even if the return type of foo is specified explicitly, type inference still fails:
fun <T> foo(): (T) -> T = fun(bar: T): T = bar
val t: Int = foo()(1) // Compile error: Type inference failed...
However, when the generic type parameter is shared with the outer function, it works!
fun <T> foo(baz: T) = fun (bar: T): T = bar
val t: Int = foo(1)(1) // Horray! But I want to write foo()(1) instead...
How do I write the function foo so that foo()(1) will compile, where bar is a generic type?
I am not an expert on how type inference works, but the basic rule is: At the point of use the compiler must know all types in the expression being used.
So from my understanding is that:
foo() <- using type information here
foo()(1) <- providing the information here
Looks like type inference doesn't work 'backward'
val foo = foo<Int>()//create function
val bar = foo(1)//call function
To put it in simple (possibly over-simplified) terms, when you call a dynamically generated function, such as the return value of a higher-order function, it's not actually a function call, it's just syntactic sugar for the invoke function.
At the syntax level, Kotlin treats objects with return types like () -> A and (A, B) -> C like they are normal functions - it allows you to call them by just attaching arguments in parenthesis. This is why you can do foo<Int>()(1) - foo<Int>() returns an object of type (Int) -> (Int), which is then called with 1 as an argument.
However, under the hood, these "function objects" aren't really functions, they are just plain objects with an invoke operator method. So for example, function objects that take 1 argument and return a value are really just instances of the special interface Function1 which looks something like this
interface Function1<A, R> {
operator fun invoke(a: A): R
}
Any class with operator fun invoke can be called like a function i.e. instead of foo.invoke(bar, baz) you can just call foo(bar, baz). Kotlin has several built-in classes like this named Function, Function1, Function2, Function<number of args> etc. used to represent function objects. So when you call foo<Int>()(1), what you are actually calling is foo<Int>().invoke(1). You can confirm this by decompiling the bytecode.
So what does this have to do with type inference? Well when you call foo()(1), you are actually calling foo().invoke(1) with a little syntactic sugar, which makes it a bit easier to see why inference fails. The right hand side of the dot operator cannot be used to infer types for the left hand side, because the left hand side has to be evaluated first. So the type for foo has to be explicitly stated as foo<Int>.
Just played around with it a bit and sharing some thoughts, basically answering the last question "How do I write the function foo so that foo()(1) will compile, where bar is a generic type?":
A simple workaround but then you give up your higher order function (or you need to wrap it) is to have an intermediary object in place, e.g.:
object FooOp {
operator fun <T> invoke(t : T) = t
}
with a foo-method similar as to follows:
fun foo() = FooOp
Of course that's not really the same, as you basically work around the first generic function. It's basically nearly the same as just having 1 function that returns the type we want and therefore it's also able to infer the type again.
An alternative to your problem could be the following. Just add another function that actually specifies the type:
fun <T> foo() = fun(bar: T): T = bar
#JvmName("fooInt")
fun foo() = fun(bar : Int) = bar
The following two will then succeed:
val t: Int = foo()(1)
val t2: String = foo<String>()("...")
but... (besides potentially needing lots of overloads) it isn't possible to define another function similar to the following:
#JvmName("fooString")
fun foo() = fun(bar : String) = bar
If you define that function it will give you an error similar as to follows:
Conflicting overloads: #JvmName public final fun foo(): (Int) -> Int defined in XXX, #JvmName public final fun foo(): (String) -> String defined in XXX
But maybe you are able to construct something with that?
Otherwise I do not have an answer to why it is infered and why it is not.
is there a bidirectional hashmap for kotlin?
If not - what is the best way to express this in kotlin?
Including guava to get the BiMap from there feels like shooting with a very big gun on a very little target - no solution that I can imagine currently feels right - the best thing I have in mind is to write a custom class for it
I need a simple BiMap implementation too so decided to create a little library called bimap.
The implementation of BiMap is quite straightforward but it contains a tricky part, which is a set of entries, keys and values. I'll try to explain some details of the implementation but you can find the full implementation on GitHub.
First, we need to define interfaces for an immutable and a mutable BiMaps.
interface BiMap<K : Any, V : Any> : Map<K, V> {
override val values: Set<V>
val inverse: BiMap<V, K>
}
interface MutableBiMap<K : Any, V : Any> : BiMap<K, V>, MutableMap<K, V> {
override val values: MutableSet<V>
override val inverse: MutableBiMap<V, K>
fun forcePut(key: K, value: V): V?
}
Please, notice that BiMap.values returns a Set instead of a Collection. Also BiMap.put(K, V) throws an exception when the BiMap already contains a given value. If you want to replace pairs (K1, V1) and (K2, V2) with (K1, V2) you need to call forcePut(K, V). And finally you may get an inverse BiMap to access its keys by values.
The BiMap is implemented using two regular maps:
val direct: MutableMap<K, V>
val reverse: MutableMap<V, K>
The inverse BiMap can be created by just swapping the direct and the reverse maps. My implementation provides an invariant bimap.inverse.inverse === bimap but that's not necessary.
As mentioned earlier the forcePut(K, V) method can replace pairs (K1, V1) and (K2, V2) with (K1, V2). First it checks what the current value for K1 is and removes it from the reverse map. Then it finds a key for value V2 and removes it from the direct map. And then the method inserts the given pair to both maps. Here's how it looks in code.
override fun forcePut(key: K, value: V): V? {
val oldValue = direct.put(key, value)
oldValue?.let { reverse.remove(it) }
val oldKey = reverse.put(value, key)
oldKey?.let { direct.remove(it) }
return oldValue
}
Implementations of Map and MutableMap methods are quite simple so I will not provide details for them here. They just perform an operation on both maps.
The most complicated part is entries, keys and values. In my implementation I create a Set that delegates all method invocations to direct.entries and handle modification of entries. Every modification happens in a try/catch block so that the BiMap remains in consistent state when an exception is thrown. Moreover, iterators and mutable entries are wrapped in similar classes. Unfortunately, it makes iteration over entries much less efficient because an additional MutableMap.MutableEntry wrapper is created on every iteration step.
If speed is not a priority ( O(n) complexity ) you can create an extension function: map.getKey(value)
/**
* Returns the first key corresponding to the given [value], or `null`
* if such a value is not present in the map.
*/
fun <K, V> Map<K, V>.getKey(value: V) =
entries.firstOrNull { it.value == value }?.key
FWIW, you can get the inverse of the map in Kotlin using an extension function:
fun <K, V> Map<K, V>.inverseMap() = map { Pair(it.value, it.key) }.toMap()
The map operator can be used to iterate over the List of key-value pairs in the Map, then convert back to a map using .toMap().
Well, you are right - as it stated in a similar question for Java "Bi-directional Map in Java?", Kotlin does not have BiMap out of the box.
The workarounds include using Guava and creating a custom class using two usual maps:
class BiMap<K, V>() {
private keyValues = mutableMapOf<K, V>()
private valueKeys = mutableMapOf<V, K>()
operator fun get(key: K) = ...
operator fun get(value: V) = ...
...
}
This solution should not be slower or take more memory than a more sophisticated one. Although I am not sure what happens when K is the same as V.
The cleanest solution to to use Guava and create an extension function that turns a Map into a BiMap. This follows the semantics of Kotlin's other Map conversions as well. Although Guava might have a bit of overhead, you gain the flexibility to add more extension functions wrappers in the future. You can always remove Guava in the future and replace the extension function with another implementation.
First declare your extension function.
fun <K, V> Map<K, V>.toBiMap() = HashBiMap.create(this)
Then use it like this:
mutableMapOf("foo" to "bar", "me" to "you").toBiMap()