val (_,time) = time { Thread.sleep(1000) }
I see the Left Hand Side (LHS) has a val, so its declaring a variable. LHS also has some kind of a function syntax which does not look like a lambda declaration. What is (_,time)? Don’t you have to give a type to the time on the LHS? I understand the RHS perfectly well: it is a function which accepts a lambda as parameter and is named ‘time’. Original code
The left hand side is called destructuring.
If you try to assign an instance of a data class (or any class which has componentN functions) to a variable you can desturcture it. This means that you can assign its internals to variables. The _ syntax indicates that you don't care about the first item.
Example:
class Foo(val first: String, val second: String) {
operator fun component1() = first
operator fun component2() = second
}
Usage:
val (first, second) = Foo("first", "second")
If you use data classes you don't need to create the componentN functions, they are generated for you.
Equivalent data class:
data class Foo(val first: String, val second: String)
Related
I work with a lot's of generated kotlin data classes (openapi-generated) with val's and two common fields available and processed. So i can assign values only on construction, like:
data class StringRepresentation {
val value: String,
val available: Boolean,
val processed: Boolean,
}
data class DoubleRepresentation {
val value: Double,
val available: Boolean,
val processed: Boolean,
}
And i have to init lot's of them with common robust code, like:
val currentRepresentation = StringRepresentation("Something", true, false)
Can any pattern or Kotlin language support be used to remove robost object initialization?
It could be wonderful to use some kind of generic template method, something like this:
private inline fun <reified T: StringRepresentation> buildRepresentation(
value: Any,
available: Boolean,
processed: Boolean
): T {
return when(T) {
is StringRepresentation -> StringRepresentation(value.toString(), available, processed)
else -> ...
}
}
, but my types and properties are final and also syntax doesn't allow to set multiple generic boundaries. I can't figure it out the right approach for this. I guess in that case I need to write a builder, but this seems to be java way.
Is there any kotlin way to do this?
I do not think that it is possible with your setup to write a builder that would actually be useful. Your *Representation data types stand in no explicit type relation to their respective type parameter (e.g. a StringRepresentation is not Something<String>), so what should be the return type of a generic builder function? It could only be Any and you would need to cast every result to its expected type in order to use it.
What you can do is to define a generic data class:
data class Representation<T>(
val value: T,
val available: Boolean,
val processed: Boolean,
)
I know, you cannot use that class as super class of your specific data classes, but you can write extension functions that convert the generic representation for one value type into its corresponding specific representation:
fun Representation<String>.typed() = StringRepresentation(value, available, processed)
fun Representation<Double>.typed() = DoubleRepresentation(value, available, processed)
Then you can use the same code to create a data object of any type:
val stringRepresentation: StringRepresentation = Representation("x", false, true).typed()
val doubleRepresentation: DoubleRepresentation = Representation(1.0, false, true).typed()
But please note that this is still not a generic solution since whatever you put into the constructor Representation has to be typed explicitly as a String or Double, respectively.
Let's say you define a generic function for all undefined value types:
fun <T: Any> Representation<T>.typed(): Any = error("no typed representation for value type ${value::class}")
The specific cases above will still work, and you could additionally write something like this:
val x : Any = 2.0
val someRep: Any = Representation(x, true, false).typed()
This is syntactically correct and will compile, but it will not work as desired, because what you get is an IllegalArgumentException ("no typed representation for value type class kotlin.Double"), because x is not typed as Double, but as Any.
Is it possible to Kotlin Compiler to infer type parameter based on another type parameter?
That is: infere type A based on type B in IntExample class definition.
interface Something<A>
interface Example<A, B: Something<A>>
class IntSomething: Something<Int>
// Can Int type parameter be infered by the fact that IntSomething is Something<Int>?
// If yes, how could I specify B type parameter without specifing the infered A (Int) parameter?
class IntExample: Example<Int, IntSomething> // specifing Int here is painful!!!
Imagine that we have more type parameters like that - it will be a lot of boilerplate to specify each of them if some might (theoretically) be infered.
EDIT
After an exhausive respose from #KarstenGabriel I will extend the previous example, to make it clear what for are the type parameters used here:
interface Something<A> {
val sth: A
}
interface Example<A, B: Something<A>> {
val eg: A
val something: B
}
data class IntSomething(override val sth: Int): Something<Int>
data class DescribedIntSomething(
override val sth: Int,
val description: String
): Something<Int>
data class DescribedIntExample(
override val eg: Int,
override val something: DescribedIntSomething,
): Example<Int, DescribedIntSomething> // specifing Int here is painful
fun main() {
val describedIntExample = DescribedIntExample(
eg = 1,
something = DescribedIntSomething(1, "Just one")
)
// We have to know that something is DescribedIntSomething to read description.
// Neither `*` nor `Something<Int>` is sufficient, we need `B: Something<Int>` to keep B
val description = describedIntExample.something.description
println(description)
}
So we use the type parameters - A and B as return values from eg and something
Wildcard * cannot be used as it is just means Any?. We need to keep concrete type B. (eg. to enable reading descrption in the example)
Wildcard Something<Int> cannot be used instead of B: Something<Int> for thesame reason as in the point 1
Maybe it's just an language design level. The type parameters do exists in compile time (they are ereased later), so theoretically Example<DescribedIntSomething> might be sufficient instead of Example<Int, DescribedIntSomething> as DescribedIntSomething is Something<Int>
The problem is solvable under some assumptions:
You need type parameter A only for property eg (or other similar cases).
It is okay that we convert eg to be a function instead of a property.
The desired value for eg (your A value) can be derived from the value of something (your B value). If the value is not inferred, then it is not possible to infer the type.
We then define Example without parameter A:
interface Example<B: Something<*>> {
val something: B
}
Now inside Example we do not have a possibility to obtain the type parameter of B's Something-type, because the type parameter A on Something<A> does not exist at runtime. So you cannot just ask an instance of B what its Something-type parameter is. And Kotlin cannot do that either, because the information is just not there, if it is not explicitly specified by you.
But we know the parameter at compile-time which can be used in an inline extension function with reified parameter:
inline fun <reified A, reified B : Something<A>> Example<B>.eg(): A = something.sth
(documentation: Inline functions with reified parameter and Extension functions)
In this example I assume that eg should have the value of sth.
If you want eg to be private, you can put the function inside Example and make it private, otherwise it must be specified outside of the class.
Now you can just define your subclass without the need to specify the former A parameter, but you still have the right type:
data class DescribedIntExample(
override val something: DescribedIntSomething,
) : Example<DescribedIntSomething>
fun main() {
val describedIntExample = DescribedIntExample(
something = DescribedIntSomething(1, "Just one")
)
val x = describedIntExample.eg() // x has inferred type Int and value 1
}
Have a question about -> in kotlin.
fun test0 (a: String, combine: (b: String) -> String ): String {
return combine(a)
}
There is a example function above, how to use this function?
I dont know how to pass the parm combine.
Have tried follow:
private fun getFold(a: String): String {
return a
}
fun test() {
var a: String = "a"
val test1 = test0 (a, combine = getFold(a))
}
Sync error in combine = getFold(a)) ,say:
Type mismatch. Required:(String) → String Found: String
So how to pass the parm combine?
In your example, combine is a parameter of type (b: String) -> String, which is a function taking a single String and returning a String.
(In fact, you don't need to name the parameter b; it could simply be written (String) -> String.)
There are three main ways to pass a function as a parameter:
As a lambda. This is perhaps the most common: you provide the function body directly, in braces. For example:
val test1 = test0(a, { it })
Here the lambda is { it }. (it is a keyword you can use in lambdas which take a single parameter, and refers to that parameter. An equivalent might be { a -> a }.)
In fact, because the function parameter is the last parameter, Kotlin lets you move the lambda after the parens:
val test1 = test0(a){ it }
This means exactly the same, but in some cases it can read better (by making the function call look like language syntax; functions like map and filter are often called that way).
As an anonymous function. This is similar to a lambda, but the syntax is more like defining a normal function; it's more verbose, but gives you more control. In this case you could use a normal function body:
val test2 = test0(a, fun(b: String): String { return b })
Or an expression body:
val test2 = test0(a, fun(b: String) = b)
As a callable reference. This is for when you have an existing method or function that you want to use. (You might already have a suitable function in your project, or in a library; or the code might be too long to fit neatly into a lambda.)
It's done using the :: operator, e.g.:
val test3 = test0(a, ::getFold)
You can reference a method, top-level function, extension function, property, or constructor in this way. (If it's not a top-level function, you may need to tell the compiler which object/class it belongs to — just as you would when calling it directly — e.g. myInstance::methodName.)
It looks like this is what the code in the question is trying to do. However, the lambda syntax is usually simpler and clearer, so consider that if you don't need the existing function for any other reason.
(The error message in the question is because combine = getFold(a) will call getFold(), and try to assign its result to the combine parameter. That result is a String, not a function type, hence the type mismatch.)
test0(a, combine = ::getFold)
or
test0(a, combine = this::getFold)
Or like this:
combine = {getFold(it)}
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.
I see there is a typealias keyword being used and then the invoke method is being called on that "type"
Can someone please provide insight into what this is and how it is being used?
typealias NewKittiesReceived = (Kitty) -> Unit
class KittyRepository {
private val timer = Timer()
private val random = Random()
private val period = TimeUnit.SECONDS.toMillis(1)
internal fun receiveNewKitties(newKittiesReceived: NewKittiesReceived) {
timer.schedule(object : TimerTask() {
override fun run() {
val nameRandom = random.nextInt(KittyNames.values().size)
val ageRandom = random.nextInt(5)
newKittiesReceived.invoke(Kitty(KittyNames.values()[nameRandom].name, ageRandom))
}
}, period, period)
}
}
It’s often more readable to have dedicated names for function types, such as (Kitty) -> Unit. In the end, a typealias simply gives us a way to define an alias for such a (e.g.) function type which can then be used throughout the code instead of that explicit type as a 1:1 replacement.
In your example the function type (Kitty) -> Unit is being aliased with NewKittiesReceived, which is an argument to the shown function receiveNewKitties. Every variable holding a function (newKittiesReceived in the example) can be invoked with function.invoke(arguments...) or simpler with function(arguments).
There’s only a single situation in which the typealias is used actually: the definition of newKittiesReceived: NewKittiesReceived will be translated to newKittiesReceived: (Kitty) -> Unit.
The docs are found here.
This is what the documentation says:
Type aliases provide alternative names for existing types. If the type
name is too long you can introduce a different shorter name and use
the new one instead.
So, as you can see, typealises improve readability and shorten names that are to long.