adding star projection in kotlin poet - kotlin

I am using KOTLIN Poet to generated some code. I am stuck with adding star projection for a parameterized type. Could not find anything of adding star projection in KOTLIN Poet docs.
Is there a way to add star projection in KOTLIN Poet.

To get a TypeName as a star projection, use:
ClassName("", "StarClass").parameterizedBy(STAR)
In a small example:
val starClass = ClassName("", "StarClass").parameterizedBy(STAR)
val exampleFile = FileSpec.builder("", "StackOverflow")
.addFunction(
FunSpec.builder("starFunction")
.addParameter("starClazz", starClass)
.addStatement("println(starClazz.toString())", starClass)
.build()
)
.build()
exampleFile.writeTo(System.out)
Outputs:
public fun starFunction(starClazz: StarClass<*>): Unit {
println(starClazz.toString())
}

Related

Kotlin - how to make a map serializable

I am programming in android (but for this question it might not matter). i have a kotlin map defined as follows:
var filters: MutableMap<String, Any?>
i need to pass it to another screen (Activity in android) and for this i ususally make it serializable in java. but in kotlin this data structure is not serializable. Lets see what i am trying to do:
var b = Bundle()
b.putSerializable("myFilter",filters) //- this gives a compile error that filters is not serializable.
I tried calling filters.toMap() but that does not work either. How is this done in kotlin ? how can i send a map to another screen in android ?
Use HashMap in place of MutableMap.
The bundle requires a Serialiable object. MutableMap is an interface and hence is not serialiable. HashMap is a concrete class which implements serializable. You can use any concrete sub class of Map which implements serializable
Create a hashmap :
val filters: HashMap<String, Any?> = HashMap()
filters.put("a", 2)
Or
val filters: HashMap<String, Any?> = hashMapOf("a" to 2)
Put into bundle:
val b = Bundle()
b.putSerializable("myFilter", filters)

Kotlin type-safe typealiases

