in kotlin how to change to Array<CharSequence> from Array<String> - kotlin

From one library module it returns some Array<Array<String>>, like below:
private val BASIC_ESCAPE_RULE = arrayOf(arrayOf("\"", """), // "
arrayOf("&", "&"),
arrayOf("<", "<"),
arrayOf(">", ">"))
fun getBasicEscapeRule(): Array<Array<String>> {
return BASIC_ESCAPE_RULE.clone()
}
In the project it has dependency on that library and it also uses another library module to do lookup/translation, which only takes Array<CharSequence>.
class translator (vararg lookup: Array<CharSequence>) {
... ...
fun translate(content: String) : String {}
}
When trying to call into a the second library's routing with the data getting from the first library,
the making of the translator translator(*getBasicEscapeRule()) got error:
Type mismatch: inferred type is Array<Array<String>> but Array<out Array<CharSequence>> was expected
In the second library it needs to use CharSequence for char manipulation.
How to convert the Array into Array?

To transform an Array<Array<String>> into an Array<Array<CharSequence>>, you can use the following code:
val src: Array<Array<String>> = TODO()
val result: Array<Array<CharSequence>> =
src.map { array -> array.map { s -> s as CharSequence }.toTypedArray() }.toTypedArray()

Related

Kotlin: Type inference failed. The value of the type parameter T should be mentioned in input types

I'm new to Kotlin, for the piece of the below code:
fun a(stcd: String) {
val res = mutableSetOf<String>()
val aaa = mutableListOf<Map<String, Set<String>>>()
aaa.stream().filter { x: Map<String, Set<String>> -> x.isNotEmpty() }
.filter { x: Map<String, Set<String>> ->
x.values.contains(stcd) // throws error
}.forEach { x: Map<String, Set<String>> ->
x.forEach { (k: String, v: Set<String>?) ->
res.add(k)
}
}
}
Could anyone point out why contains throws error:Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.?
This is because x.values is not a Set<String>, as you probably think it is. In fact, it's aCollection<Set<String>> as per the definition of values. So, such a collection can't contain a String type.

Kotlin - output type from type parameter

I am parsing multiple CSV files and would like to provide my application with some generic parsers with logging capabilities. Is it possible to give some generic solution for it?
My try to do that is:
interface Converter<out T> {
fun convert(fieldName: String, value: String): T?
}
object DoubleMapper : Converter<Double> {
private val log = LoggerFactory.getLogger(this::class.java)
override fun convert(fieldName: String, value: String): Double {
log.info("Converting $fieldName: $value to Double")
return 123.3
}
}
object ConverterProvider {
private val log = LoggerFactory.getLogger(ConverterProvider::class.java)
inline fun <reified T : Any> getConverter(): (String, String) -> T {
return when (T::class) {
Double::class -> DoubleMapper::convert
Int::class -> IntMapper::convert
else -> {
throw java.lang.RuntimeException("We do not have mapper")
}
}
}
}
However, this does not compile, does kotlin provide such capabilities to have function return type depend on type parameter?
Your solution is almost correct one. The only problem is that the compiler is not smart enough to understand that you verified the type of T and you return the right type of the converter. You just need to cast the converter to T:
return when (T::class) {
...
} as (String, String) -> T
This cast is unchecked, meaning that the compiler can't guarantee at runtime that the cast is safe. However, as long as you return correct converter for the T, such cast should be safe and you can just suppress the warning:
#Suppress("UNCHECKED_CAST")
return when (T::class) {
...
} as (String, String) -> T

Kotlin DSL - type inference on returned value

I'm trying to introduce the following (simplified) DSL:
fun <T> myDsl(specFn: DslSpec<T>.() -> Unit) {
val value = DslSpec<T>().apply(specFn).fn!!()
println("value is: $value")
}
class DslSpec<T> {
internal var fn: (() -> T)? = null
fun getValue(fn: () -> T) {
this.fn = fn
}
}
fun testCase() {
myDsl {
getValue {
"abc"
}
}
}
But it fails to infer T based just on the returned type of getValue ("Not enough information to infer type variable T"). I kind of see how it could be a very hard task to do for a compiler, but thought maybe there are already some tricks to make constructs like this work?
If you're using a version of Kotlin < 1.6.0, you should add #BuilderInference to the specFn argument:
fun <T> myDsl(#BuilderInference specFn: DslSpec<T>.() -> Unit) {
...
}
https://pl.kotl.in/__xy04j88
If you're using a version >= 1.6.0, you should either use the annotation as well, or both your declarations and their usages must be compiled with the compiler argument -Xenable-builder-inference.

Kotlin SAM interface and method reference

I am a bit confused why I can do the following
val outputter1: (s: String) -> Unit = ::println
but when I do
val outputter2: Outputter = ::println
given
fun interface Outputter {
fun output(output: String)
}
I get a compilation error
None of the following functions can be called with the arguments supplied.
println() defined in kotlin.io
println(Any?) defined in kotlin.io
...
Shouldn't method references translate to SAM inteface types as well as Function types?
Apparently, SAM conversions must be explicit in assignments (despite the type declaration) using the auto-generated adapter functions:
val outputter2: Outputter = Outputter { println(it) } // OK
val outputter3: Outputter = Outputter(::println) // OK
val outputter4: Outputter = { s: String -> println(s) } // compile error
But they are inferred fine in function calls:
fun main() {
takesOutputter(::println) // OK
}
fun takesOutputter(o: Outputter) {
o.output("test")
}
For reference, checkout the doc on Kotlin SAM conversions, and this part in the Java interop section which gives more examples of SAM conversions.

Receive transformation map function to send into `List<>.mapNotNull()`

Im trying to write a function like transform that receives a function that will be used inside of mapNotNull but I cant find a way to do it.
Example
val items: List<String?> = listOf(null, "cosa")
fun transform(transformer: (String) -> String?) {
items.mapNotNull(transformer) // <-------------------------------------- THIS DOES NOT COMPILE
}
fun main() {
val items: List<String?> = listOf(null, "cosa")
val transformer: (String) -> String? = {
null
}
val map = transform(transformer)
print(map)
}
You can check how this works here: play.kotlinlang
How can I declare the parameter of fun transform to be able to pass it inside of the mapNotNull ?
The mapNotNull function is defined as:
public inline fun <T, R : Any> Iterable<T>.mapNotNull(transform: (T) -> R?): List<R>
in other words, the type of the parameter to the transform lambda is T, where T is the type of the Iterable being operated on. In your case, your iterable is a List of type String?.
Therefore, you need to declare your transformer as type (String?) -> String?, and only the non-null results of that transform will be included in the result.
To update the code you supplied on play.kotlinlang, with a few additional modifications to make the type declarations a bit more idiomatic -- note, I've left the code mostly as-is, despite the odd use of the additional transform function:
val items = listOf<String?>(null, "cosa")
fun transform (transformer: (String?) -> String?): List<String> {
return items.mapNotNull(transformer)
}
fun main() {
val items = listOf<String?>(null, "cosa")
val transformer: (String?) -> String? = {
// this of course means the output of transform will always be empty
null
}
val map = transform(transformer)
print(map)
}
You have a list of nullable strings.
mapNotNull applies the transform function to an each element in a list and then checks if the result of this functions is null. So in this case, it passes a nullable string in the transformer function, and that function definitely cannot be of (String) -> String? type because the parameter here is a non-nullable string.
You should either declare the transformer function as (String?) -> String?, or remove nulls from list before calling mapNotNull:
items.filterNotNull().mapNotNull(transformer)
Another option is to wrap transformer into a lambda function before passing it to mapNotNull and handle null elements there, for example:
items.mapNotNull { e -> e?.let(transformer) }
this applies transformer function to an element only if it is not null.