I use typealiases in my Kotlin code a lot, but I wonder if I can enforce type-safety on them.
typealias Latitude = Double
typealias Longitude = Double
fun someFun(lat: Latitude, lon: Longitude) {...}
val lat: Latitude = 12.34
val lon: Longitude = 56.78
someFun(lon, lat) // parameters are in a wrong order, but the code compiles fine
It would be nice if I could somehow prevent implicit casting between typealiases, helping to avoid such issues.
Of course, there is a problem, that the operations on basic types would be not available for typealiases, but it can be solved with extension functions (or casts).
I don't want to use data classes, holding a single field, because it seems a bit of overkill, especially for primitive types (or maybe I am wrong and they'll be optimized out?)
So the question: can I somehow enforce type-safety for typealiases?
Update for Kotlin 1.3
Inline classes are already available as of Kotlin 1.3 and currently are marked as experimental. See the docs
Original answer
Unfortunately you can't avoid this currently. There is a feature in progress - inline classes (#9 in this document), which will solve the problem with the runtime overhead, while enforcing compile time type-safety. It looks quite similar to Scala's value classes, which are handy if you have a lot of data, and normal case classes will be an overhead.
Unfortunately this is not possible with typealiases. The kotlin reference says:
Type aliases do not introduce new types. They are equivalent to the
corresponding underlying types. When you add typealias Predicate<T>
and use Predicate<Int> in your code, the Kotlin compiler always expand
it to (Int) -> Boolean. Thus you can pass a variable of your type
whenever a general function type is required and vice versa:
typealias Predicate<T> = (T) -> Boolean
fun foo(p: Predicate<Int>) = p(42)
fun main(args: Array<String>) {
val f: (Int) -> Boolean = { it > 0 }
println(foo(f)) // prints "true"
val p: Predicate<Int> = { it > 0 }
println(listOf(1, -2).filter(p)) // prints "[1]"
}
See kotlin type aliases.
tl;dr You have to use (data) classes
As the name typealias implies, a typealias is only a alias and not a new type. In your example Latitude and Longitude are Ints, independet from their names. To make them typesafe you have to declare a type. In theory you could inherit new types from Int. Since Int is a final class this is not possible. So its reqiuered to create a new class.
You can use inline classes for this (since Kotlin 1.5). Inline classes are erased during complication, so at runtime lat and lon are just doubles, but you get the benefit of the compile-time checks.
#JvmInline
value class Latitude(private val value: Double)
#JvmInline
value class Longitude(private val value: Double)
fun someFun(lat: Latitude, lon: Longitude) {
println("($lat, $lon)")
}
fun main() {
val lat = Latitude(12.34)
val lon = Longitude(56.78)
someFun(lon, lat) // Type mismatch: inferred type is Longitude but Latitude was expected
someFun(lat, lon) // OK
}
Here is the difference between typealias and inline classes for the case of avoiding params wrong order:
typeAlias:
typealias LatitudeType = String
typealias LongitudeType = String
fun testTypeAlias() {
val lat: LatitudeType = "lat"
val long: LongitudeType = "long"
testTypeAliasOrder(lat, long) // ok
testTypeAliasOrder(long, lat) // ok :-(
}
fun testTypeAliasOrder(lat: LatitudeType, long: LongitudeType) {}
inline classes:
#JvmInline
value class Latitude(val lat: String)
#JvmInline
value class Longitude(val long: String)
fun testInlineClasses() {
val lat = Latitude("lat")
val long = Longitude("long")
testInlineClassesOrder(lat, long) // ok
testInlineClassesOrder(long, lat) // Compilation error :-)
}
fun testInlineClassesOrder(lat: Latitude, long: Longitude) {}
I've been interested in this topic for quite a while. This is what I came up with.
I would define an interface for an Id type and I would implement it:
interface UniqueId<T> {
fun getId(): T
fun toExternal(): String
}
data class UniqueIdImpl<T>(private val id: T) : UniqueId<T> {
override fun getId(): T = id
override fun toExternal(): String = "External-$id"
}
(For the sake of the example, I could have made it simpler by omitting the type parameter and just go for Int...)
Then you define your types like so, using delegation:
data class ClientId(private val id: UniqueId<Int>): UniqueId<Int> by id
data class OrderId(private val id: UniqueId<Int>): UniqueId<Int> by id
data class SomeId(private val id: UniqueId<UUID>): UniqueId<UUID> by id
And this is how to use them:
val clientId = ClientId(UniqueIdImpl(1))
val someId = SomeId(UniqueIdImpl(UUID.randomUUID()))
EDIT:
Well, you can get similar effect with abstract classes...
abstract class I<T>(private val i: T) {
fun getId() = i
fun toExternal() = "External-$i"
}
data class OtherId(private val i: Int) : I<Int>(i)
data class YetAnotherId(private val i: UUID) : I<UUID>(i)
By defining Latitude and also Longitude as aliases for Double it can be seen as transitive aliases, i.e. you defined Latitude as an alias for Longitude and vice versa. Now, all three type names can be used interchangeably:
val d: Double = 5.0
val x: Latitude = d
val y: Longitude = x
You could, as an alternative, simply use parameter names to make clear what is being passed:
fun someFun(latitude: Double, longitude: Double) {
}
fun main(args: Array<String>) {
val lat = 12.34
val lon = 56.78
someFun(latitude = lon, longitude = lat)
}
I was recently struggling with similar case. Inline classes are not the solution cause it forces me to use property wrapper.
Hopefully for me I've managed to solve my problem by inheritance delegation.
class ListWrapper(list: List<Double>): List<Double> by list
This approach allows us to operate directly on ListWrapper as on regular List. Type is strictly identified so it might be passed via the Koin dependency injection mechanism for example.
We can go even deeper:
class ListListWrapper(list: ListWrapper): ListWrapper by list
but this require us to "open" the parent class with reflection cause `#Suppress("FINAL_SUPERTYPE") does not work.
Unfortunately with primitives there is other issue, cause they somehow providing only empty private constructor and are initialized with some undocumented magic.

Kotlin smart cast with Stream

I have interface A and class B: A
val a: Stream<A>
val b: Stream<B> = a.filter { it is B }
.map { it as B }
Is there a way to write this using Kotlin smart casts?
Is there a way to write this using Kotlin smart casts?
No, this is not possible with basic static analysis as there no indicator that a, after being filtered, only contains Bs, as it is still a Stream<A>, so you must check this yourself. Kotlin's smart casting is applied only to the value of a variable and not to a type parameter.
AFAIK there isn't anything that does this in the Java or Kotlin libraries for Streams, but you could convert the stream to a Sequence and use filterIsInstance:
a.asSequence().filterIsInstance<B>().asStream()
Of course, you could also implement this functionality directly on streams with an extension method:
inline fun <reified B> Stream<*>.filterIsInstance() = a.filter { it is B }.map { it as B }
...
val a: Stream<A>
val b: Stream<B> = a.filterIsInstance<B>()
Just a comment: do you need to use Streams? I would consider using Kotlin's Sequences from the start instead.

Wildcards generic in Kotlin for variable

Is it possible to declare generic wildcards in Kotlin like this code in Java:
List<Integer> a = new ArrayList<>();
List<? extends Number> b = a;
The equivalent in Kotlin would be like this:
val a = ArrayList<Int>()
val b: ArrayList<out Number> = a
Kotlin doesn't have wildcards, it uses the concepts of declaration-site variance and type projections instead.
Please check the documentation, covers pretty extensively.
Kotlin provides so called star-projection
val a = ArrayList<Int>()
val b: ArrayList<out Number> = a

BiMap / 2-way hashmap in Kotlin

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()